diff -Nru 3depict-0.0.12/ChangeLog 3depict-0.0.13/ChangeLog --- 3depict-0.0.12/ChangeLog 2012-11-18 00:02:36.000000000 +0000 +++ 3depict-0.0.13/ChangeLog 2013-04-12 18:10:08.000000000 +0000 @@ -1,3 +1,59 @@ +* 12 Apr 2013 : 0.0.13 + Features: + - Spherical composition profile support + - Added axial distribution mode to spatial analysis (directional RDF) + - New build for windows 64 (no parallel build available yet) + + User Visible Bugfixes/Changes: + - Fix crash if unable to obtain RSS feed when checking for updates from behind proxy (Windows only) + - Rangefiles now correctly load when altering name property + - Copy/pasting from the raw data grid now works. + - Plot now updates when scrolling, rather than just during mouse motion + - Fix refresh loop in Data Load filter when "monitor" active and "enabled" inactive. + - Fix RDF generating error/crashes when passing < 4 points + - Fix voxel filtering not preserving intensity correctly + - Fix crash bug on OSX during animate + - Fix animate dialog, where wrong text box updated on frame change + - Animate dialog "remove" button now works correctly + - Clipping algorithm now uses multiple CPUs + - RDF algorithm (max dist) now uses multiple CPUs + - The default camera now is stored and loaded when saving state + - Ion information filter now emits warnings if sampling is enabled by a parent + - Warning on export of plot's without legend fixed + - Fix bug where gl window did not update after sash move on some video drivers + - Not providing an extention when exporting plots now causes prompt, rather than error + - Fixed filters not staying selected when loading new data files + - More locking of UI elements during refresh + - Improve view splitter startup behaviour + + Technical Bugfixes/Features: + - Mathgl >= 1.11 (Nov 2010) now required as hard + dependency, earlier versions will not compile + - Mathgl 2.x now supported + - Refactored clipping and concentration profile code + into single geometry handler + - Refactored often copy-pasted XML writer code back to + "filter common" functions + - Fixed bug whereby if user preference had been altered + for pos data, with loadlimit=0, then loading would cancel + if this value was not changed in the filter property, + and sampling was set. + - Improved wx correctness in property grid + - Tentative support in "getDeps" script for CentOS6 + - Refactor APTClasses & basics functions into several + more manageable parts + - Better RNG support (negative ranges, range lines starting with a digit) + - More extensive unit testing + - Fix double-free bug for certain topologies in filter tree + - Fix memory leak when aborting refresh + - Cross compilation script for mingw-win64 and 32 + - Source code relayout to reflect overall design + - Fix several minor assertion errors + - Remove several redundant scene update calls in main window + - Re-enable OSX checking for updates + - Fix incorrect progress reporting when ranging + - Improved release QA checking + * Nov 2012 : 0.0.12 Features: - Animation tool for performing "sweeps" of filter properties @@ -91,7 +147,7 @@ - More strict emit/use/block patterns for spatial analysis, bound box and external program -* 1 Apr, 2011 : 0.0.10 +* 1 Apr, 2012 : 0.0.10 Features: - Improved aborting behaviour for filters @@ -120,7 +176,7 @@ - More QA checking in release script - Compiles against GCC 4.7. - Re-enable convex hull based algorithms in OSX. - - Remove unneccessary #includes. + - Remove unnecessary #includes. - Some code de-duplication, thanks to pmd.sourceforge.net - Hidden debug only Autosave with ctrl+insert. - Fix memory leaks in filter devices, rangefile filter @@ -269,7 +325,7 @@ Technical Bugfixes/Features: - - Signficantly more complex refresh system, now performs type analysis + - Significantly more complex refresh system, now performs type analysis on tree to determine minimal subsections of tree to refresh. Now filters that cannot cache well will penalise the refresh system much less. - Fix corner case bug in LFSR selection routines (power of two @@ -383,7 +439,7 @@ - Ensure visibility reset actually resets to looking down +ve axis - Change plot axis to show log_10 rather than just log() during log mode - - Fixed interaction overlay drawing transparancy + - Fixed interaction overlay drawing transparency Technical Bugs/Features: - Really fast "random" sampling. @@ -391,11 +447,11 @@ use due to bad name handling - Fix incorrect usage of std::unique that was leading to assertion failure - - Make conjugation in quaternions implicit for even faster quat + - Make conjugation in quaternions implicit for even faster quaternion rotations. - Fix bug in GenericLoadFloatFile, where the output vector was too - small for cols<4, resulting in mem overflow - - Fix bug in transform filter where data limits were requirested for + small for cols<4, resulting in memory overflow + - Fix bug in transform filter where data limits were required for ion data sizes < 2 - Fixes for spatial analysis filter - Catch and report errors to console, rather than crash. @@ -408,7 +464,7 @@ after ion export - Fix bug in BoundCube::setBounds where incorrect assignment for z was made - - Valgrind out two crash bugs due to uninited mem + - Valgrind out two crash bugs due to uninitialised memory @@ -416,7 +472,7 @@ - Files with arbitrary number of data channels can now be loaded, but only one channel at a time can be analysed. - - Many functions are now openMP parallellised, and thus will + - Many functions are now openMP parallelised, and thus will take advantage of multiple CPUs, if enabled at compile time - Simple animation support (PNG sequences in an orbit) - Voxelisation support; voxel data can be generated using the new diff -Nru 3depict-0.0.12/Makefile.am 3depict-0.0.13/Makefile.am --- 3depict-0.0.12/Makefile.am 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/Makefile.am 2013-04-05 21:48:27.000000000 +0000 @@ -1,5 +1,5 @@ SUBDIRS = src -EXTRA_DIST = config.rpath packaging/ m4/ docs/ deps/ translations/ test/ +EXTRA_DIST = config.rpath packaging/ m4/ docs/ translations/ test/ data/ ACLOCAL_AMFLAGS = -Im4 diff -Nru 3depict-0.0.12/Makefile.in 3depict-0.0.13/Makefile.in --- 3depict-0.0.12/Makefile.in 2012-11-11 20:00:31.000000000 +0000 +++ 3depict-0.0.13/Makefile.in 2013-04-06 11:05:53.000000000 +0000 @@ -264,7 +264,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src -EXTRA_DIST = config.rpath packaging/ m4/ docs/ deps/ translations/ test/ +EXTRA_DIST = config.rpath packaging/ m4/ docs/ translations/ test/ data/ ACLOCAL_AMFLAGS = -Im4 all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive diff -Nru 3depict-0.0.12/README 3depict-0.0.13/README --- 3depict-0.0.12/README 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/README 2013-03-22 18:31:39.000000000 +0000 @@ -1 +1,25 @@ -See the web page for the latest documentation, at http://threedepict.sourceforge.net . +If you want the manual, or a "how to use" for this program, See the web +page for the latest documentation, at http://threedepict.sourceforge.net. + +Most users should obtain a "binary" version from the website. If you are +trying to build from source, the webpage is recommended, but otherwise, +install the required dependencies (see website for more details) and then, +from the command-line run: + +./configure +make +make install + +to build the default-mode (single-threaded, debug on ) program. + +Interesting configure flags (see ./configure --help): + +--enable-openmp-parallel : Enable multi-CPU mode (for multi-CPU sections + of the program) via the "openMP" framework +--disable-debug-checks : Disable debug checks. This makes the program + much faster, but less likely to catch + program bugs + + + + diff -Nru 3depict-0.0.12/TODO 3depict-0.0.13/TODO --- 3depict-0.0.12/TODO 2012-11-18 00:02:36.000000000 +0000 +++ 3depict-0.0.13/TODO 2013-03-22 18:39:14.000000000 +0000 @@ -1,11 +1,14 @@ 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 == Eventually == * Support for XY scatter plots * Status bar message queue @@ -34,7 +37,6 @@ scene drawing of non-pointcloud objects * Voxelisation filter needs progress * Better progress during cluster ranging - * Clipping should be parallelised * Billboard text * Camera animation control (slerp?) * Undo by timestream @@ -52,7 +54,6 @@ Outstanding bugs: == Next release== - * Abort behaviour odd, shows "aborted" generic message, then waits for several seconds, then shows error * File -> export image -> Height*=2, results in aspect ratio of output image being distorted * Cluster filter wont save state correctly if parent rangefile has disabled ions. It will output incorrect @@ -62,16 +63,13 @@ of plot zoom status Windows: - * section symbol does not display on console tab + * Drawing updates for resolution dialog are wonk - OSX: - * drag drop not working? == Eventually== * Lighting calculations on isosurfaces can be problematic. See example package * Voxelisation "filter" option appears to be reducing voxel intensity * Loading a full pos file directly onto the video card cannot be aborted. - * OSX drag/drop functionality broken. * Scroll wheel on text area for camera drop down does not scroll cameras; only on button (wxGTK only??) * Switching between fixed width and num bins in voxel @@ -80,11 +78,6 @@ * Error bar masking for graph (mathgl draws error bars outside plot boundary) * Pos load add could always add to bottom of filter list, rather than default value - * Grid copy/ctrl-c doesn't seem to work under GTK. The data gets - passed to the clipboard, but then wx doesn't appear to - do anything with it... - - Could be constrained to wxGTK2.8 or less ( - wxWidgets Bug Ticket #11811 ??? ) * Under mac osx, changing languages does not cause stock wx translation strings to change, even after app restart. * Select an X-Y crop, camera coords, on a dataset, @@ -93,22 +86,15 @@ dataset disappears until mouse motion. This is due to camera up vector not being updated, I suspect. * 3D Text bounding boxes are wrong. - * mac os x: icon on dock bounces very fast during some refreshes - * mac os x: update from rss feed crashes - - == Needs reproducing == - * Invalid range file being opened cause Package export to crash - * Duplicate range at end when exporting range - * Large datasets causing crash? - * Ion transform leaking memory?? - * Windows (32 bit on 64) crash on startup bug -- seems to happen after - locale init, maybe openGL related (there was a second - opengl program running at the time - context - problem???). Cannot reproduce... Maybe fixed by improved - glpane error code? + + OSX: + * drag drop not working? + * icon on dock bounces very fast during some refreshes 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 @@ -126,21 +112,20 @@ -- Refactor/cleanup -- - * updateFilterPropertyGrid is in a bad location, need new - file that knows about filters and wx at the same time, - but is not viscontrol ;) - * Refactor wxMessageDialog *... to wxErrMsg(..) + * 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 * 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 - Plots need to be connected/disconnected - Plots need to be able to specify bounding boxes separate from their data - Plots need to be able to set strings/legends + - There is little diference between plot1D and plot2D, really. * work out which inline FIXMEs and TODOs are still valid, and need attention * 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 diff -Nru 3depict-0.0.12/aclocal.m4 3depict-0.0.13/aclocal.m4 --- 3depict-0.0.12/aclocal.m4 2012-11-11 20:00:29.000000000 +0000 +++ 3depict-0.0.13/aclocal.m4 2013-04-06 11:05:52.000000000 +0000 @@ -576,18 +576,6 @@ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 8 - -# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. -AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) - # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, diff -Nru 3depict-0.0.12/config.h.in 3depict-0.0.13/config.h.in --- 3depict-0.0.12/config.h.in 2012-11-11 20:00:38.000000000 +0000 +++ 3depict-0.0.13/config.h.in 2013-04-06 11:06:00.000000000 +0000 @@ -15,6 +15,9 @@ /* Define if you have the FREETYPE2 library */ #undef HAVE_LIBFREETYPE +/* Define to 1 if you have the `ftgl' library (-lftgl). */ +#undef HAVE_LIBFTGL + /* Define if you have the GNOME XML library */ #undef HAVE_LIBXML @@ -90,6 +93,9 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* "Enable mgl2 support" */ +#undef USE_MGL2 + /* Version number of package */ #undef VERSION diff -Nru 3depict-0.0.12/configure 3depict-0.0.13/configure --- 3depict-0.0.12/configure 2012-11-11 20:00:31.000000000 +0000 +++ 3depict-0.0.13/configure 2013-04-06 11:07:46.000000000 +0000 @@ -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.12. +# Generated by GNU Autoconf 2.69 for 3Depict 0.0.13. # # Report bugs to . # @@ -580,8 +580,8 @@ # Identity of this package. PACKAGE_NAME='3Depict' PACKAGE_TARNAME='3depict' -PACKAGE_VERSION='0.0.12' -PACKAGE_STRING='3Depict 0.0.12' +PACKAGE_VERSION='0.0.13' +PACKAGE_STRING='3Depict 0.0.13' PACKAGE_BUGREPORT='mycae@yahoo.com' PACKAGE_URL='' @@ -652,6 +652,8 @@ XML_LIBS XML_CFLAGS XMLCONFIG +HAVE_WINDRES_FALSE +HAVE_WINDRES_TRUE WX_RESCOMP WX_VERSION WX_LIBS_STATIC @@ -675,8 +677,6 @@ CPP USE_PRECOMPILED_HEADERS_FALSE USE_PRECOMPILED_HEADERS_TRUE -HAVE_WINDRES_FALSE -HAVE_WINDRES_TRUE am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE @@ -764,6 +764,8 @@ ac_subst_files='' ac_user_opts=' enable_option_checking +with_ftgl_prefix +with_ftgl_no_pkg enable_dependency_tracking with_wxdir with_wx_config @@ -771,12 +773,11 @@ with_wx_exec_prefix with_xml_config with_freetype -with_ftgl_prefix -with_ftgl_dont_use_pkg with_libqhull_flags with_libqhull_link with_libpng_flags with_libpng_link +enable_mgl2 with_mgl_flags with_mgl_libs with_gsl_flags @@ -1348,7 +1349,7 @@ # 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.12 to adapt to many kinds of systems. +\`configure' configures 3Depict 0.0.13 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1418,7 +1419,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of 3Depict 0.0.12:";; + short | recursive ) echo "Configuration of 3Depict 0.0.13:";; esac cat <<\_ACEOF @@ -1428,6 +1429,7 @@ --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors + --enable-mgl2 Enable mathgl 2.x support --disable-gsltest Do not try to compile and run a test GSL program --enable-openmp-parallel Enable OpenMP multi-CPU usage; requires GCC > 4.2 for parallel STL support --disable-debug-checks Disable any debug checking, provides faster operation, but less information needed to debug internal problems, or to provide problem reports to developers @@ -1435,6 +1437,8 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) +--with-ftgl-prefix : specify prefix dir for FTGL +--with-ftgl-no-pkg : don't use pkg-config to check for ftgl --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH --with-wx-config=CONFIG wx-config script to use (optional) --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional) @@ -1442,9 +1446,6 @@ Exec prefix where wxWidgets is installed (optional) --with-xml-config=PATH use xml-config in PATH to find libxml --with-freetype=DIR where to find the freetype 2.x library - --with-ftgl-prefix=PFX , - Manually specify the FTGL location (optional) - --ftgl-dont-use-pkg don't use pkg-config to check for ftgl --with-libqhull-flags=PATH : specify compiler flags for libqhull --with-libqhull-link=PATH : specify linker flag (library) for libqhull --with-libpng-flags=PATH : specify compiler flags for libpng @@ -1545,7 +1546,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -3Depict configure 0.0.12 +3Depict configure 0.0.13 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2226,7 +2227,7 @@ 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.12, which was +It was created by 3Depict $as_me 0.0.13, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3041,7 +3042,7 @@ # Define the identity of the package. PACKAGE='3depict' - VERSION='0.0.12' + VERSION='0.0.13' cat >>confdefs.h <<_ACEOF @@ -4451,17 +4452,6 @@ ac_config_files="$ac_config_files Makefile src/Makefile" -#Lets check if we have windres, and assume this only exists under -#Windows. - if which windres > /dev/null; then - HAVE_WINDRES_TRUE= - HAVE_WINDRES_FALSE='#' -else - HAVE_WINDRES_TRUE='#' - HAVE_WINDRES_FALSE= -fi - - #Ok, lets try using gcc style precompiled headers. if 1; then USE_PRECOMPILED_HEADERS_TRUE= @@ -5255,9 +5245,31 @@ " "$LINENO" 5 fi + if which ${host_os}windres > /dev/null && which windres >> /dev/null; then + HAVE_WINDRES_TRUE= + HAVE_WINDRES_FALSE='#' +else + HAVE_WINDRES_TRUE='#' + HAVE_WINDRES_FALSE= +fi + + #Append the --gl-libs flag WX_LIBS="$WX_LIBS `$WX_CONFIG_PATH --gl-libs`" +case "${host_os}" in + *w64_mingw*) + #wx-config is a little unreliable in cross-compile mode + # Manually append -DUNICODE to cppflags/cxxflags + WX_CXXFLAGS="$WX_CXXFLAGS -DUNICODE" + WX_CPPFLAGS="$WX_CPPFLAGS -DUNICODE" + ;; + *) + ;; +esac + + + # Check for xml-config (libxml2 configuration utility) @@ -5805,26 +5817,6 @@ -# -# Allow user to pass a manual dir for FTGL -# - -# Check whether --with-ftgl-prefix was given. -if test "${with_ftgl_prefix+set}" = set; then : - withval=$with_ftgl_prefix; ftgl_prefix="$withval" -else - ftgl_config_prefix="" -fi - -# -# allow for disabling the pkg-config check -# FIXME: THIS DOESN'T work "unrecognised option" - -# Check whether --with-ftgl-dont-use-pkg was given. -if test "${with_ftgl_dont_use_pkg+set}" = set; then : - withval=$with_ftgl_dont_use_pkg; -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ftgl" >&5 $as_echo_n "checking for ftgl... " >&6; } @@ -5837,16 +5829,26 @@ FTGL_CFLAGS="-I$ftgl_prefix/include/ -L$ftgl_prefix/lib/" FTGL_LIBS="-lFTGL" else - if test "x$ftgl_dont_use_pkg" = "xyes" ; then + + HAVE_PKG=$(basename $(which pkg-config)) + + + if test $HAVE_PKG != x"pkg-config" ; then + manual_ftgl="yes" ; + fi + + + if test "x$with_ftgl_no_pkg" = "xyes" ; then $as_echo "#define FTGL_NO_PKG_CONFIG 1" >>confdefs.h #well the user doesn't want us to use pkg-config so dont. manual_ftgl=yes else - # - #Use PKG_CONFIG to do the heavy lifting, must be greater than 2.0.0 - # + if ! test x"$manual_ftgl" == x"yes" ; then + # + #Use PKG_CONFIG to do the heavy lifting, must be greater than 2.0.0 + # pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FTGL" >&5 @@ -5919,19 +5921,77 @@ libftgl="yes" fi - #Check to see if pkg-config did the job - if test "x$libftgl" = "xno" ; then - #dang, looks like we have to try a manual approach - manual_ftgl=yes + #Check to see if pkg-config did the job + if test "x$libftgl" = "xno" ; then + #dang, looks like we have to try a manual approach + manual_ftgl=yes ; + fi fi fi fi -#TODO: see if we can put in some manual tests for a few common locations for ftgl? if test "x$manual_ftgl" = "xyes" ; then - as_fn_error $? "*** Couldn't find FTGL, either provide the path to the base dir, i e if you libs are in /usr/lib and your includes are in /usr/include or /usr/include/FTGL then use the --with-ftgl-prefix=/usr/ to tell configure where to look, or alternately install pkg-config and ensure pkg-config outputs the correct path for ftgl ***" "$LINENO" 5 + CFLAGS_ORIG="$CFLAGS" + LIBS_ORIG="$LIBS" + LIBS="$LIBS $FTGL_LIBS $LDFLAGS" + + if test x$FTGL_LIBS == x"" ; then + FTGL_LIBS="-lftgl" + fi + + #TODO: see if we can put in some more manual tests for a few common locations for ftgl? + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ftglCreateSimpleLayout in -lftgl" >&5 +$as_echo_n "checking for ftglCreateSimpleLayout in -lftgl... " >&6; } +if ${ac_cv_lib_ftgl_ftglCreateSimpleLayout+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lftgl -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ftglCreateSimpleLayout (); +int +main () +{ +return ftglCreateSimpleLayout (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ftgl_ftglCreateSimpleLayout=yes +else + ac_cv_lib_ftgl_ftglCreateSimpleLayout=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ftgl_ftglCreateSimpleLayout" >&5 +$as_echo "$ac_cv_lib_ftgl_ftglCreateSimpleLayout" >&6; } +if test "x$ac_cv_lib_ftgl_ftglCreateSimpleLayout" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBFTGL 1 +_ACEOF + + LIBS="-lftgl $LIBS" + +else + as_fn_error $? "Couldnt find ftgl -- provide base dir or install pkg_config" "$LINENO" 5 +fi + + + CFLAGS="$CFLAGS_ORIG" + LIBS="$LIBS_ORIG" fi # @@ -6155,106 +6215,59 @@ if test x"$with_libpng_flags" != x"" ; then PNG_CFLAGS="$with_libpng_flags" -else - -pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNG" >&5 -$as_echo_n "checking for PNG... " >&6; } - -if test -n "$PNG_CFLAGS"; then - pkg_cv_PNG_CFLAGS="$PNG_CFLAGS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpng >= 1.2\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libpng >= 1.2") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_PNG_CFLAGS=`$PKG_CONFIG --cflags "libpng >= 1.2" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried -fi -if test -n "$PNG_LIBS"; then - pkg_cv_PNG_LIBS="$PNG_LIBS" - elif test -n "$PKG_CONFIG"; then - if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpng >= 1.2\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libpng >= 1.2") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - pkg_cv_PNG_LIBS=`$PKG_CONFIG --libs "libpng >= 1.2" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes -else - pkg_failed=yes -fi - else - pkg_failed=untried fi - -if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes +#set libpng's link flags +if test x"$with_libpng_link" != x"" ; +then + PNG_LIBS="$with_libpng_link" else - _pkg_short_errors_supported=no -fi - if test $_pkg_short_errors_supported = yes; then - PNG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpng >= 1.2" 2>&1` - else - PNG_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpng >= 1.2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$PNG_PKG_ERRORS" >&5 - - as_fn_error $? "Package requirements (libpng >= 1.2) were not met: - -$PNG_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -Alternatively, you may set the environment variables PNG_CFLAGS -and PNG_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details." "$LINENO" 5 -elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -Alternatively, you may set the environment variables PNG_CFLAGS -and PNG_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details. -To get pkg-config, see . -See \`config.log' for more details" "$LINENO" 5; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for png_create_write_struct_2 in -lpng" >&5 +$as_echo_n "checking for png_create_write_struct_2 in -lpng... " >&6; } +if ${ac_cv_lib_png_png_create_write_struct_2_+:} false; then : + $as_echo_n "(cached) " >&6 else - PNG_CFLAGS=$pkg_cv_PNG_CFLAGS - PNG_LIBS=$pkg_cv_PNG_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpng -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char png_create_write_struct_2 (); +int +main () +{ +return png_create_write_struct_2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_png_png_create_write_struct_2_=yes +else + ac_cv_lib_png_png_create_write_struct_2_=no fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_create_write_struct_2_" >&5 +$as_echo "$ac_cv_lib_png_png_create_write_struct_2_" >&6; } +if test "x$ac_cv_lib_png_png_create_write_struct_2_" = xyes; then : + PNG_LIBS=-lpng +else + PNG_USE_PKG_CFG=yes fi -#set libpng's link flags -if test x"$with_libpng_link" != x"" ; -then - PNG_LIBS="$with_libpng_link" -else + if test x"$PNG_USE_PKG_CFG" == x"yes" ; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNG" >&5 @@ -6346,6 +6359,7 @@ $as_echo "yes" >&6; } fi + fi fi @@ -6486,6 +6500,12 @@ CFLAGS_ORIG="$CFLAGS" LDFLAGS_ORIG="$LDFLAGS" +# Check whether --enable-mgl2 was given. +if test "${enable_mgl2+set}" = set; then : + enableval=$enable_mgl2; +fi + + # Check whether --with-mgl-flags was given. if test "${with_mgl_flags+set}" = set; then : @@ -6512,13 +6532,47 @@ LDFLAGS="$LDFLAGS $MGL_LIBS" -ac_fn_c_check_header_mongrel "$LINENO" "mgl/mgl_c.h" "ac_cv_header_mgl_mgl_c_h" "$ac_includes_default" -if test "x$ac_cv_header_mgl_mgl_c_h" = xyes; then : +#mathgl 2, under linux (at least debian) installs headers +# into /usr/include/mgl2/ +#Note: +# mathgl1.x uses mgl_c.h as c functions. +# mathgl2.x uses mgl_cf.h for c functions. +MGL_HEADER_TESTFILE=mgl/mgl_c.h + +if test x"${enable_mgl2}" == x"yes" ; then + +$as_echo "#define USE_MGL2 1 " >>confdefs.h + +fi + +case "${host_os}" in + darwin*) + ;; + mingw*|windows*|winnt) + ;; + linux*) + #if enable mgl2, substitute header + if test -z "${enable_mgl2}" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"mathgl check: assuming mathgl 1.x\"" >&5 +$as_echo "\"mathgl check: assuming mathgl 1.x\"" >&6; } + else + #note file rename under mgl2 mgl_c->mgl_cf + MGL_HEADER_TESTFILE="mgl2/mgl_cf.h" + fi + ;; + *) + ;; +esac + +#mgl2 is installed into different path (at least under debian) +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" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : $as_echo "#define HAVE_MGL_H /**/" >>confdefs.h else - as_fn_error $? "Required MathGL headers not found (looking for mgl/mgl_c.h) - is mathgl development code installed?" "$LINENO" 5 + as_fn_error $? "Required MathGL headers not found (looking for ${MGL_HEADER_TESTFILE}) - is mathgl development code installed?" "$LINENO" 5 fi @@ -6566,6 +6620,7 @@ as_fn_error $? "Required MathGL libraries not found" "$LINENO" 5 fi + CFLAGS="$CFLAGS_ORIG" LDFLAGS="$LDFLAGS_ORIG" @@ -7310,14 +7365,14 @@ as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_WINDRES_TRUE}" && test -z "${HAVE_WINDRES_FALSE}"; then - as_fn_error $? "conditional \"HAVE_WINDRES\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi if test -z "${USE_PRECOMPILED_HEADERS_TRUE}" && test -z "${USE_PRECOMPILED_HEADERS_FALSE}"; then as_fn_error $? "conditional \"USE_PRECOMPILED_HEADERS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${HAVE_WINDRES_TRUE}" && test -z "${HAVE_WINDRES_FALSE}"; then + as_fn_error $? "conditional \"HAVE_WINDRES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${USE_XML_TRUE}" && test -z "${USE_XML_FALSE}"; then as_fn_error $? "conditional \"USE_XML\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -7719,7 +7774,7 @@ # 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.12, which was +This file was extended by 3Depict $as_me 0.0.13, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7785,7 +7840,7 @@ 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.12 +3Depict config.status 0.0.13 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru 3depict-0.0.12/configure.ac 3depict-0.0.13/configure.ac --- 3depict-0.0.12/configure.ac 2012-11-11 20:00:03.000000000 +0000 +++ 3depict-0.0.13/configure.ac 2013-03-23 17:38:30.000000000 +0000 @@ -1,14 +1,10 @@ -AC_INIT([3Depict], [0.0.12], [mycae@yahoo.com]) +AC_INIT([3Depict], [0.0.13], [mycae@yahoo.com]) AM_INIT_AUTOMAKE([foreign]) AC_PROG_CXX AC_PROG_CC -AM_CONFIG_HEADER([config.h]) +AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile src/Makefile]) -#Lets check if we have windres, and assume this only exists under -#Windows. -AM_CONDITIONAL(HAVE_WINDRES, which windres > /dev/null) - #Ok, lets try using gcc style precompiled headers. AM_CONDITIONAL(USE_PRECOMPILED_HEADERS, 1) @@ -36,8 +32,23 @@ ]) fi +AM_CONDITIONAL(HAVE_WINDRES, which ${host_os}windres > /dev/null && which windres >> /dev/null) + #Append the --gl-libs flag WX_LIBS="$WX_LIBS `$WX_CONFIG_PATH --gl-libs`" + +case "${host_os}" in + *w64_mingw*) + #wx-config is a little unreliable in cross-compile mode + # Manually append -DUNICODE to cppflags/cxxflags + WX_CXXFLAGS="$WX_CXXFLAGS -DUNICODE" + WX_CPPFLAGS="$WX_CPPFLAGS -DUNICODE" + ;; + *) + ;; +esac + + AC_SUBST(WX_LIBS) dnl ---------- @@ -201,8 +212,6 @@ if test x"$with_libpng_flags" != x"" ; then PNG_CFLAGS="$with_libpng_flags" -else - PKG_CHECK_MODULES(PNG, libpng >= 1.2) fi AC_SUBST(PNG_CFLAGS) @@ -211,7 +220,13 @@ then PNG_LIBS="$with_libpng_link" else - PKG_CHECK_MODULES(PNG, libpng >= 1.2) + + AC_CHECK_LIB([png],[png_create_write_struct_2] , + [PNG_LIBS=-lpng], [PNG_USE_PKG_CFG=yes],-lm) + + if test x"$PNG_USE_PKG_CFG" == x"yes" ; then + PKG_CHECK_MODULES(PNG, libpng >= 1.2) + fi fi AC_SUBST(PNG_LIBS) @@ -262,6 +277,9 @@ CFLAGS_ORIG="$CFLAGS" LDFLAGS_ORIG="$LDFLAGS" +AC_ARG_ENABLE(mgl2, + [ --enable-mgl2 Enable mathgl 2.x support]) + AC_ARG_WITH(mgl-flags, [ --with-mgl-flags=PATH : specify compiler flags for mathgl]) if test x"$with_mgl_flags" != x"" ; then @@ -280,9 +298,40 @@ AC_SUBST(MGL_LIBS) LDFLAGS="$LDFLAGS $MGL_LIBS" -AC_CHECK_HEADER([mgl/mgl_c.h],[AC_DEFINE(HAVE_MGL_H,[],[Have got mathgl headers])], - [AC_MSG_ERROR([Required MathGL headers not found (looking for mgl/mgl_c.h) - is mathgl development code installed?])]) +#mathgl 2, under linux (at least debian) installs headers +# into /usr/include/mgl2/ +#Note: +# mathgl1.x uses mgl_c.h as c functions. +# mathgl2.x uses mgl_cf.h for c functions. +MGL_HEADER_TESTFILE=mgl/mgl_c.h + +if test x"${enable_mgl2}" == x"yes" ; then + AC_DEFINE(USE_MGL2, 1 , ["Enable mgl2 support"]) +fi + +case "${host_os}" in + darwin*) + ;; + mingw*|windows*|winnt) + ;; + linux*) + #if enable mgl2, substitute header + if test -z "${enable_mgl2}" ; then + AC_MSG_RESULT(["mathgl check: assuming mathgl 1.x"]) + else + #note file rename under mgl2 mgl_c->mgl_cf + MGL_HEADER_TESTFILE="mgl2/mgl_cf.h" + fi + ;; + *) + ;; +esac + +#mgl2 is installed into different path (at least under debian) +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) + CFLAGS="$CFLAGS_ORIG" LDFLAGS="$LDFLAGS_ORIG" diff -Nru 3depict-0.0.12/data/3Depict.xpm 3depict-0.0.13/data/3Depict.xpm --- 3depict-0.0.12/data/3Depict.xpm 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/3Depict.xpm 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,267 @@ +/* XPM */ +static const char *_Depict[] = { +/* columns rows colors chars-per-pixel */ +"32 32 229 2", +" c #5D251D", +". c #602C26", +"X c #6B2D25", +"o c #752D24", +"O c #7E2F25", +"+ c #65322C", +"@ c #73342C", +"# c #653934", +"$ c #613E39", +"% c #773A32", +"& c #35410F", +"* c #056933", +"= c #10723D", +"- c #615926", +"; c #61423E", +": c #60602B", +"> c #29385D", +", c #1B1B7F", +"< c #2E1E62", +"1 c #012370", +"2 c #163A75", +"3 c #2B2B75", +"4 c #23237A", +"5 c #353570", +"6 c #3A3A72", +"7 c #5D234B", +"8 c #64264C", +"9 c #622751", +"0 c #431B66", +"q c #482677", +"w c #57367C", +"e c #67376B", +"r c #014D4D", +"t c #094B54", +"y c #004D5E", +"u c #21447A", +"i c #306D69", +"p c #64524D", +"a c #87342A", +"s c #893429", +"d c #91362B", +"f c #97382E", +"g c #9A392D", +"h c #843D35", +"j c #883B32", +"k c #913E34", +"l c #993B30", +"z c #A23C2F", +"x c #A23C30", +"c c #8D4239", +"v c #9D453B", +"b c #9C493F", +"n c #AD4034", +"m c #B04134", +"M c #853140", +"N c #843749", +"B c #993944", +"V c #864D47", +"C c #9B574F", +"Z c #90475A", +"A c #935F59", +"S c #A5574D", +"D c #AC584F", +"F c #B8594D", +"G c #A95C53", +"H c #B65952", +"J c #856741", +"K c #B9665C", +"L c #9E736D", +"P c #B56E66", +"I c #BC6A62", +"U c #BD766E", +"Y c #A67F7A", +"T c #B17A74", +"R c #BB7A73", +"E c #C05E51", +"W c #C16D63", +"Q c #C37D75", +"! c #038103", +"~ c #008B00", +"^ c #088108", +"/ c #0B8D0C", +"( c #019301", +") c #009E00", +"_ c #0B9E0B", +"` c #00871F", +"' c #108710", +"] c #138913", +"[ c #188C18", +"{ c #159215", +"} c #1E9515", +"| c #25951D", +" . c #02A402", +".. c #01AA01", +"X. c #01B101", +"o. c #00BA00", +"O. c #00B60A", +"+. c #0AB40A", +"@. c #00AB14", +"#. c #00A61B", +"$. c #19A619", +"%. c #00B417", +"&. c #14B314", +"*. c #1FB31F", +"=. c #1CBA1C", +"-. c #21A11C", +";. c #1CA62B", +":. c #27AC27", +">. c #23B223", +",. c #26BC26", +"<. c #23A630", +"1. c #3AAD3A", +"2. c #00C100", +"3. c #00C900", +"4. c #00CC0D", +"5. c #00D100", +"6. c #00D900", +"7. c #00E200", +"8. c #00EB00", +"9. c #00F200", +"0. c #2AC12A", +"q. c #29CA29", +"w. c #33CC33", +"e. c #3BA74C", +"r. c #4BB54B", +"t. c #5BBE64", +"y. c #44C544", +"u. c #50C850", +"i. c #50D851", +"p. c #62CF62", +"a. c #62D161", +"s. c #6BDB6B", +"d. c #7BCD7B", +"f. c #74D474", +"g. c #7EDD7E", +"h. c #04058D", +"j. c #000F8F", +"k. c #150C89", +"l. c #001184", +"z. c #001E82", +"x. c #151586", +"c. c #010195", +"v. c #000B90", +"b. c #05059F", +"n. c #0B0B9D", +"m. c #0D1790", +"M. c #141491", +"N. c #21158C", +"B. c #271F97", +"V. c #211C9F", +"C. c #263D8E", +"Z. c #0202A4", +"A. c #0A0AA6", +"S. c #0303AC", +"D. c #0D0BAB", +"F. c #1313AE", +"G. c #1D1DAF", +"H. c #0101B2", +"J. c #0E0EB0", +"K. c #0000BB", +"L. c #1617B1", +"P. c #1E1DB4", +"I. c #1C1BBC", +"U. c #2121AE", +"Y. c #2D2DB7", +"T. c #3131B5", +"R. c #3E3EBC", +"E. c #573B84", +"W. c #4943AE", +"Q. c #4040B9", +"!. c #0000C2", +"~. c #0000CB", +"^. c #0000D2", +"/. c #0000DA", +"(. c #2627C5", +"). c #2E2CC3", +"_. c #3131C0", +"`. c #3C3CCD", +"'. c #0000E3", +"]. c #0000EB", +"[. c #0000F2", +"{. c #5151C3", +"}. c #5E5EC4", +"|. c #4949D5", +" X c #5D5DD1", +".X c #6C6EC6", +"XX c #7676CE", +"oX c #7C7CCF", +"OX c #6263D7", +"+X c #AB8985", +"@X c #AE8D89", +"#X c #C58D86", +"$X c #C3908A", +"%X c #C39791", +"&X c #C79D97", +"*X c #C79D98", +"=X c #C89E99", +"-X c #CBABA7", +";X c #CAAEAA", +":X c #CDB8B6", +">X c #CEBEBD", +",X c #80D780", +"X>X>X>X:X%XC @ jXjXjXjX", +"jXjXjXjXjXjXjXjX] [ ' jXjXjXjX. c R -X;X;X;X;X;X;X;X%XS @ jXjXjX", +"jXjXjXjXjX{ r.1X4X6X3Xd.1./ & h S $X&X&X&X&X&X&X&X&X&XP b X jXjX", +"jXjXjX^ :.g.aXsXsXsXsXsX8Xa.| - S #X#X#X#X#X$X#X#X#X#XP v j jX", +"jXjX^ >.s.6X6X6X7X7X7X7X7X5Xi.-.- U Q Q Q Q Q Q Q Q Q G k k X jX", +"jXjX$.w.g.5X2X2X2X2X2X2X2X2Xs.q.} J I I W W W W I W K k a a o jX", +"jX/ =.0.f. E.E.w e Z H E F v a s s O . ", +"jX_ &.&.u.p.p.p.p.p.p.p.a.t.i C..XyXdXfXpX0XW.q N l d d d d s + ", +"! . . .*.y.y.y.r.y.y.y.e.u R.rXgXgXgXgXgXgXpXOXB.7 g g f f d + ", +"~ .......&.,.,.,.,.,.<.2 ).eXiXuXuXuXuXiXiXiXtX|.V.8 x z z d # ", +"~ ..X.X.X.X.X.+.+.+.+.t P.`.qXwXwXwXwXwXwXwXwXwX X(.N.M m x a ; ", +"( o.o.o.o.o.o.o.o.o.` m.I._.XXoXoXoXoXoXoXoXoXoX{.I.L.0 m m @ jX", +"( o.2.2.2.2.2.2.2.o.r A.J.P.W.}.}.}.}.}.}.}.}.}.Y.J.J.k.B l $ jX", +"! o.3.3.3.3.3.3.3.O.1 Z.S.S.U.R.R.Q.Q.Q.Q.Q.Q.T.A.S.Z.c.9 @ jXjX", +"jX..5.5.5.5.5.5.5.@.l.S.S.Z.S.F.U.U.U.U.U.U.P.A.S.S.S.Z.< p jXjX", +"jX~ 3.6.6.6.6.6.6.#.v.H.H.H.H.H.H.H.S.D.S.S.H.H.H.H.S.S.x.jXjXjX", +"jXjX) 6.7.7.7.6.8.%.j.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.H., jXjXjX", +"jXjXjX .6.8.8.8.8.4.z.!.!.!.!.!.!.!.!.!.!.K.!.!.!.!.!.S.4 jXjXjX", +"jXjXjXjX) 2.7.8.9.8.y !.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.n.6 jXjXjX", +"jXjXjXjXjXjX( +.o.2.* H.^.^.^.^.^.^.^.^.^.^.^.^.^.^.~.x.jXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXh.~./././././././././././././.S.5 jXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXZ./.'.'.'.'.'.'.'.'.'.'.'.K.4 jXjXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXjXZ./.].].].].].].].].].K.4 jXjXjXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXjXjXc.K./.].[.[.[.'.~.n.3 jXjXjXjXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXv.A.S.J.A.M.4 jXjXjXjXjXjXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX", +"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX" +}; Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/Left-Right-arrow.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/Left-Right-arrow.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/Left_clicked_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/Left_clicked_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/Right-arrow.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/Right-arrow.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/Right_clicked_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/Right_clicked_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/enlarge.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/enlarge.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/keyboard-alt.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/keyboard-alt.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/keyboard-command.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/keyboard-command.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/keyboard-ctrl.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/keyboard-ctrl.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/keyboard-shift.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/keyboard-shift.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/keyboard-tab.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/keyboard-tab.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/middle_clicked_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/middle_clicked_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/rotateArrow.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/rotateArrow.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/scroll_wheel_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/scroll_wheel_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/data/textures/tex-source/3Depict-icon.icns and /tmp/ZSARKCsiTI/3depict-0.0.13/data/textures/tex-source/3Depict-icon.icns differ diff -Nru 3depict-0.0.12/data/textures/tex-source/3Depict-icon.svg 3depict-0.0.13/data/textures/tex-source/3Depict-icon.svg --- 3depict-0.0.12/data/textures/tex-source/3Depict-icon.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/3Depict-icon.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,793 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/Icons-licence.txt 3depict-0.0.13/data/textures/tex-source/Icons-licence.txt --- 3depict-0.0.12/data/textures/tex-source/Icons-licence.txt 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/Icons-licence.txt 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,68 @@ +Files: + File:Left clicked mouse.svg + File:Right clicked mouse.svg +Origin: + Wikimedia Commons: +Uploader: + User:Darklama + +Licence: +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". + +Or + +Tbjs file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported, 2.5 Generic, 2.0 Generic and 1.0 Generic license. + + You are free: + + * to share – to copy, distribute and transmit the work + * to remix – to adapt the work + + Under the following conditions: + + * attribution – You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). + * share alike – If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. + +------------------- + +Files: + File:Blue_Glass_Arrow.svg + +Uploader: + User:Everaldo Coelho and [www.yellowicon.com YellowIcon] + +Licence: +This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU Lesser General Public License for more details. + + +--------------------- +Files: + File:Preferences-desktop-keyboard-shortcuts-ctrl.svg (renamed to keyboard-alt.svg) +Author: + Tango Project: Freedesktop.org (http://tango.freedesktop.org/Tango_Desktop_Project) + +Licence: + Public domain + +--------------------- + + +Files: + File:Green_sphere.svg + File:Blue_Sphere.svg + + Work has been used in derivative work (program icon) +Author: + + User:Booyabazooka; recoloured by User:Stannered +Licence: + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version + 2.1 of the License, or (at your option) any later version. This + library is distributed in the hope that it will be useful, + but without any warranty; without even the implied warranty of + merchantability or fitness for a particular purpose. See version + 2.1 and version 3 of the GNU Lesser General Public License for + more details. +---------------------- diff -Nru 3depict-0.0.12/data/textures/tex-source/Left-Right-arrow.svg 3depict-0.0.13/data/textures/tex-source/Left-Right-arrow.svg --- 3depict-0.0.12/data/textures/tex-source/Left-Right-arrow.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/Left-Right-arrow.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1102 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -Nru 3depict-0.0.12/data/textures/tex-source/Left_clicked_mouse.svg 3depict-0.0.13/data/textures/tex-source/Left_clicked_mouse.svg --- 3depict-0.0.12/data/textures/tex-source/Left_clicked_mouse.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/Left_clicked_mouse.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,238 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/Right-arrow.svg 3depict-0.0.13/data/textures/tex-source/Right-arrow.svg --- 3depict-0.0.12/data/textures/tex-source/Right-arrow.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/Right-arrow.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,553 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -Nru 3depict-0.0.12/data/textures/tex-source/Right_clicked_mouse.svg 3depict-0.0.13/data/textures/tex-source/Right_clicked_mouse.svg --- 3depict-0.0.12/data/textures/tex-source/Right_clicked_mouse.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/Right_clicked_mouse.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,351 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/enlarge.svg 3depict-0.0.13/data/textures/tex-source/enlarge.svg --- 3depict-0.0.12/data/textures/tex-source/enlarge.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/enlarge.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1265 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/keyboard-alt.svg 3depict-0.0.13/data/textures/tex-source/keyboard-alt.svg --- 3depict-0.0.12/data/textures/tex-source/keyboard-alt.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/keyboard-alt.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,302 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Alt + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/keyboard-command.svg 3depict-0.0.13/data/textures/tex-source/keyboard-command.svg --- 3depict-0.0.12/data/textures/tex-source/keyboard-command.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/keyboard-command.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,302 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/keyboard-ctrl.svg 3depict-0.0.13/data/textures/tex-source/keyboard-ctrl.svg --- 3depict-0.0.12/data/textures/tex-source/keyboard-ctrl.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/keyboard-ctrl.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,301 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ctrl + + diff -Nru 3depict-0.0.12/data/textures/tex-source/keyboard-shift.svg 3depict-0.0.13/data/textures/tex-source/keyboard-shift.svg --- 3depict-0.0.12/data/textures/tex-source/keyboard-shift.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/keyboard-shift.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,302 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/keyboard-tab.svg 3depict-0.0.13/data/textures/tex-source/keyboard-tab.svg --- 3depict-0.0.12/data/textures/tex-source/keyboard-tab.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/keyboard-tab.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,334 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Tab + + diff -Nru 3depict-0.0.12/data/textures/tex-source/middle_clicked_mouse.svg 3depict-0.0.13/data/textures/tex-source/middle_clicked_mouse.svg --- 3depict-0.0.12/data/textures/tex-source/middle_clicked_mouse.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/middle_clicked_mouse.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,433 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/data/textures/tex-source/rotateArrow.svg 3depict-0.0.13/data/textures/tex-source/rotateArrow.svg --- 3depict-0.0.12/data/textures/tex-source/rotateArrow.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/rotateArrow.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1703 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -Nru 3depict-0.0.12/data/textures/tex-source/scroll_wheel_mouse.svg 3depict-0.0.13/data/textures/tex-source/scroll_wheel_mouse.svg --- 3depict-0.0.12/data/textures/tex-source/scroll_wheel_mouse.svg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/data/textures/tex-source/scroll_wheel_mouse.svg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,306 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/debian/changelog 3depict-0.0.13/debian/changelog --- 3depict-0.0.12/debian/changelog 2013-01-12 13:39:08.000000000 +0000 +++ 3depict-0.0.13/debian/changelog 2013-04-13 00:57:38.000000000 +0000 @@ -1,8 +1,14 @@ -3depict (0.0.12-1ubuntu1~oneiric1) oneiric; urgency=low +3depict (0.0.13-1ubuntu1~oneiric) oneiric; urgency=low - * PPA Update for 0.0.12 + * PPA Update for 0.0.13 - -- tehuser Sat, 12 Jan 2013 13:34:41 +0400 + -- tehuser Sat, 13 Apr 2013 01:00:23 +0100 + +3depict (0.0.13-1) unstable; urgency=low + + * New upstream release + + -- D Haley Sat, 23 Mar 2013 16:06:15 +0100 3depict (0.0.12-1) experimental; urgency=low diff -Nru 3depict-0.0.12/debian/control 3depict-0.0.13/debian/control --- 3depict-0.0.12/debian/control 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/control 2013-04-12 23:08:17.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Debian Science Maintainers Uploaders: D Haley DM-Upload-Allowed: yes -Build-Depends: debhelper (>= 7), libgl1-mesa-dev | libgl-dev, libpng-dev | libpng15-dev, libqhull-dev, libwxgtk2.8-dev, libftgl-dev, autoconf, libxml2-dev, libmgl-dev, autotools-dev +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 Homepage: http://threedepict.sourceforge.net/index.html Vcs-Git: git://git.debian.org/debian-science/packages/3depict.git diff -Nru 3depict-0.0.12/debian/patches/3depict-docdir.patch 3depict-0.0.13/debian/patches/3depict-docdir.patch --- 3depict-0.0.12/debian/patches/3depict-docdir.patch 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/patches/3depict-docdir.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Documentation directory change for debian ---- a/src/3Depict.cpp -+++ b/src/3Depict.cpp -@@ -2674,11 +2674,13 @@ - { - //First attempt to locate the local copy of the manual. - string s; -- s=locateDataFile("3Depict-manual.pdf"); -+ s=locateDataFile("manual.pdf"); - - //Also Debian makes us use the lowercase "D", so check there too. - if(!s.size()) -- s=locateDataFile("3depict-manual.pdf"); -+ { -+ s=std::string("/usr/share/3depict/manual.pdf"); -+ } - - - //If we found it, use the default program associated with that data file diff -Nru 3depict-0.0.12/debian/patches/FTGL-lowercase.patch 3depict-0.0.13/debian/patches/FTGL-lowercase.patch --- 3depict-0.0.12/debian/patches/FTGL-lowercase.patch 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/patches/FTGL-lowercase.patch 2013-04-12 23:08:17.000000000 +0000 @@ -1,11 +1,13 @@ ---- a/configure -+++ b/configure -@@ -5835,7 +5835,7 @@ +Index: 3depict-0.0.13/configure +=================================================================== +--- 3depict-0.0.13.orig/configure 2013-04-12 22:16:55.000000000 +0200 ++++ 3depict-0.0.13/configure 2013-04-12 22:20:49.000000000 +0200 +@@ -5827,7 +5827,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$ftgl_dont_use_pkg" = "xyes" ; then + HAVE_PKG=$(basename $(which pkg-config)) diff -Nru 3depict-0.0.12/debian/patches/font-path-changed.patch 3depict-0.0.13/debian/patches/font-path-changed.patch --- 3depict-0.0.12/debian/patches/font-path-changed.patch 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/patches/font-path-changed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Upstream assumes different font directories than debian. ---- a/src/wxcomponents.cpp -+++ b/src/wxcomponents.cpp -@@ -683,8 +683,15 @@ - { - //This is a list of possible target dirs to search - //(Oh look Ma, I'm autoconf!) -+ -+ //DEBIAN PATCH: So, it looks like someone moved all the fonts! -+ // I have no idea why they did that... Lets just use the dirs I have on my -+ // clean debian machine. I have to find a better way to do this, or please -+ // stop moving my fonts! - const char *dirs[] = { ".", - "/usr/share/fonts/truetype", -+ "/usr/share/fonts/truetype/freefont", -+ "/usr/share/fonts/truetype/ttf-dejavu", - "/usr/local/share/fonts/truetype", - "/usr/X11R6/lib/X11/fonts/truetype", - "/usr/X11R6/lib64/X11/fonts/truetype", diff -Nru 3depict-0.0.12/debian/patches/lowercase-textdomain.patch 3depict-0.0.13/debian/patches/lowercase-textdomain.patch --- 3depict-0.0.12/debian/patches/lowercase-textdomain.patch 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/patches/lowercase-textdomain.patch 2013-04-12 23:08:17.000000000 +0000 @@ -1,7 +1,9 @@ Debian uses different text domain for the lang files ---- a/src/3Depict.cpp -+++ b/src/3Depict.cpp -@@ -5703,7 +5703,7 @@ +Index: 3depict-0.0.13/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 @@ else { //Set the gettext language @@ -10,7 +12,7 @@ setlocale (LC_ALL, ""); #ifdef __WXMAC__ bindtextdomain( PROGRAM_NAME, paths->GetResourcesDir().mb_str(wxConvUTF8) ); -@@ -5735,8 +5735,8 @@ +@@ -196,8 +196,8 @@ break; } #else diff -Nru 3depict-0.0.12/debian/patches/series 3depict-0.0.13/debian/patches/series --- 3depict-0.0.12/debian/patches/series 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/patches/series 2013-04-12 23:08:17.000000000 +0000 @@ -1,6 +1,3 @@ -3depict-docdir.patch debian-desktop-naming.patch -font-path-changed.patch lowercase-textdomain.patch FTGL-lowercase.patch -upstream-post-0.0.12-fixes.patch diff -Nru 3depict-0.0.12/debian/patches/upstream-post-0.0.12-fixes.patch 3depict-0.0.13/debian/patches/upstream-post-0.0.12-fixes.patch --- 3depict-0.0.12/debian/patches/upstream-post-0.0.12-fixes.patch 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/patches/upstream-post-0.0.12-fixes.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -diff -r ab68a990a52f -r c844e00b9a6c src/3Depict.cpp ---- a/src/3Depict.cpp Tue Dec 11 19:44:29 2012 +0100 -+++ b/src/3Depict.cpp Tue Dec 11 19:49:33 2012 +0100 -@@ -1772,7 +1772,7 @@ - - - -- panelSpectra->limitInteraction(!locking); -+ panelSpectra->limitInteraction(locking); - break; - } - default: -@@ -2071,6 +2071,9 @@ - setLockUI(false); - panelTop->Enable(true); - -+ //Re-run the scene update for the original case, -+ // this allow sfor things like the selection bindings to be reinitialised. -+ doSceneUpdate(); - } - - void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event) -diff -r ab68a990a52f -r c844e00b9a6c src/mathglPane.cpp ---- a/src/mathglPane.cpp Tue Dec 11 19:44:29 2012 +0100 -+++ b/src/mathglPane.cpp Tue Dec 11 19:49:33 2012 +0100 -@@ -611,7 +611,7 @@ - - void MathGLPane::leftMouseDown(wxMouseEvent& event) - { -- if(!gr || !thePlot->getNumVisible() || !thePlot->isInteractionLocked()) -+ if(!gr || !thePlot->getNumVisible() || thePlot->isInteractionLocked()) - return; - - int w,h; diff -Nru 3depict-0.0.12/debian/rules 3depict-0.0.13/debian/rules --- 3depict-0.0.12/debian/rules 2013-01-12 13:21:56.000000000 +0000 +++ 3depict-0.0.13/debian/rules 2013-04-12 23:08:17.000000000 +0000 @@ -20,11 +20,15 @@ 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" LDFLAGS="-Wl,-z,defs" --with-ftgl-prefix="/usr" + ./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 @@ -61,7 +65,8 @@ $(MAKE) DESTDIR=$(CURDIR)/debian/3depict install #Install the textures - cp -rp src/textures/ $(CURDIR)/debian/3depict/usr/share/3depict/ + mkdir -p $(CURDIR)/debian/3depict/usr/share/3depict/textures/ + cp -p data/textures/*png $(CURDIR)/debian/3depict/usr/share/3depict/textures/ #rename 3Depict (real program name) to debian-friendly 3depict mv $(CURDIR)/debian/3depict/usr/bin/3Depict $(CURDIR)/debian/3depict/usr/bin/3depict @@ -73,8 +78,8 @@ #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)/src/3Depict.xpm $(CURDIR)/debian/3depict/usr/share/pixmaps/3depict.xpm - install -Dp -m 644 $(CURDIR)/src/tex-source/3Depict-icon.svg $(CURDIR)/debian/3depict/usr/share/pixmaps/3depict.svg + 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. diff -Nru 3depict-0.0.12/deps/getDeps 3depict-0.0.13/deps/getDeps --- 3depict-0.0.12/deps/getDeps 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/deps/getDeps 1970-01-01 00:00:00.000000000 +0000 @@ -1,728 +0,0 @@ -#!/bin/bash - -# -# getDeps- The dependency handler you're using when your not using -# a dependency handler. (Downloads dependencies for 3Depict) -# Copyright (C) 2012, D Haley, AV Ceguerra -# -# 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 . -# - -function setFullDeps { - #Dependency ID, URL and name - DEPIDS=( 0 1 2 3 4 5) - DEPNAMES=( libpng freetype ftgl wxwidgets mathgl qhull) - DEPURLS=(https://sourceforge.net/projects/libpng/files/libpng15/older-releases/1.5.4/libpng-1.5.4.tar.gz \ - https://sourceforge.net/projects/freetype/files/freetype2/2.4.6/freetype-2.4.6.tar.gz \ - http://downloads.sourceforge.net/project/ftgl/FTGL%20Source/2.1.3%7Erc5/ftgl-2.1.3-rc5.tar.gz \ - http://downloads.sourceforge.net/project/wxwindows/2.8.11/wxWidgets-2.8.11.tar.gz \ - http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download \ - http://www.qhull.org/download/qhull-2011.1-src.tgz) - DEPFILENAMES=(libpng-1.5.4.tar.gz \ - freetype-2.4.6.tar.gz \ - ftgl-2.1.3-rc5.tar.gz \ - wxWidgets-2.8.11.tar.gz \ - mathgl-1.11.2.tar.gz \ - qhull-2011.1-src.tgz) - DEPMDSUM=(dea4d1fd671160424923e92ff0cdda78 \ - 1dc4af24a86e2f78a49ac6b520a81ec5 \ - fcf4d0567b7de9875d4e99a9f7423633 \ - ce80389e1b70d6a518c80b7b715b763e\ - acd33e68911d9506f60d769dce23f95e \ - a65061cf2a6e6581182f4df0f3667a8e) - -} - -function setMacDeps { - OS_VERSION=`sw_vers -productVersion |sed 's/\.[0-9]*$//'` - #Dependency ID, URL and name - DEPIDS=( 0) - DEPNAMES=( mathgl) - DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download) - DEPFILENAMES=( mathgl-1.11.2.tar.gz) - DEPMDSUM=( acd33e68911d9506f60d769dce23f95e) - -} - -function installMacPorts { - #check to see if it's installed - if [ x"`which port`" == x"" ] ; then - echo "macports will now be installed..." - echo "OS_VERSION = $OS_VERSION" - - if [ x"$OS_VERSION" == x"10.5" ] ; then - curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3-10.5-Leopard.dmg - hdiutil attach MacPorts-2.0.3-10.5-Leopard.dmg - elif [ x"$OS_VERSION" == x"10.6" ] ; then - curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3-10.6-SnowLeopard.dmg - hdiutil attach MacPorts-2.0.3-10.6-SnowLeopard.dmg - elif [ x"$OS_VERSION" == x"10.7" ] ; then - curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3-10.7-Lion.dmg - hdiutil attach MacPorts-2.0.3-10.7-Lion.dmg - else - echo "Mac OS X $OS_VERSION not supported." - exit 1 - fi - if [ $? -ne 0 ] ; then - echo "macports dmg could not be mounted" - exit 1 - fi - - # use installer to install macports to /opt/local - sudo installer -pkg /Volumes/MacPorts-2.0.3/MacPorts-2.0.3.pkg -target / - hdiutil detach /Volumes/MacPorts-2.0.3/ - - echo "sourcing .profile after macports installation" - . ~/.profile - - echo "updating macports ports tree to latest..." - sudo port selfupdate - if [ $? -ne 0 ] ; then - echo "macports was not successful in updating ports tree" - exit 1 - fi - else - echo "macports is already already installed." - fi -} - -function setSuseDeps { - DEPIDS=( 0) - DEPNAMES=( mathgl) - DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download) - DEPFILENAMES=( mathgl-1.11.2.tar.gz) - DEPMDSUM=( acd33e68911d9506f60d769dce23f95e) - -} - -function detectProxy() -{ - #Check the http proxy variable - if [ x"$http_proxy" == x"" ] ; then - if [ x"$OS_NAME" == x"Darwin" ] ; then - ##Are we using mac? Try to get the proxy automagically - - #PROXY=`system_profiler |grep "Auto Configure URL" | sed 's/^[ ]*//' | sort | uniq | awk {'sub(/^.*:[ \t]*/, "", $0); print $0;'}` - PROXY=`system_profiler SPNetworkDataType|grep "HTTP Proxy Server" | sed 's/^[ ]*//' |sort | uniq | awk {'sub(/^.*:[ \t]*/, "", $0); print $0;'}` - PROXYPORT=`system_profiler SPNetworkDataType|grep "HTTP Proxy Port" | sed 's/^[ ]*//' |sort | uniq | awk {'sub(/^.*:[ \t]*/, "", $0); print $0;'}` - if [ x"$PROXY" != x"" ] ; then - echo "using proxy as : $PROXY:$PROXYPORT ; hope this works" - export http_proxy=$PROXY:$PROXYPORT - fi - - echo "using $http_proxy as the proxy server" - else - echo "Proxy not found... Maybe you dont need one." - echo " You can set one by passing it as an argument (./getdeps nameofproxy), if required" - echo " eg: ./getdeps your_proxy_server:12345" - echo - echo "Or you can set it at the command line with " - echo " export http_proxy=your_proxy_server:12345" - echo "(where 12345 is the proxy server \"port\"), usually 8080 or 8000" - fi - else - echo "using $http_proxy as the proxy server" - fi -} - -function parseArgs() -{ - if [ $# -gt 1 ] ; then - echo "usage : getDeps [proxyserver]" - exit 1 - elif [ $# -eq 1 ] ; then - export http_proxy=$1 - echo "using $1 as the proxy server" - else - #User did not specify a proxy as argument - try to detect - echo "detecting proxy..." - detectProxy - fi -} - -function testCompiler() -{ - echo "int main(int argc, char *argv[]) { return 0; } ; " > gcctest.c - gcc gcctest.c -o gcctest - - if [ ! -f gcctest ] ; then - echo "You do not have gcc (GNU compiler frontend) installed?? Install it into your PATH, then try again." - exit 1 - fi - rm gcctest.c gcctest - - echo "int main(int argc, char *argv[]) { return 0; } ; " > gcctest.cpp - - g++ gcctest.cpp -o gcctest - if [ ! -f gcctest ] ; then - echo "You do not have g++ (C++ compiler) installed?? Install it into your PATH, then try again." - exit 1 - fi - - rm gcctest.cpp gcctest -} - -function handleMacDistro() -{ - - #Ensure fink/homebrew are not installed - for i in fink homebrew - do - if [ x"`which $i`" != x"" ] ; then - echo "$i was detected on your system - getDeps assumes macports is in use. Either install deps manually using fink, or use macports..." - exit 1 - fi - done - - - # install deps except mathgl - echo "installing 3Depict dependencies..." - sudo port install wget libpng freetype ftgl wxWidgets-devel dylibbundler qhull gsl cmake libtool pkgconfig - if [ $? -ne 0 ] ; then - echo "macports was not successful in getting the dependencies" - exit 1 - fi -} - -function handleLinuxDistro() -{ - #Attempt to detect some popular linux distros - echo "Trying to detect your linux system type. " - echo "If this fails, you should just try to use your package manager to do this" - - GUESS_DISTRIB_BY_PKGMAN="no" - if [ x`which lsb_release` == x"" ] ; then - GUESS_DISTRIB_BY_PKGMAN="yes" - else - # we have an lsb_release command - use it! - DISTRIBUTOR=`lsb_release -i -s` - if [ $? -eq 0 ] ; then - if [ x$DISTRIBUTOR == x"Debian" ] ; then - LINUXDISTRO="DebianLike" - elif [ x$DISTRIBUTOR == x"Ubuntu" ] ; then - LINUXDISTRO="DebianLike" - elif [ x$DISTRIBUTOR == x"LinuxMint" ] ; then - LINUXDISTRO="DebianLike" - elif [ x$DISTRIBUTOR == x"SUSE LINUX" ] ; then - LINUXDISTRO="SuseLike" - elif [ x$DISTRIBUTOR == x"Fedora" ] ; then - LINUXDISTRO="RedhatLike" - elif [ x$DISTRIBUTOR == x"CentOS" ] ; then - LINUXDISTRO="RedhatLike" - elif [ x`echo $DISTRIBUTOR | grep -i redhat` != x"" ] ; then - LINUXDISTRO="RedhatLike" - else - GUESS_DISTRIB_BY_PKGMAN="yes" - fi - else - LINUXDISTRO="Unknown" - fi - fi - - #Try to guess based upon package manager binary - if [ x"$GUESS_DISTRIB_BY_PKGMAN" != x"no" ] ; then - if [ x`which apt-get` != x"" ] ; then - LINUXDISTRO="DebianLike" - elif [ x`which yum` != x"" ] ; then - LINUXDISTRO="RedhatLike" - elif [ x`which zypper` != x"" ] ; then - LINUXDISTRO="SuseLike" - else - LINUXDISTRO="Unknown" - fi - fi - - case $LINUXDISTRO in - DebianLike) - echo "System appears to be Debian-esque (debian/ubuntu/mint...)." - echo "Running apt-get:" - - sudo apt-get build-dep 3depict && sudo apt-get install make g++ - if [ $? -ne 0 ] ; then - echo "Failed to install build-dependencies" - exit 1 - else - echo "All done." - exit 0 - fi - ;; - RedhatLike) - echo "System appears to be redhat like" - - sudo yum groupinstall "Development Tools" && sudo yum install yum-utils && sudo yum-builddep 3Depict - - if [ $? -ne 0 ] ; then - echo "Failed to install build dependencies" - exit 1 - else - echo "All done." - exit 0 - fi - - ;; - SuseLike) - echo "System appears to be suse-like" - sudo zypper install -t devel_C_C++ && sudo zypper install libxml2-devel wxGTK-devel ftgl-devel libpng14-devel freetype2-devel qhull-devel - - echo "Installed as much as is available from repo. Still need some extra deps... Proceeding to source install" - setSuseDeps - - ;; - *) - #Call setFullDeps to set depnames for error message below - setFullDeps - - echo "--------" - echo "Are you sure you need to run this?? " - echo "You are running some unrecognised version of linux " - echo "you should use your package manager to install these " - echo "libraries : ${dep_names[*]}" - echo - echo "Refusing to continue, otherwise script could break your system..." - echo "--------" - echo - exit 1 - ;; - esac -} - -function runDownloads() -{ - echo "OK, we need to download some libraries, compile them, and try to install them." - echo " This is a bit of a long-shot, but this script will try to do this automagically." - echo " Ensure your net connection is good." - - echo "---------" - echo "Let's go!" - echo "---------" - - HAVE_ALL_DEPS=0 - if [ -d sources ] ; then - echo "OK, found the \"sources\" folder. Cool" - else - echo "making the source folder" - mkdir sources - fi - - echo "Looking for dependencies" - - for i in ${DEPIDS[*]} - do - j=${DEPFILENAMES[$i]} - k=${DEPURLS[$i]} - - if [ ! -f "sources/$j" ] ; then - echo "Missing sources/$j. Will attempt to download" - -case $OS_NAME in - Darwin) - wget $k -O sources/$j - ;; - *) - - if [ x`which curl` == x"" ] ; then - echo "the program -curl- was not present. Aborting" - echo "Need the files:" - echo ${DEPFILENAMES[*]} - echo "supposedly at:" - echo ${DEPURLS[*]} - echo "try to find these online, and place in the sources folder" - fi - - #use CURL to download the file and save it to source/$k - curl -L --progress-bar $k -o sources/$j - ;; -esac - if [ $? -ne 0 ] ; then - echo "Couldn't download dependency : $j, from $k :" - echo "try to find it online, and put it in the sources folder" - fi - - if [ ! -f "sources/$j" ] ; then - echo - echo "That's not right... i was told it was downloaded, but now I can't find it." - echo "Something is wrong, you may have to download the file yourself," - echo " and place it in the sources folder" - echo - echo "Try $k" - echo "or look online for \"$j\"" - echo - echo "will continue in 8 seconds..." - sleep 8 - fi - else - echo "found $j; this is good" - fi - - - done - - echo - echo - echo " -------------------------" - echo - echo -} - -function checkHashes() -{ - - for i in ${DEPIDS[*]} - do - j=${DEPFILENAMES[$i]} - -case $OS_NAME in - Darwin) - #Mac OSX has an undocumented md5sum compat function. Use it - HASH_SUM=`md5 sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'}` - ;; - *) - HASH_SUM=`md5sum sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'}` - ;; -esac - - if [ x"$HASH_SUM" != x"${DEPMDSUM[$i]}" ] ; then - echo "Warning! The file contents for sources/$j appear to be wrong (hash mismatch). " - echo "I recommend pressing ctrl+c and downloading the file manually and overwriting it" - - echo "continuing in 20 seconds. Press ctrl+c to abort (recommended)" - sleep 20 - else - echo " $j looks OK. Good -- moving on" - sleep 1 - fi - done -} - -function prepBuildDir() -{ - echo "------------------------------" - echo " Extraction" - echo - - - if [ -d decompress ] ; then - echo "deleting existing decompress folder" - rm -rf ./decompress - fi - - - echo " Decompressing archives; this can be slow..." - - - - mkdir -p decompress - - if [ $? -ne 0 ] ; then - echo "Oh dear, I couldn't make a folder called \"decompress\". Thats odd. Giving up" - exit 1 - fi - - cd decompress - for i in ${DEPIDS[*]} - do - j=${DEPFILENAMES[$i]} - - echo "Extracting $j" - if [ x"`echo $j | grep \.tar\.gz`" != x"" ] ; then - tar -zxf ../sources/$j - elif [ x"`echo $j | grep \.tar\.bz2`" != x"" ] ; then - tar -jxf ../sources/$j - elif [ x"`echo $j | grep \.tgz`" != x"" ] ; then - tar -zxf ../sources/$j - elif [ x"`echo $j | grep \.zip`" != x"" ] ; then - unzip ../sources/$j - else - echo "$j apparently not a tar-gz or zip file! Aborting!" - exit 1 - fi - - if [ $? -ne 0 ] ; then - echo "There was a problem extracting $j, aborting" - exit 1 - fi - done - - sleep 2 - - -} - -#-----------Entry point------------ -OS_NAME=`uname` -parseArgs $* - -#Each platform needs to be initialised in a different way -case $OS_NAME in - Darwin) - #Mac OSX has an undocumented md5sum compat function. Use it - setMacDeps - installMacPorts - handleMacDistro - sleep 1; - ;; - MINGW*) - #This doesn't work under windows. - echo "This is not functional under windows, due to the difficulty of providing a robust tool chain." - - echo "---------------" - echo " If you want to fix this, please do, and send me the fix!" - echo "---------------" - exit 1 - ;; - Linux) - handleLinuxDistro - - ;; - *) - echo "Your platform was not recognised. Program will proceed, but may fail" - sleep 1 - setFullDeps - ;; -esac - -testCompiler - -runDownloads - - -echo "So it looks like we have downloaded all the files." -echo "I'm just going to check the integrity of these files first." -echo - -checkHashes - -prepBuildDir - - -echo "------------------------------" -echo " Compilation" - -######## -for i in ${DEPIDS[*]} -do - j=${DEPFILENAMES[$i]} - - #Strip the extension from the filename - if [ x"`echo $j | grep \.tar\.gz`" != x"" ] ; then - foldername=${j%.tar.gz} - elif [ x"`echo $j | grep \.tar\.bz2`" != x"" ] ; then - foldername=${j%.tar.bz2} - elif [ x"`echo $j | grep \.tgz`" != x"" ] ; then - foldername=${j%.tgz} - elif [ x"`echo $j | grep \.zip`" != x"" ] ; then - foldername=${j%.zip} - else - echo "$j apparently not a tar-gz or zip file! Aborting!" - exit 1 - fi - - pushd $foldername - - echo "Attempting to compile ${DEPNAMES[$i]}" - case "${DEPNAMES[$i]}" in - libpng) - # Compile libpng - case "$OS_NAME" in - Linux) - make -f scripts/makefile.linux - ;; - *) - echo "Unable to build libpng, unknown platform" - exit 1 - ;; - esac - - if [ $? -ne 0 ] ; then - echo "Damn. Unable to build. Aborting" - exit 1 - fi - - echo "I want to install ${DEPNAMES[$i]} to the system:" - #install - sudo make install -f scripts/makefile.linux - if [ $? -ne 0 ] ; then - echo "Damn. Unable to install. Aborting" - exit 1 - fi - - ;; - wxwidgets) - # Configure wxwidgets; to let it find this bits its wants - ./configure --enable-unicode --with-opengl - - if [ $? -ne 0 ] ; then - echo "Damn. Unable to configure. Aborting" - exit 1 - fi - - echo "OK, configure was good. Building, this will take a while" - sleep 2 - - make - - if [ $? -ne 0 ] ; then - echo "Damn. Unable to build. Aborting" - exit 1 - fi - - echo "I want to install ${DEPNAMES[$i]} to the system:" - #install - sudo make install - if [ $? -ne 0 ] ; then - echo "Damn. Unable to install. Aborting" - exit 1 - fi - ;; - - freetype) - # Configure freetype - ./configure - - if [ $? -ne 0 ] ; then - echo "Damn. unable to configure. aborting" - exit 1 - fi - - echo "OK, configure was good. Building, this will take a while" - sleep 2 - - make - - if [ $? -ne 0 ] ; then - echo "Damn. unable to build. aborting" - exit 1 - fi - - echo "I want to install ${DEPNAMES[$i]} to the system:" - #install - sudo make install - if [ $? -ne 0 ] ; then - echo "Damn. unable to install. aborting" - exit 1 - fi - ;; - - ftgl) - echo "Re-arranging build directory" - #FTGL has a tilde in the filename, but not the download, move it. - mv "ftgl-2.1.3~rc5" "ftgl-2.1.3-rc5" - - # Configure ftgl - ./configure CXXFLAGS="-fpermissive" - - if [ $? -ne 0 ] ; then - echo "Damn. unable to configure. aborting" - exit 1 - fi - - echo "OK, configure was good. Building, this will take a while" - sleep 2 - - make - - if [ $? -ne 0 ] ; then - echo "Damn. unable to build. aborting" - exit 1 - fi - - echo "I want to install ${DEPNAMES[$i]} to the system:" - #install - sudo make install - if [ $? -ne 0 ] ; then - echo "Damn. unable to install. aborting" - exit 1 - fi - ;; - - mathgl) - # Configure mathgl. Disable GNU scientific library to remove that dependency - if [ x"$OS_NAME" == x"Darwin" ] ; then - PNGDIR=/opt/local - PNGLIBS=" CXXFLAGS=-I$PNGDIR/include LDFLAGS=-L$PNGDIR/lib " - echo $PNGLIBS - pwd - patch mgl/mgl_eps.cpp < ../../sources/mgl_eps.patch - patch mgl/mgl_export.cpp < ../../sources/mgl_export.patch - fi - ./configure --disable-gsl $PNGLIBS - - if [ $? -ne 0 ] ; then - echo "Damn. unable to configure. aborting" - exit 1 - fi - - echo "OK, configure was good. Building, this will take a while" - sleep 2 - - make - - if [ $? -ne 0 ] ; then - echo "Damn. unable to build. aborting" - exit 1 - fi - - echo "I want to install ${DEPNAMES[$i]} to the system:" - #install - sudo make install - if [ $? -ne 0 ] ; then - echo "Mathgl said it failed, but is known to misreport. Continuing in 10 seconds" - sleep 10 - fi - ;; - - qhull) - if [ x`which cmake` == "" ] ; then - echo "Cmake not found on your system. This is needed to build qhull (sigh.). You can install it from http://www.cmake.org/cmake/resources/software.html" - else - #build - cmake . - make - - #OK, lets install! - echo "I want to install ${DEPNAMES[$i]} to the system:" - sudo make install - if [ $? -ne 0 ] ; then - echo "Damn. unable to install. aborting" - exit 1 - fi - fi - - ;; - *) - echo "There is a bug in the script. I do not know the dependency ${DEPNAMES[$i]}. Aborting" - exit 1 - ;; - esac - - - - popd -done - - -######## - -echo "------------------------------" -echo " All done!" - -echo - -echo " You should hopefully be able to build and run 3Depict now!" -echo -echo - - - - diff -Nru 3depict-0.0.12/deps/sources/mgl_eps.patch 3depict-0.0.13/deps/sources/mgl_eps.patch --- 3depict-0.0.12/deps/sources/mgl_eps.patch 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/deps/sources/mgl_eps.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -306,308c306,308 -< -< bool gz = fname[strlen(fname)-1]=='z'; -< void *fp = gz ? gzopen(fname,"wt") : fopen(fname,"wt"); ---- -> -> bool gz = fname[strlen(fname)-1]=='z'; -> void *fp = ( gz ? gzopen(fname,"wt") : (void *)fopen(fname,"wt")); -456c456 -< if(gz) gzclose(fp); else fclose((FILE *)fp); ---- -> if(gz) gzclose((gzFile_s*)fp); else fclose((FILE *)fp); -466,467c466,467 -< bool gz = fname[strlen(fname)-1]=='z'; -< void *fp = gz ? gzopen(fname,"wt") : fopen(fname,"wt"); ---- -> bool gz = fname[strlen(fname)-1]=='z'; -> void *fp = (gz ? gzopen(fname,"wt") : (void *)fopen(fname,"wt")); -623c623 -< if(gz) gzclose(fp); else fclose((FILE *)fp); ---- -> if(gz) gzclose((gzFile_s*)fp); else fclose((FILE *)fp); diff -Nru 3depict-0.0.12/deps/sources/mgl_export.patch 3depict-0.0.13/deps/sources/mgl_export.patch --- 3depict-0.0.12/deps/sources/mgl_export.patch 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/deps/sources/mgl_export.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -235c235 -< if(gz) gzprintf(fp, "%s", buf); ---- -> if(gz) gzprintf((gzFile_s*)fp, "%s", buf); -246c246 -< void *fp = gz ? gzopen(fname,"wt") : fopen(fname,"wt"); ---- -> void *fp = gz ? gzopen(fname,"wt") : (void*)fopen(fname,"wt"); -258c258 -< if(gz) gzclose(fp); else fclose((FILE *)fp); ---- -> if(gz) gzclose((gzFile_s*)fp); else fclose((FILE *)fp); diff -Nru 3depict-0.0.12/docs/developers/code-notes.txt 3depict-0.0.13/docs/developers/code-notes.txt --- 3depict-0.0.12/docs/developers/code-notes.txt 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/docs/developers/code-notes.txt 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,5 @@ +String comments that can be searched for in the code: + COMPAT_BREAK : items that need to be changed at some point, but require a compatability break with earlier versions + TODO : Deferred/nice-to-have/not-sure-about-fix items + FIXME : Not nicely written bits of code, or known minor problems/failure edge cases. + diff -Nru 3depict-0.0.12/docs/manual-latex/3depictusermanual.kilepr 3depict-0.0.13/docs/manual-latex/3depictusermanual.kilepr --- 3depict-0.0.12/docs/manual-latex/3depictusermanual.kilepr 2012-11-24 12:01:53.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/3depictusermanual.kilepr 2013-03-22 18:31:39.000000000 +0000 @@ -68,16 +68,16 @@ [item:manual.tex] archive=true -column=14 +column=0 encoding=UTF-8 highlight=LaTeX -line=417 +line=2 mode=LaTeX open=true order=0 [view-settings,view=0,item:manual.tex] -CursorColumn=14 -CursorLine=417 +CursorColumn=0 +CursorLine=2 JumpList= ViMarks=a,349,0,b,903,0 diff -Nru 3depict-0.0.12/docs/manual-latex/manual.aux 3depict-0.0.13/docs/manual-latex/manual.aux --- 3depict-0.0.12/docs/manual-latex/manual.aux 2012-11-24 20:55:56.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.aux 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -\relax -\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} -\HyperFirstAtBeginDocument{\ifx\hyper@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@anchor\@undefined -\let\contentsline\oldcontentsline -\let\newlabel\oldnewlabel -\fi} -\fi} -\global\let\hyper@last\relax -\gdef\HyperFirstAtBeginDocument#1{#1} -\providecommand\HyField@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}Understanding the program}{9}{section.3}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Filters}{9}{subsection.3.1}} -\@writefile{lof}{\contentsline {figure}{\numberline {6}{\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. }}{9}{figure.6}} -\newlabel{fig:basic-filter}{{6}{9}{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.6}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Trees}{9}{subsection.3.2}} -\newlabel{sec:treebehaviour}{{3.2}{9}{Trees\relax }{subsection.3.2}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {7}{\ignorespaces Data propagation in a tree for a particular arrangement of filters. Data is propagated from a parent filter to its children.}}{10}{figure.7}} -\newlabel{fig:datapropagate}{{7}{10}{Data propagation in a tree for a particular arrangement of filters. Data is propagated from a parent filter to its children}{figure.7}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Stashes}{10}{subsection.3.3}} -\@writefile{lof}{\contentsline {figure}{\numberline {8}{\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.}}{11}{figure.8}} -\newlabel{fig:stash-creation}{{8}{11}{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.8}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.4}Plots}{11}{subsection.3.4}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.5}Cameras}{11}{subsection.3.5}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.6}Effects}{12}{subsection.3.6}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.7}Program actions}{12}{subsection.3.7}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.1}Save}{12}{subsubsection.3.7.1}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.2}Undo}{12}{subsubsection.3.7.2}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.3}Raw Data}{12}{subsubsection.3.7.3}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.4}Export Menu}{12}{subsubsection.3.7.4}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.5}Autosave}{13}{subsubsection.3.7.5}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {3.7.6}Export Animation}{13}{subsubsection.3.7.6}} -\newlabel{sec:animationExport}{{3.7.6}{13}{Export Animation\relax }{subsubsection.3.7.6}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {9}{\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.}}{14}{figure.9}} -\newlabel{fig:animateFilterView}{{9}{14}{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.9}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {10}{\ignorespaces Numerical input window for setting parameters for animation}}{14}{figure.10}} -\newlabel{fig:animateParamDialog}{{10}{14}{Numerical input window for setting parameters for animation\relax }{figure.10}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {11}{\ignorespaces Conflicting filter properties shown, highlighted to show the conflicting values in the animation property grid.}}{15}{figure.11}} -\newlabel{fig:animateParamConflict}{{11}{15}{Conflicting filter properties shown, highlighted to show the conflicting values in the animation property grid}{figure.11}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {12}{\ignorespaces Setting string properties using the string input dialog, via manual entry.}}{16}{figure.12}} -\newlabel{fig:animatePropString}{{12}{16}{Setting string properties using the string input dialog, via manual entry}{figure.12}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {13}{\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.}}{16}{figure.13}} -\newlabel{fig:animateFrameView}{{13}{16}{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.13}{}} -\@writefile{toc}{\contentsline {section}{\numberline {4}Detailed Reference}{17}{section.4}} -\@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Data types}{17}{subsection.4.1}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.1.1}Ions}{17}{subsubsection.4.1.1}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.1.2}Plots}{17}{subsubsection.4.1.2}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.1.3}Range}{17}{subsubsection.4.1.3}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.1.4}Voxels}{17}{subsubsection.4.1.4}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.1.5}Drawables}{17}{subsubsection.4.1.5}} -\@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Filters}{17}{subsection.4.2}} -\newlabel{sec:filter}{{4.2}{18}{Filters\relax }{subsection.4.2}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.1}Data load}{18}{subsubsection.4.2.1}} -\@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Propagation matrix for Data load.}}{19}{table.1}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.2}Downsampling}{19}{subsubsection.4.2.2}} -\@writefile{lot}{\contentsline {table}{\numberline {2}{\ignorespaces Propagation matrix for Downsampling.}}{19}{table.2}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.3}Ion Information}{19}{subsubsection.4.2.3}} -\@writefile{lot}{\contentsline {table}{\numberline {3}{\ignorespaces Propagation matrix for Ion Information.}}{20}{table.3}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.4}Ranging}{20}{subsubsection.4.2.4}} -\newlabel{sec:rangeFilter}{{4.2.4}{20}{Ranging\relax }{subsubsection.4.2.4}{}} -\@writefile{lot}{\contentsline {table}{\numberline {4}{\ignorespaces Propagation matrix for Ranging.}}{20}{table.4}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.5}Bounding Box}{21}{subsubsection.4.2.5}} -\@writefile{lot}{\contentsline {table}{\numberline {5}{\ignorespaces Propagation matrix for Bounding Box.}}{21}{table.5}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.6}Clipping}{21}{subsubsection.4.2.6}} -\@writefile{lot}{\contentsline {table}{\numberline {6}{\ignorespaces Propagation matrix for Clipping.}}{21}{table.6}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.7}Spectrum}{21}{subsubsection.4.2.7}} -\@writefile{lot}{\contentsline {table}{\numberline {7}{\ignorespaces Propagation matrix for Spectrum.}}{22}{table.7}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.8}Profile}{22}{subsubsection.4.2.8}} -\@writefile{lot}{\contentsline {table}{\numberline {8}{\ignorespaces Propagation matrix for Profile.}}{22}{table.8}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.9}Spatial Analysis}{22}{subsubsection.4.2.9}} -\@writefile{toc}{\contentsline {paragraph}{Algorithms}{22}{section*.3}} -\citation{Stephenson07} -\citation{Hyde10} -\citation{Vaumousse03} -\@writefile{lot}{\contentsline {table}{\numberline {9}{\ignorespaces Propagation matrix for Spatial Analysis.}}{23}{table.9}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.10}Clustering analysis}{23}{subsubsection.4.2.10}} -\@writefile{lot}{\contentsline {table}{\numberline {10}{\ignorespaces Propagation matrix for Clustering Analysis.}}{24}{table.10}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.11}External Program}{24}{subsubsection.4.2.11}} -\@writefile{toc}{\contentsline {paragraph}{Command syntax: }{24}{section*.4}} -\@writefile{toc}{\contentsline {paragraph}{Prior to program execution:}{25}{section*.5}} -\@writefile{toc}{\contentsline {paragraph}{After program execution:}{25}{section*.6}} -\@writefile{lot}{\contentsline {table}{\numberline {11}{\ignorespaces Propagation matrix for External Program.}}{25}{table.11}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.12}Annotation}{25}{subsubsection.4.2.12}} -\@writefile{toc}{\contentsline {paragraph}{Text}{25}{section*.7}} -\@writefile{toc}{\contentsline {paragraph}{Arrow, Arrow with Text}{26}{section*.8}} -\@writefile{toc}{\contentsline {paragraph}{Angle Measurement}{26}{section*.9}} -\@writefile{lot}{\contentsline {table}{\numberline {12}{\ignorespaces Propagation matrix for Annotation.}}{26}{table.12}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {4.2.13}Voxels}{26}{subsubsection.4.2.13}} -\@writefile{lot}{\contentsline {table}{\numberline {13}{\ignorespaces Propagation matrix for Voxels.}}{27}{table.13}} -\@writefile{toc}{\contentsline {subsection}{\numberline {4.3}Ion Colour}{27}{subsection.4.3}} -\@writefile{lot}{\contentsline {table}{\numberline {14}{\ignorespaces Propagation matrix for Ion Colour.}}{27}{table.14}} -\@writefile{toc}{\contentsline {subsection}{\numberline {4.4}Ion Transform}{27}{subsection.4.4}} -\@writefile{lot}{\contentsline {table}{\numberline {15}{\ignorespaces Propagation matrix for Ion Transform.}}{28}{table.15}} -\@writefile{toc}{\contentsline {section}{\numberline {5}Attributions}{28}{section.5}} -\@writefile{toc}{\contentsline {section}{\numberline {6}Licence}{28}{section.6}} -\@writefile{toc}{\contentsline {section}{\numberline {7}Appendices}{28}{section.7}} -\newlabel{sec:appendix}{{7}{28}{Appendices\relax }{section.7}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {7.1}Paths}{28}{subsection.7.1}} -\newlabel{sec:3DepictPaths}{{7.1}{28}{Paths\relax }{subsection.7.1}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {7.2}File formats}{28}{subsection.7.2}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.2.1}State file}{28}{subsubsection.7.2.1}} -\newlabel{sec:xmlstatefile}{{7.2.1}{28}{State file\relax }{subsubsection.7.2.1}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.2.2}Range files}{29}{subsubsection.7.2.2}} -\newlabel{sec:rangeFormat}{{7.2.2}{29}{Range files\relax }{subsubsection.7.2.2}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.2.3}POS files}{31}{subsubsection.7.2.3}} -\newlabel{sec:posformat}{{7.2.3}{31}{POS files\relax }{subsubsection.7.2.3}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.2.4}Text files}{31}{subsubsection.7.2.4}} -\newlabel{sec:textformat}{{7.2.4}{31}{Text files\relax }{subsubsection.7.2.4}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {7.3}External Program Examples}{31}{subsection.7.3}} -\newlabel{sec:externalProgExample}{{7.3}{31}{External Program Examples\relax }{subsection.7.3}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {14}{\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. }}{32}{figure.14}} -\newlabel{fig:externalProgScilabSample}{{14}{32}{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.14}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.3.1}Scilab}{32}{subsubsection.7.3.1}} -\@writefile{lof}{\contentsline {figure}{\numberline {15}{\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.}}{36}{figure.15}} -\newlabel{fig:externalProgPythonSample}{{15}{36}{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.15}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.3.2}Python}{36}{subsubsection.7.3.2}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.3.3}Bash}{37}{subsubsection.7.3.3}} -\@writefile{lof}{\contentsline {figure}{\numberline {16}{\ignorespaces Example program screenshot when using the BASH test example.}}{38}{figure.16}} -\newlabel{fig:externalProgBashSample}{{16}{38}{Example program screenshot when using the BASH test example}{figure.16}{}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.3.4}C/C++}{39}{subsubsection.7.3.4}} -\@writefile{lof}{\contentsline {figure}{\numberline {17}{\ignorespaces Example program screenshot without and with the C++ test example present..}}{40}{figure.17}} -\newlabel{fig:externalProgCppSample}{{17}{40}{Example program screenshot without and with the C++ test example present.}{figure.17}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {7.4}Modifying the program}{43}{subsection.7.4}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.4.1}Development tools}{44}{subsubsection.7.4.1}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.4.2}Getting yourself set up}{44}{subsubsection.7.4.2}} -\@writefile{toc}{\contentsline {subsubsection}{\numberline {7.4.3}Changing stuff}{44}{subsubsection.7.4.3}} -\bibstyle{unsrt} -\bibdata{manual} -\bibcite{Stephenson07}{1} -\bibcite{Hyde10}{2} -\bibcite{Vaumousse03}{3} diff -Nru 3depict-0.0.12/docs/manual-latex/manual.bbl 3depict-0.0.13/docs/manual-latex/manual.bbl --- 3depict-0.0.12/docs/manual-latex/manual.bbl 2012-11-24 20:55:53.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.bbl 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -\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 -Nru 3depict-0.0.12/docs/manual-latex/manual.blg 3depict-0.0.13/docs/manual-latex/manual.blg --- 3depict-0.0.12/docs/manual-latex/manual.blg 2012-11-24 20:55:53.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.blg 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -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 -Nru 3depict-0.0.12/docs/manual-latex/manual.log 3depict-0.0.13/docs/manual-latex/manual.log --- 3depict-0.0.12/docs/manual-latex/manual.log 2012-11-24 20:55:56.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.log 1970-01-01 00:00:00.000000000 +0000 @@ -1,514 +0,0 @@ -This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) (format=pdflatex 2012.11.24) 24 NOV 2012 21:55 -entering extended mode - restricted \write18 enabled. - %&-line parsing enabled. -**manual.tex -(./manual.tex -LaTeX2e <2011/06/27> -Babel 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@part=\count79 -\c@section=\count80 -\c@subsection=\count81 -\c@subsubsection=\count82 -\c@paragraph=\count83 -\c@subparagraph=\count84 -\c@figure=\count85 -\c@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@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@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@gobject=\count87 -)) -\Gin@req@height=\dimen103 -\Gin@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@primitive is available. -Package pdftexcmds Info: \pdf@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@linkcounter=\count88 -\Hy@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@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@Hy@tempcnt=\count91 -LaTeX Info: Redefining \url on input line 4653. -\Fld@menulength=\count92 -\Field@Width=\dimen106 -\Fld@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@abspage=\count93 -\c@Item=\count94 -\c@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@listcount=\count96 -\c@bookmark@seq@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@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@size=\dimen109 -\c@WF@wrappedlines=\count98 -\WF@box=\box26 -\WF@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@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=305, 1312.905pt x 974.64125pt> -File: ./figures/CoverImage.png Graphic file (type 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@toc=\write4 -\openout4 = `manual.toc'. - - [3] -<./figures/compilation.pdf, id=410, 489.83pt x 262.58101pt> -File: ./figures/compilation.pdf Graphic file (type 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 - - \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=727, 1026.83624pt x 682.55pt> -File: ./figures/interface.png Graphic file (type 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=734, 579.76598pt x 383.834pt> -File: ./figures/camera.pdf Graphic file (type 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=819, 1199.48125pt x 848.16875pt> -File: ./figures/spectrum-raw.png Graphic file (type 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=822, 1199.48125pt x 848.16875pt> -File: ./figures/console.png Graphic file (type 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/generic-filter.png, id=844, 4353.20471pt x 2563.45941pt> -File: ./figures/generic-filter.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/generic-filter.png used on input line 268. -(pdftex.def) Requested size: 399.29463pt x 235.12141pt. - [9 <./figures/generic-filter.png>] -<./figures/tree-propagate.pdf, id=854, 1518.55293pt x 800.81699pt> -File: ./figures/tree-propagate.pdf Graphic file (type pdf) - - -Package pdftex.def Info: ./figures/tree-propagate.pdf used on input line 287. -(pdftex.def) Requested size: 399.29463pt x 210.56586pt. - -<./figures/Stash-operation.png, id=856, 1068.99374pt x 608.2725pt> -File: ./figures/Stash-operation.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/Stash-operation.png used on input line 309. -(pdftex.def) Requested size: 399.29463pt x 227.20132pt. - [10 <./figures/tree-propagate.pdf>] -[11 <./figures/Stash-operation.png>] [12] -<./figures/exportanimDialogFilterView.png, id=1182, 1380.15625pt x 800.9925pt> -File: ./figures/exportanimDialogFilterView.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/exportanimDialogFilterView.png used on input - line 373. -(pdftex.def) Requested size: 422.77664pt x 245.35957pt. - -<./figures/exportanimParamDialog.png, id=1183, 1376.14125pt x 801.99625pt> -File: ./figures/exportanimParamDialog.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/exportanimParamDialog.png used on input line - 383. -(pdftex.def) Requested size: 422.77664pt x 246.38904pt. - -<./figures/exportanimDialogConflict.png, id=1185, 1382.16376pt x 801.99625pt> -File: ./figures/exportanimDialogConflict.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/exportanimDialogConflict.png used on input l -ine 393. -(pdftex.def) Requested size: 422.77664pt x 245.31215pt. - [13] [14 <./figures/exportanimDialogFilterView.png (PNG copy)> <./figures/expo -rtanimParamDialog.png (PNG copy)>] -<./figures/exportanimDialogPropString.png, id=1197, 1237.62375pt x 763.85374pt> -File: ./figures/exportanimDialogPropString.png Graphic file (type png) - -Package pdftex.def Info: ./figures/exportanimDialogPropString.png used on input - line 405. -(pdftex.def) Requested size: 422.77664pt x 260.93065pt. - -<./figures/exportanimDialogFrameView.png, id=1198, 1237.62375pt x 763.85374pt> -File: ./figures/exportanimDialogFrameView.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/exportanimDialogFrameView.png used on input -line 419. -(pdftex.def) Requested size: 422.77664pt x 260.93065pt. - [15 <./figures/exportanimDialogConflict.png (PNG copy)>] [16 <./figures/export -animDialogPropString.png (PNG copy)> <./figures/exportanimDialogFrameView.png ( -PNG copy)>] [17] [18] [19] -[20] [21] [22] [23] [24] [25] - -LaTeX Warning: `!h' float specifier changed to `!ht'. - -[26] - -LaTeX Warning: `!h' float specifier changed to `!ht'. - -[27] -Underfull \hbox (badness 10000) in paragraph at lines 1038--1039 - - [] - -[28] [29] [30] [31] -<./figures/externalProgScilab.png, id=1331, 1686.3pt x 847.165pt> -File: ./figures/externalProgScilab.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/externalProgScilab.png used on input line 11 -70. -(pdftex.def) Requested size: 422.77664pt x 212.38535pt. - [32 <./figures/externalProgScilab.png>] -[33] [34] -<./figures/externalProgPython.png, id=1348, 1465.475pt x 856.19875pt> -File: ./figures/externalProgPython.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/externalProgPython.png used on input line 13 -51. -(pdftex.def) Requested size: 399.29463pt x 233.28014pt. - [35] [36 <./figures/externalProgPython.png>] <./figures/externalProgBash.png, -id=1360, 1385.175pt x 876.27374pt> -File: ./figures/externalProgBash.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/externalProgBash.png used on input line 1425 -. -(pdftex.def) Requested size: 399.29463pt x 252.5886pt. - [37] [38 <./figures/externalProgBash.png>] -LaTeX Font Info: Try loading font information for OMS+cmtt on input line 148 -2. -LaTeX Font Info: No file OMScmtt.fd. on input line 1482. - -LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined -(Font) using `OMS/cmsy/m/n' instead -(Font) for symbol `textbraceleft' on input line 1482. - -<./figures/externalProgCpp.png, id=1371, 2123.935pt x 839.135pt> -File: ./figures/externalProgCpp.png Graphic file (type png) - - -Package pdftex.def Info: ./figures/externalProgCpp.png used on input line 1490. - -(pdftex.def) Requested size: 399.29463pt x 157.74715pt. - [39] [40 <./figures/externalProgCpp.png>] -[41] [42] [43] [44] (./manual.bbl) -Package atveryend Info: Empty hook `BeforeClearDocument' on input line 1734. - [45] -Package atveryend Info: Empty hook `AfterLastShipout' on input line 1734. - (./manual.aux) -Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 1734. -Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 1734. - -Package rerunfilecheck Info: File `manual.out' has not changed. -(rerunfilecheck) Checksum: 0E9DC2FD9B880A552B3AAC8077AEE0A4;4932. - - -LaTeX Font Warning: Some font shapes were not available, defaults substituted. - -Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 1734. - ) -Here is how much of TeX's memory you used: - 5486 strings out of 495059 - 82702 string characters out of 3182029 - 166796 words of memory out of 3000000 - 8434 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,1038b,445s stack positions out of 5000i,500n,10000p,200000b,50000s - -Output written on manual.pdf (49 pages, 2576130 bytes). -PDF statistics: - 1510 PDF objects out of 1728 (max. 8388607) - 1160 compressed objects within 12 object streams - 175 named destinations out of 1000 (max. 500000) - 691 words of extra memory for PDF output out of 10000 (max. 10000000) - diff -Nru 3depict-0.0.12/docs/manual-latex/manual.out 3depict-0.0.13/docs/manual-latex/manual.out --- 3depict-0.0.12/docs/manual-latex/manual.out 2012-11-24 20:55:56.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.out 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -\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}{Understanding the program}{}% 21 -\BOOKMARK [2][-]{subsection.3.1}{Filters}{section.3}% 22 -\BOOKMARK [2][-]{subsection.3.2}{Trees}{section.3}% 23 -\BOOKMARK [2][-]{subsection.3.3}{Stashes}{section.3}% 24 -\BOOKMARK [2][-]{subsection.3.4}{Plots}{section.3}% 25 -\BOOKMARK [2][-]{subsection.3.5}{Cameras}{section.3}% 26 -\BOOKMARK [2][-]{subsection.3.6}{Effects}{section.3}% 27 -\BOOKMARK [2][-]{subsection.3.7}{Program actions}{section.3}% 28 -\BOOKMARK [3][-]{subsubsection.3.7.1}{Save}{subsection.3.7}% 29 -\BOOKMARK [3][-]{subsubsection.3.7.2}{Undo}{subsection.3.7}% 30 -\BOOKMARK [3][-]{subsubsection.3.7.3}{Raw Data}{subsection.3.7}% 31 -\BOOKMARK [3][-]{subsubsection.3.7.4}{Export Menu}{subsection.3.7}% 32 -\BOOKMARK [3][-]{subsubsection.3.7.5}{Autosave}{subsection.3.7}% 33 -\BOOKMARK [3][-]{subsubsection.3.7.6}{Export Animation}{subsection.3.7}% 34 -\BOOKMARK [1][-]{section.4}{Detailed Reference}{}% 35 -\BOOKMARK [2][-]{subsection.4.1}{Data types}{section.4}% 36 -\BOOKMARK [3][-]{subsubsection.4.1.1}{Ions}{subsection.4.1}% 37 -\BOOKMARK [3][-]{subsubsection.4.1.2}{Plots}{subsection.4.1}% 38 -\BOOKMARK [3][-]{subsubsection.4.1.3}{Range}{subsection.4.1}% 39 -\BOOKMARK [3][-]{subsubsection.4.1.4}{Voxels}{subsection.4.1}% 40 -\BOOKMARK [3][-]{subsubsection.4.1.5}{Drawables}{subsection.4.1}% 41 -\BOOKMARK [2][-]{subsection.4.2}{Filters}{section.4}% 42 -\BOOKMARK [3][-]{subsubsection.4.2.1}{Data load}{subsection.4.2}% 43 -\BOOKMARK [3][-]{subsubsection.4.2.2}{Downsampling}{subsection.4.2}% 44 -\BOOKMARK [3][-]{subsubsection.4.2.3}{Ion Information}{subsection.4.2}% 45 -\BOOKMARK [3][-]{subsubsection.4.2.4}{Ranging}{subsection.4.2}% 46 -\BOOKMARK [3][-]{subsubsection.4.2.5}{Bounding Box}{subsection.4.2}% 47 -\BOOKMARK [3][-]{subsubsection.4.2.6}{Clipping}{subsection.4.2}% 48 -\BOOKMARK [3][-]{subsubsection.4.2.7}{Spectrum}{subsection.4.2}% 49 -\BOOKMARK [3][-]{subsubsection.4.2.8}{Profile}{subsection.4.2}% 50 -\BOOKMARK [3][-]{subsubsection.4.2.9}{Spatial Analysis}{subsection.4.2}% 51 -\BOOKMARK [3][-]{subsubsection.4.2.10}{Clustering analysis}{subsection.4.2}% 52 -\BOOKMARK [3][-]{subsubsection.4.2.11}{External Program}{subsection.4.2}% 53 -\BOOKMARK [3][-]{subsubsection.4.2.12}{Annotation}{subsection.4.2}% 54 -\BOOKMARK [3][-]{subsubsection.4.2.13}{Voxels}{subsection.4.2}% 55 -\BOOKMARK [2][-]{subsection.4.3}{Ion Colour}{section.4}% 56 -\BOOKMARK [2][-]{subsection.4.4}{Ion Transform}{section.4}% 57 -\BOOKMARK [1][-]{section.5}{Attributions}{}% 58 -\BOOKMARK [1][-]{section.6}{Licence}{}% 59 -\BOOKMARK [1][-]{section.7}{Appendices}{}% 60 -\BOOKMARK [2][-]{subsection.7.1}{Paths}{section.7}% 61 -\BOOKMARK [2][-]{subsection.7.2}{File formats}{section.7}% 62 -\BOOKMARK [3][-]{subsubsection.7.2.1}{State file}{subsection.7.2}% 63 -\BOOKMARK [3][-]{subsubsection.7.2.2}{Range files}{subsection.7.2}% 64 -\BOOKMARK [3][-]{subsubsection.7.2.3}{POS files}{subsection.7.2}% 65 -\BOOKMARK [3][-]{subsubsection.7.2.4}{Text files}{subsection.7.2}% 66 -\BOOKMARK [2][-]{subsection.7.3}{External Program Examples}{section.7}% 67 -\BOOKMARK [3][-]{subsubsection.7.3.1}{Scilab}{subsection.7.3}% 68 -\BOOKMARK [3][-]{subsubsection.7.3.2}{Python}{subsection.7.3}% 69 -\BOOKMARK [3][-]{subsubsection.7.3.3}{Bash}{subsection.7.3}% 70 -\BOOKMARK [3][-]{subsubsection.7.3.4}{C/C++}{subsection.7.3}% 71 -\BOOKMARK [2][-]{subsection.7.4}{Modifying the program}{section.7}% 72 -\BOOKMARK [3][-]{subsubsection.7.4.1}{Development tools}{subsection.7.4}% 73 -\BOOKMARK [3][-]{subsubsection.7.4.2}{Getting yourself set up}{subsection.7.4}% 74 -\BOOKMARK [3][-]{subsubsection.7.4.3}{Changing stuff}{subsection.7.4}% 75 Binary files /tmp/arveZAt5b_/3depict-0.0.12/docs/manual-latex/manual.pdf and /tmp/ZSARKCsiTI/3depict-0.0.13/docs/manual-latex/manual.pdf differ diff -Nru 3depict-0.0.12/docs/manual-latex/manual.tex 3depict-0.0.13/docs/manual-latex/manual.tex --- 3depict-0.0.12/docs/manual-latex/manual.tex 2012-11-19 23:39:24.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.tex 2013-03-23 11:43:07.000000000 +0000 @@ -40,7 +40,7 @@ \begin{minipage}{0.3\textwidth} \begin{flushright} \large \emph{Version:} \\ - 0.0.12, Nov 2012\end{flushright} + 0.0.13, Apr 2012\end{flushright} \end{minipage} \vfill diff -Nru 3depict-0.0.12/docs/manual-latex/manual.toc 3depict-0.0.13/docs/manual-latex/manual.toc --- 3depict-0.0.12/docs/manual-latex/manual.toc 2012-11-24 20:55:56.000000000 +0000 +++ 3depict-0.0.13/docs/manual-latex/manual.toc 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -\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}Understanding the program}{9}{section.3} -\contentsline {subsection}{\numberline {3.1}Filters}{9}{subsection.3.1} -\contentsline {subsection}{\numberline {3.2}Trees}{9}{subsection.3.2} -\contentsline {subsection}{\numberline {3.3}Stashes}{10}{subsection.3.3} -\contentsline {subsection}{\numberline {3.4}Plots}{11}{subsection.3.4} -\contentsline {subsection}{\numberline {3.5}Cameras}{11}{subsection.3.5} -\contentsline {subsection}{\numberline {3.6}Effects}{12}{subsection.3.6} -\contentsline {subsection}{\numberline {3.7}Program actions}{12}{subsection.3.7} -\contentsline {subsubsection}{\numberline {3.7.1}Save}{12}{subsubsection.3.7.1} -\contentsline {subsubsection}{\numberline {3.7.2}Undo}{12}{subsubsection.3.7.2} -\contentsline {subsubsection}{\numberline {3.7.3}Raw Data}{12}{subsubsection.3.7.3} -\contentsline {subsubsection}{\numberline {3.7.4}Export Menu}{12}{subsubsection.3.7.4} -\contentsline {subsubsection}{\numberline {3.7.5}Autosave}{13}{subsubsection.3.7.5} -\contentsline {subsubsection}{\numberline {3.7.6}Export Animation}{13}{subsubsection.3.7.6} -\contentsline {section}{\numberline {4}Detailed Reference}{17}{section.4} -\contentsline {subsection}{\numberline {4.1}Data types}{17}{subsection.4.1} -\contentsline {subsubsection}{\numberline {4.1.1}Ions}{17}{subsubsection.4.1.1} -\contentsline {subsubsection}{\numberline {4.1.2}Plots}{17}{subsubsection.4.1.2} -\contentsline {subsubsection}{\numberline {4.1.3}Range}{17}{subsubsection.4.1.3} -\contentsline {subsubsection}{\numberline {4.1.4}Voxels}{17}{subsubsection.4.1.4} -\contentsline {subsubsection}{\numberline {4.1.5}Drawables}{17}{subsubsection.4.1.5} -\contentsline {subsection}{\numberline {4.2}Filters}{17}{subsection.4.2} -\contentsline {subsubsection}{\numberline {4.2.1}Data load}{18}{subsubsection.4.2.1} -\contentsline {subsubsection}{\numberline {4.2.2}Downsampling}{19}{subsubsection.4.2.2} -\contentsline {subsubsection}{\numberline {4.2.3}Ion Information}{19}{subsubsection.4.2.3} -\contentsline {subsubsection}{\numberline {4.2.4}Ranging}{20}{subsubsection.4.2.4} -\contentsline {subsubsection}{\numberline {4.2.5}Bounding Box}{21}{subsubsection.4.2.5} -\contentsline {subsubsection}{\numberline {4.2.6}Clipping}{21}{subsubsection.4.2.6} -\contentsline {subsubsection}{\numberline {4.2.7}Spectrum}{21}{subsubsection.4.2.7} -\contentsline {subsubsection}{\numberline {4.2.8}Profile}{22}{subsubsection.4.2.8} -\contentsline {subsubsection}{\numberline {4.2.9}Spatial Analysis}{22}{subsubsection.4.2.9} -\contentsline {paragraph}{Algorithms}{22}{section*.3} -\contentsline {subsubsection}{\numberline {4.2.10}Clustering analysis}{23}{subsubsection.4.2.10} -\contentsline {subsubsection}{\numberline {4.2.11}External Program}{24}{subsubsection.4.2.11} -\contentsline {paragraph}{Command syntax: }{24}{section*.4} -\contentsline {paragraph}{Prior to program execution:}{25}{section*.5} -\contentsline {paragraph}{After program execution:}{25}{section*.6} -\contentsline {subsubsection}{\numberline {4.2.12}Annotation}{25}{subsubsection.4.2.12} -\contentsline {paragraph}{Text}{25}{section*.7} -\contentsline {paragraph}{Arrow, Arrow with Text}{26}{section*.8} -\contentsline {paragraph}{Angle Measurement}{26}{section*.9} -\contentsline {subsubsection}{\numberline {4.2.13}Voxels}{26}{subsubsection.4.2.13} -\contentsline {subsection}{\numberline {4.3}Ion Colour}{27}{subsection.4.3} -\contentsline {subsection}{\numberline {4.4}Ion Transform}{27}{subsection.4.4} -\contentsline {section}{\numberline {5}Attributions}{28}{section.5} -\contentsline {section}{\numberline {6}Licence}{28}{section.6} -\contentsline {section}{\numberline {7}Appendices}{28}{section.7} -\contentsline {subsection}{\numberline {7.1}Paths}{28}{subsection.7.1} -\contentsline {subsection}{\numberline {7.2}File formats}{28}{subsection.7.2} -\contentsline {subsubsection}{\numberline {7.2.1}State file}{28}{subsubsection.7.2.1} -\contentsline {subsubsection}{\numberline {7.2.2}Range files}{29}{subsubsection.7.2.2} -\contentsline {subsubsection}{\numberline {7.2.3}POS files}{31}{subsubsection.7.2.3} -\contentsline {subsubsection}{\numberline {7.2.4}Text files}{31}{subsubsection.7.2.4} -\contentsline {subsection}{\numberline {7.3}External Program Examples}{31}{subsection.7.3} -\contentsline {subsubsection}{\numberline {7.3.1}Scilab}{32}{subsubsection.7.3.1} -\contentsline {subsubsection}{\numberline {7.3.2}Python}{36}{subsubsection.7.3.2} -\contentsline {subsubsection}{\numberline {7.3.3}Bash}{37}{subsubsection.7.3.3} -\contentsline {subsubsection}{\numberline {7.3.4}C/C++}{39}{subsubsection.7.3.4} -\contentsline {subsection}{\numberline {7.4}Modifying the program}{43}{subsection.7.4} -\contentsline {subsubsection}{\numberline {7.4.1}Development tools}{44}{subsubsection.7.4.1} -\contentsline {subsubsection}{\numberline {7.4.2}Getting yourself set up}{44}{subsubsection.7.4.2} -\contentsline {subsubsection}{\numberline {7.4.3}Changing stuff}{44}{subsubsection.7.4.3} Binary files /tmp/arveZAt5b_/3depict-0.0.12/locales/de_DE/LC_MESSAGES/3Depict.mo and /tmp/ZSARKCsiTI/3depict-0.0.13/locales/de_DE/LC_MESSAGES/3Depict.mo differ diff -Nru 3depict-0.0.12/m4/ftgl.m4 3depict-0.0.13/m4/ftgl.m4 --- 3depict-0.0.12/m4/ftgl.m4 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/m4/ftgl.m4 2013-03-27 17:41:19.000000000 +0000 @@ -11,22 +11,21 @@ dnl dnl This script requires the pkg.m4 file -AC_DEFUN([AX_CHECK_FTGL], [ -dnl AC_REQUIRE([PKG_CHECK_MODULES]) - I had to take this out, with it in it messes up confgure -dnl as the PKG_CHECK_MODULES is expanded with no arguments. I dont want to expand it, I just -dnl want to ensure that it is defined. never mind. - -# +#This is broken without pkg-config!! # Allow user to pass a manual dir for FTGL # -AC_ARG_WITH([ftgl-prefix], [AC_HELP_STRING([--with-ftgl-prefix=PFX]), - Manually specify the FTGL location (optional)], +AC_ARG_WITH([ftgl-prefix], [--with-ftgl-prefix : specify prefix dir for FTGL], ftgl_prefix="$withval", ftgl_config_prefix="") # # allow for disabling the pkg-config check -# FIXME: THIS DOESN'T work "unrecognised option" -AC_ARG_WITH([ftgl-dont-use-pkg], - [ AC_HELP_STRING([--ftgl-dont-use-pkg], [ don't use pkg-config to check for ftgl]) ]) +AC_ARG_WITH([ftgl-no-pkg], + [--with-ftgl-no-pkg : don't use pkg-config to check for ftgl]) + +AC_DEFUN([AX_CHECK_FTGL], [ +dnl AC_REQUIRE([PKG_CHECK_MODULES]) - I had to take this out, with it in it messes up confgure +dnl as the PKG_CHECK_MODULES is expanded with no arguments. I dont want to expand it, I just +dnl want to ensure that it is defined. never mind. + AC_MSG_CHECKING([for ftgl]) @@ -38,29 +37,52 @@ FTGL_CFLAGS="-I$ftgl_prefix/include/ -L$ftgl_prefix/lib/" FTGL_LIBS="-lFTGL" else - if test "x$ftgl_dont_use_pkg" = "xyes" ; then + + HAVE_PKG=$(basename $(which pkg-config)) + + + if test $HAVE_PKG != x"pkg-config" ; then + manual_ftgl="yes" ; + fi + + + if test "x$with_ftgl_no_pkg" = "xyes" ; then AC_DEFINE([FTGL_NO_PKG_CONFIG], [1], [Dont use pkg-config to locate ftgl]) #well the user doesn't want us to use pkg-config so dont. manual_ftgl=yes - else - # - #Use PKG_CONFIG to do the heavy lifting, must be greater than 2.0.0 - # - PKG_CHECK_MODULES([FTGL], ftgl >= 2.0.0, [libftgl="yes"], [libftgl="no"]) - - #Check to see if pkg-config did the job - if test "x$libftgl" = "xno" ; then - #dang, looks like we have to try a manual approach - manual_ftgl=yes + else + if ! test x"$manual_ftgl" == x"yes" ; then + # + #Use PKG_CONFIG to do the heavy lifting, must be greater than 2.0.0 + # + PKG_CHECK_MODULES([FTGL], ftgl >= 2.0.0, [libftgl="yes"], [libftgl="no"]) + + #Check to see if pkg-config did the job + if test "x$libftgl" = "xno" ; then + #dang, looks like we have to try a manual approach + manual_ftgl=yes ; + fi fi fi fi -#TODO: see if we can put in some manual tests for a few common locations for ftgl? if test "x$manual_ftgl" = "xyes" ; then - AC_MSG_ERROR([*** Couldn't find FTGL, either provide the path to the base dir, i e if you libs are in /usr/lib and your includes are in /usr/include or /usr/include/FTGL then use the --with-ftgl-prefix=/usr/ to tell configure where to look, or alternately install pkg-config and ensure pkg-config outputs the correct path for ftgl ***]) + CFLAGS_ORIG="$CFLAGS" + LIBS_ORIG="$LIBS" + LIBS="$LIBS $FTGL_LIBS $LDFLAGS" + + if test x$FTGL_LIBS == x"" ; then + FTGL_LIBS="-lftgl" + fi + + #TODO: see if we can put in some more manual tests for a few common locations for ftgl? + AC_CHECK_LIB(ftgl, ftglCreateSimpleLayout, + [], AC_MSG_ERROR([Couldnt find ftgl -- provide base dir or install pkg_config]),-lm) + + CFLAGS="$CFLAGS_ORIG" + LIBS="$LIBS_ORIG" fi # diff -Nru 3depict-0.0.12/packaging/RPM/3Depict-0.0.13-font-path.patch 3depict-0.0.13/packaging/RPM/3Depict-0.0.13-font-path.patch --- 3depict-0.0.12/packaging/RPM/3Depict-0.0.13-font-path.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/RPM/3Depict-0.0.13-font-path.patch 2013-03-23 18:04:46.000000000 +0000 @@ -0,0 +1,27 @@ +diff -r 1b997a96b779 src/wxcomponents.cpp +--- src/wxcomponents.cpp Sat Mar 23 17:50:44 2013 +0000 ++++ src/wxcomponents.cpp Sat Mar 23 17:56:14 2013 +0000 +@@ -857,16 +857,17 @@ + //(Oh look Ma, I'm autoconf!) + + const char *dirs[] = { ".", +- "/usr/share/fonts/truetype", //Old debian ++ "/usr/local/share/fonts/truetype", // User fonts + "/usr/share/fonts/truetype/freefont", // New debian + "/usr/share/fonts/truetype/ttf-dejavu", //New debian +- "/usr/local/share/fonts/truetype", // User fonts ++ "/usr/share/fonts/truetype", //Old debian ++ "/usr/share/fonts/dejavu", //Fedora + "/usr/X11R6/lib/X11/fonts/truetype", + "/usr/X11R6/lib64/X11/fonts/truetype", +- "/usr/lib/X11/fonts/truetype",// Fedora 32 +- "/usr/lib64/X11/fonts/truetype", //Fedora 64 +- "/usr/local/lib/X11/fonts/truetype", // Fedora 32 new +- "/usr/local/lib64/X11/fonts/truetype",// Fedora 64 new ++ "/usr/lib/X11/fonts/truetype", ++ "/usr/lib64/X11/fonts/truetype", ++ "/usr/local/lib/X11/fonts/truetype", ++ "/usr/local/lib64/X11/fonts/truetype", + "", + }; //MUST end with "". + diff -Nru 3depict-0.0.12/packaging/RPM/3Depict-0.0.13-manual-pdf-loc.patch 3depict-0.0.13/packaging/RPM/3Depict-0.0.13-manual-pdf-loc.patch --- 3depict-0.0.12/packaging/RPM/3Depict-0.0.13-manual-pdf-loc.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/RPM/3Depict-0.0.13-manual-pdf-loc.patch 2013-03-23 18:04:46.000000000 +0000 @@ -0,0 +1,16 @@ +diff -r 1b997a96b779 src/gui/mainFrame.cpp +--- src/gui/mainFrame.cpp Sat Mar 23 17:50:44 2013 +0000 ++++ src/gui/mainFrame.cpp Sat Mar 23 17:56:36 2013 +0000 +@@ -2546,9 +2546,9 @@ + string s; + s=locateDataFile("3Depict-manual.pdf"); + +- //Also Debian makes us use the lowercase "D", so check there too. +- if(!s.size()) +- s=locateDataFile("3depict-manual.pdf"); ++ //Also Fedora has diff dir ++ if(!wxFileExists(wxStr(s))) ++ s="/usr/share/doc/3Depict-0.0.8/3Depict-0.0.8-manual.pdf"; + + + //If we found it, use the default program associated with that data file diff -Nru 3depict-0.0.12/packaging/RPM/3Depict-0.0.9-font-path.patch 3depict-0.0.13/packaging/RPM/3Depict-0.0.9-font-path.patch --- 3depict-0.0.12/packaging/RPM/3Depict-0.0.9-font-path.patch 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/packaging/RPM/3Depict-0.0.9-font-path.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -diff -r dfc04b8b14b2 src/wxcomponents.cpp ---- src/wxcomponents.cpp Fri May 20 22:26:38 2011 +0100 -+++ src/wxcomponents.cpp Fri May 20 22:27:00 2011 +0100 -@@ -666,6 +666,7 @@ - //This is a list of possible target dirs to search - //(Oh look Ma, I'm autoconf!) - const char *dirs[] = { ".", -+ "/usr/share/fonts/dejavu", //Fedora - "/usr/share/fonts/truetype", - "/usr/local/share/fonts/truetype", - "/usr/X11R6/lib/X11/fonts/truetype", diff -Nru 3depict-0.0.12/packaging/RPM/3Depict-0.0.9-manual-pdf-loc.patch 3depict-0.0.13/packaging/RPM/3Depict-0.0.9-manual-pdf-loc.patch --- 3depict-0.0.12/packaging/RPM/3Depict-0.0.9-manual-pdf-loc.patch 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/packaging/RPM/3Depict-0.0.9-manual-pdf-loc.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -diff -r 634db475333f src/3Depict.cpp ---- src/3Depict.cpp Sun Oct 23 17:43:37 2011 +0100 -+++ src/3Depict.cpp Sun Oct 23 17:44:33 2011 +0100 -@@ -2142,9 +2142,9 @@ - string s; - s=locateDataFile("3Depict-manual.pdf"); - -- //Also Debian makes us use the lowercase "D", so check there too. -- if(!s.size()) -- s=locateDataFile("3depict-manual.pdf"); -+ //Also Fedora has diff dir -+ if(!wxFileExists(wxStr(s))) -+ s="/usr/share/doc/3Depict-0.0.8/3Depict-0.0.8-manual.pdf"; - - - //If we found it, use the default program associated with that data file diff -Nru 3depict-0.0.12/packaging/RPM/3Depict.spec 3depict-0.0.13/packaging/RPM/3Depict.spec --- 3depict-0.0.12/packaging/RPM/3Depict.spec 2012-11-11 20:10:07.000000000 +0000 +++ 3depict-0.0.13/packaging/RPM/3Depict.spec 2013-03-23 18:05:07.000000000 +0000 @@ -1,5 +1,5 @@ Name: 3Depict -Version: 0.0.12 +Version: 0.0.13 Release: 1%{?dist} Summary: Valued 3D point cloud visualization and analysis Group: Applications/Engineering @@ -27,7 +27,7 @@ #WX widgets BuildRequires: wxGTK-devel #PDF latex build -BuildRequires: tex(latex) +#BuildRequires: tex(latex) #Required for surface removal algorithms BuildRequires: qhull-devel @@ -54,20 +54,13 @@ %configure --disable-debug-checks --enable-openmp-parallel make %{?_smp_mflags} -pushd docs/manual-latex -pdflatex manual.tex -bibtex manual -pdflatex manual.tex -popd - - %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} # Install the textures mkdir -p %{buildroot}%{_datadir}/%{name}/textures -cp -p src/textures/* %{buildroot}%{_datadir}/%{name}/textures +cp -p data/textures/*png %{buildroot}%{_datadir}/%{name}/textures/ #Install the manpage @@ -77,7 +70,7 @@ --dir %{buildroot}%{_datadir}/applications \ packaging/%{name}.desktop mkdir -p %{buildroot}%{_datadir}/pixmaps/ -install -Dp -m 644 src/tex-source/%{name}-icon.svg %{buildroot}%{_datadir}/pixmaps/%{name}.svg +install -Dp -m 644 data/textures/tex-source/%{name}-icon.svg %{buildroot}%{_datadir}/pixmaps/%{name}.svg #install language files #-- @@ -116,7 +109,19 @@ %changelog -* Sun Nov 11 2012 D Haley - 0.0.12-1 +* Sun Mar 23 2013 D Haley - 0.0.13-1 +- Update to 0.0.13 + +* Sun Mar 23 2013 D Haley - 0.0.12-4 +- Add aarch 64 patch for bug 924960, until next version + +* Wed Feb 13 2013 Fedora Release Engineering - 0.0.12-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Sun Dec 9 2012 D Haley - 0.0.12-2 +- Import bugfixes from upstream for plot UI and crash fixes + +* Sun Nov 25 2012 D Haley - 0.0.12-1 - Update to 0.0.12 * Mon Apr 2 2012 D Haley - 0.0.10-1 @@ -131,7 +136,7 @@ * Thu Jan 12 2012 Fedora Release Engineering - 0.0.9-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild -* Sat Dec 20 2011 D Haley - 0.0.9-1 +* Sat Dec 17 2011 D Haley - 0.0.9-1 - Update to 0.0.9 * Tue Dec 06 2011 Adam Jackson - 0.0.8-3 @@ -146,13 +151,13 @@ * Sun Aug 14 2011 D Haley - 0.0.7-1 - Update to 0.0.7 -* Sun May 20 2011 D Haley - 0.0.6-1 +* Fri May 20 2011 D Haley - 0.0.6-1 - Update to 0.0.6 -* Mon Mar 27 2011 D Haley - 0.0.5-1 +* Sun Mar 27 2011 D Haley - 0.0.5-1 - New upstream release -* Sat Mar 13 2011 D Haley - 0.0.4-3 +* Sun Mar 13 2011 D Haley - 0.0.4-3 - Patch opengl startup code -- peek at gl context. Possible fix for bug 684390 * Sat Feb 12 2011 D Haley - 0.0.4-2 @@ -174,5 +179,5 @@ - Update to 0.0.2 - Address comments in package review -* Sat Aug 08 2010 D Haley - 0.0.1-1 +* Sun Aug 08 2010 D Haley - 0.0.1-1 - Initial package diff -Nru 3depict-0.0.12/packaging/check3Depict-cross.sh 3depict-0.0.13/packaging/check3Depict-cross.sh --- 3depict-0.0.12/packaging/check3Depict-cross.sh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/check3Depict-cross.sh 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,86 @@ +#!/bin/bash +#A script for checking that the cross-compilation build still compiles + +#You probably want to set up your own environment first, then customise +# this script, rather than trying to use it as a base for cross-compilation + +CROSS_BASEDIR= +#Abort notice file +ABORT_MSG_FILE=/tmp/NOTE_ABORT +#Project directory, relative to CROSS_BASEDIR +PROJECTDIR=3Depict + +if [ ! -d $CROSS_BASEDIR ] ; then + echo "Cross compilation base dir missing :" $CROSS_BASEDIR + exit 1 +fi + +if [ ! -d $CROSS_BASEDIR/$PROJECT ] ; then + echo "Cross compilation base dir missing :" $CROSS_BASEDIR + exit 1 +fi + +#Number of simultaneous processes when building +NUM_PROC=3 + +notifyAbort() +{ + cat $ABORT_MSG_FILE + rm $ABORT_MSG_FILE + exit 1 +} + +cd $CROSS_BASEDIR/$PROJECT +#Set the cross compilation path +PATH=$CROSS_BASEDIR/bin:$PATH + +hg pull + +if [ $? -ne 0 ] ; then + echo "Pull failed!" >> $ABORT_MSG_FILE + notifyAbort +fi + +hg up -r tip + +if [ $? -ne 0 ] ; then + echo "Update failed!" >> $ABORT_MSG_FILE + notifyAbort +fi + + +make distclean +if [ $? -ne 0 ] ; then + echo "cross compile did not clean!" > $ABORT_MSG_FILE + notifyAbort +fi + +#Initiate the configuration +export CPPFLAGS="-I${CROSS_BASEDIR}/include/ -DUNICODE" +export LDFLAGS=-L${CROSS_BASEDIR}/lib/ +#openmp is, out of the box, not supported by the cross-compiler. +# Bug : http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=625779 +# Looks like its an easy fix, but we would need our own private version +./configure --host=x86_64-w64-mingw32 --enable-debug-checks + +if [ $? -ne 0 ] ; then + echo "Configure failed!" > $ABORT_MSG_FILE + notifyAbort +fi + + + +make -j $NUM_PROC + +if [ $? -ne 0 ] ; then + echo "Build failed" > $ABORT_MSG_FILE + notifyAbort +fi + +if [ ! -f $BINARY ] ; then + echo "Weird, binary is missing!" > $ABORT_MSG_FILE + notifyAbort +fi + +echo "Build succeeded" + diff -Nru 3depict-0.0.12/packaging/debian/3depict.1 3depict-0.0.13/packaging/debian/3depict.1 --- 3depict-0.0.12/packaging/debian/3depict.1 2012-11-11 18:50:07.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/3depict.1 2013-03-23 17:38:30.000000000 +0000 @@ -25,7 +25,7 @@ .PP As a further note, the XML file format has not been stabilised for the 0.0.x series; and may change between revisions .SH AUTHOR -3Depict was written by D. Haley in 2011 +3Depict was written by D. Haley in 2012 .SH HOMEPAGE 3Depict Project Home : http://threedepict.sourceforge.net .PP diff -Nru 3depict-0.0.12/packaging/debian/changelog 3depict-0.0.13/packaging/debian/changelog --- 3depict-0.0.12/packaging/debian/changelog 2012-11-14 22:19:49.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/changelog 2013-03-23 17:38:30.000000000 +0000 @@ -1,20 +1,21 @@ -3depict (0.0.12-1) UNRELEASED; urgency=low +3depict (0.0.13-1) unstable; urgency=low - * Update to upstream - - -- D Haley Wed, 14 Nov 2012 22:34:50 +0100 - -3depict (0.0.10-3) unstable; urgency=low + * New upstream release - * Apply upstream patch to fix value transform filter + -- D Haley Sat, 23 Mar 2013 16:06:15 +0100 - -- D Haley Fri, 6 Apr 2012 15:52:57 +0100 +3depict (0.0.12-1) experimental; urgency=low -3depict (0.0.10-2) UNRELEASED; urgency=low + [ D Haley ] + * New upstream release + [ Sylvestre Ledru ] * Standards-Version updated to version 3.9.3 - -- Sylvestre Ledru Mon, 02 Apr 2012 01:01:11 +0200 + [ Sébastien Villemot ] + * Refreshed patches + + -- D Haley Sat, 24 Nov 2012 23:54:29 +0100 3depict (0.0.10-1) unstable; urgency=low diff -Nru 3depict-0.0.12/packaging/debian/copyright 3depict-0.0.13/packaging/debian/copyright --- 3depict-0.0.12/packaging/debian/copyright 2012-11-11 18:50:07.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/copyright 2013-03-23 17:38:30.000000000 +0000 @@ -9,7 +9,7 @@ Copyright: - Copyright (C) 2010 D. Haley + Copyright (C) 2012 D. Haley License: @@ -33,7 +33,7 @@ The Debian packaging is: - Copyright (C) 2010 D Haley + Copyright (C) 2012 D Haley and is licensed under the GPL version 3 or any later version, see `/usr/share/common-licenses/GPL-3'. diff -Nru 3depict-0.0.12/packaging/debian/patches/3depict-docdir.patch 3depict-0.0.13/packaging/debian/patches/3depict-docdir.patch --- 3depict-0.0.12/packaging/debian/patches/3depict-docdir.patch 2012-11-14 22:19:32.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/patches/3depict-docdir.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Documentation directory change for debian -Index: 3depict/src/3Depict.cpp -=================================================================== ---- 3depict.orig/src/3Depict.cpp 2012-11-14 22:44:44.000000000 +0100 -+++ 3depict/src/3Depict.cpp 2012-11-14 22:44:47.000000000 +0100 -@@ -2651,11 +2651,13 @@ - { - //First attempt to locate the local copy of the manual. - string s; -- s=locateDataFile("3Depict-manual.pdf"); -+ s=locateDataFile("manual.pdf"); - - //Also Debian makes us use the lowercase "D", so check there too. - if(!s.size()) -- s=locateDataFile("3depict-manual.pdf"); -+ { -+ s=std::string("/usr/share/3depict/manual.pdf"); -+ } - - - //If we found it, use the default program associated with that data file diff -Nru 3depict-0.0.12/packaging/debian/patches/FTGL-lowercase.patch 3depict-0.0.13/packaging/debian/patches/FTGL-lowercase.patch --- 3depict-0.0.12/packaging/debian/patches/FTGL-lowercase.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/patches/FTGL-lowercase.patch 2013-03-23 17:38:30.000000000 +0000 @@ -0,0 +1,13 @@ +Index: 3depict-0.0.13/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 @@ + 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 + diff -Nru 3depict-0.0.12/packaging/debian/patches/font-path-changed.patch 3depict-0.0.13/packaging/debian/patches/font-path-changed.patch --- 3depict-0.0.12/packaging/debian/patches/font-path-changed.patch 2012-11-14 22:19:34.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/patches/font-path-changed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Upstream assumes different font directories than debian. -Index: 3depict/src/wxcomponents.cpp -=================================================================== ---- 3depict.orig/src/wxcomponents.cpp 2012-11-14 22:44:44.000000000 +0100 -+++ 3depict/src/wxcomponents.cpp 2012-11-14 22:45:13.000000000 +0100 -@@ -681,8 +681,15 @@ - { - //This is a list of possible target dirs to search - //(Oh look Ma, I'm autoconf!) -+ -+ //DEBIAN PATCH: So, it looks like someone moved all the fonts! -+ // I have no idea why they did that... Lets just use the dirs I have on my -+ // clean debian machine. I have to find a better way to do this, or please -+ // stop moving my fonts! - const char *dirs[] = { ".", - "/usr/share/fonts/truetype", -+ "/usr/share/fonts/truetype/freefont", -+ "/usr/share/fonts/truetype/ttf-dejavu", - "/usr/local/share/fonts/truetype", - "/usr/X11R6/lib/X11/fonts/truetype", - "/usr/X11R6/lib64/X11/fonts/truetype", diff -Nru 3depict-0.0.12/packaging/debian/patches/lowercase-textdomain.patch 3depict-0.0.13/packaging/debian/patches/lowercase-textdomain.patch --- 3depict-0.0.12/packaging/debian/patches/lowercase-textdomain.patch 2012-11-14 22:19:35.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/patches/lowercase-textdomain.patch 2013-03-23 17:38:30.000000000 +0000 @@ -1,9 +1,9 @@ Debian uses different text domain for the lang files -Index: 3depict/src/3Depict.cpp +Index: 3depict-0.0.13/src/3Depict.cpp =================================================================== ---- 3depict.orig/src/3Depict.cpp 2012-11-14 22:44:47.000000000 +0100 -+++ 3depict/src/3Depict.cpp 2012-11-14 22:45:18.000000000 +0100 -@@ -5678,7 +5678,7 @@ +--- 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 @@ else { //Set the gettext language @@ -12,7 +12,7 @@ setlocale (LC_ALL, ""); #ifdef __WXMAC__ bindtextdomain( PROGRAM_NAME, paths->GetResourcesDir().mb_str(wxConvUTF8) ); -@@ -5710,8 +5710,8 @@ +@@ -196,8 +196,8 @@ break; } #else diff -Nru 3depict-0.0.12/packaging/debian/patches/series 3depict-0.0.13/packaging/debian/patches/series --- 3depict-0.0.12/packaging/debian/patches/series 2012-11-14 22:19:36.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/patches/series 2013-03-23 17:38:30.000000000 +0000 @@ -1,5 +1,3 @@ -3depict-docdir.patch debian-desktop-naming.patch -font-path-changed.patch lowercase-textdomain.patch FTGL-lowercase.patch diff -Nru 3depict-0.0.12/packaging/debian/rules 3depict-0.0.13/packaging/debian/rules --- 3depict-0.0.12/packaging/debian/rules 2012-11-14 22:20:08.000000000 +0000 +++ 3depict-0.0.13/packaging/debian/rules 2013-03-23 17:38:30.000000000 +0000 @@ -9,8 +9,6 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -DPKG_EXPORT_BUILDFLAGS=1 -include /usr/share/dpkg/buildflags.mk # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) @@ -22,11 +20,15 @@ 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" LDFLAGS="${LDFLAGS} -Wl,-z,defs" --with-ftgl-prefix="/usr" + ./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 @@ -63,7 +65,8 @@ $(MAKE) DESTDIR=$(CURDIR)/debian/3depict install #Install the textures - cp -rp src/textures/ $(CURDIR)/debian/3depict/usr/share/3depict/ + mkdir -p $(CURDIR)/debian/3depict/usr/share/3depict/textures/ + cp -p data/textures/*png $(CURDIR)/debian/3depict/usr/share/3depict/textures/ #rename 3Depict (real program name) to debian-friendly 3depict mv $(CURDIR)/debian/3depict/usr/bin/3Depict $(CURDIR)/debian/3depict/usr/bin/3depict @@ -75,8 +78,8 @@ #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)/src/3Depict.xpm $(CURDIR)/debian/3depict/usr/share/pixmaps/3depict.xpm - install -Dp -m 644 $(CURDIR)/src/tex-source/3Depict-icon.svg $(CURDIR)/debian/3depict/usr/share/pixmaps/3depict.svg + 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. diff -Nru 3depict-0.0.12/packaging/deps/getDeps 3depict-0.0.13/packaging/deps/getDeps --- 3depict-0.0.12/packaging/deps/getDeps 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/deps/getDeps 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,823 @@ +#!/bin/bash + +# +# getDeps- The dependency handler you're using when your not using +# a dependency handler. (Downloads dependencies for 3Depict) +# Copyright (C) 2012, D Haley, AV Ceguerra +# +# 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 . +# + +function setFullDeps { + #Dependency ID, URL and name + DEPIDS=( 0 1 2 3 4 5) + DEPNAMES=( libpng freetype ftgl wxwidgets mathgl qhull) + DEPURLS=(https://sourceforge.net/projects/libpng/files/libpng15/older-releases/1.5.4/libpng-1.5.4.tar.gz \ + https://sourceforge.net/projects/freetype/files/freetype2/2.4.6/freetype-2.4.6.tar.gz \ + http://downloads.sourceforge.net/project/ftgl/FTGL%20Source/2.1.3%7Erc5/ftgl-2.1.3-rc5.tar.gz \ + http://downloads.sourceforge.net/project/wxwindows/2.8.11/wxWidgets-2.8.11.tar.gz \ + http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download \ + http://www.qhull.org/download/qhull-2011.1-src.tgz) + DEPFILENAMES=(libpng-1.5.4.tar.gz \ + freetype-2.4.6.tar.gz \ + ftgl-2.1.3-rc5.tar.gz \ + wxWidgets-2.8.11.tar.gz \ + mathgl-1.11.2.tar.gz \ + qhull-2011.1-src.tgz) + DEPMDSUM=(dea4d1fd671160424923e92ff0cdda78 \ + 1dc4af24a86e2f78a49ac6b520a81ec5 \ + fcf4d0567b7de9875d4e99a9f7423633 \ + ce80389e1b70d6a518c80b7b715b763e\ + acd33e68911d9506f60d769dce23f95e \ + a65061cf2a6e6581182f4df0f3667a8e) + +} + +function setMacDeps { + OS_VERSION=`sw_vers -productVersion |sed 's/\.[0-9]*$//'` + #Dependency ID, URL and name + DEPIDS=( 0) + DEPNAMES=( mathgl) + DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download) + DEPFILENAMES=( mathgl-1.11.2.tar.gz) + DEPMDSUM=( acd33e68911d9506f60d769dce23f95e) + +} + +function installMacPorts { + #check to see if it's installed + if [ x"`which port`" == x"" ] ; then + echo "macports will now be installed..." + echo "OS_VERSION = $OS_VERSION" + + if [ x"$OS_VERSION" == x"10.5" ] ; then + curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3-10.5-Leopard.dmg + hdiutil attach MacPorts-2.0.3-10.5-Leopard.dmg + elif [ x"$OS_VERSION" == x"10.6" ] ; then + curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3-10.6-SnowLeopard.dmg + hdiutil attach MacPorts-2.0.3-10.6-SnowLeopard.dmg + elif [ x"$OS_VERSION" == x"10.7" ] ; then + curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3-10.7-Lion.dmg + hdiutil attach MacPorts-2.0.3-10.7-Lion.dmg + else + echo "Mac OS X $OS_VERSION not supported." + exit 1 + fi + if [ $? -ne 0 ] ; then + echo "macports dmg could not be mounted" + exit 1 + fi + + # use installer to install macports to /opt/local + sudo installer -pkg /Volumes/MacPorts-2.0.3/MacPorts-2.0.3.pkg -target / + hdiutil detach /Volumes/MacPorts-2.0.3/ + + echo "sourcing .profile after macports installation" + . ~/.profile + + echo "updating macports ports tree to latest..." + sudo port selfupdate + if [ $? -ne 0 ] ; then + echo "macports was not successful in updating ports tree" + exit 1 + fi + else + echo "macports is already already installed." + fi +} + +function setSuseDeps { + DEPIDS=( 0) + DEPNAMES=( mathgl) + DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download) + DEPFILENAMES=( mathgl-1.11.2.tar.gz) + DEPMDSUM=( acd33e68911d9506f60d769dce23f95e) + +} + +function setCentOS5Deps { + DEPIDS=( 0) + DEPNAMES=( mathgl) + DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download) + DEPFILENAMES=( mathgl-1.11.2.tar.gz) + DEPMDSUM=( acd33e68911d9506f60d769dce23f95e) + +} + +function detectProxy() +{ + #Check the http proxy variable + if [ x"$http_proxy" == x"" ] ; then + if [ x"$OS_NAME" == x"Darwin" ] ; then + ##Are we using mac? Try to get the proxy automagically + + #PROXY=`system_profiler |grep "Auto Configure URL" | sed 's/^[ ]*//' | sort | uniq | awk {'sub(/^.*:[ \t]*/, "", $0); print $0;'}` + PROXY=`system_profiler SPNetworkDataType|grep "HTTP Proxy Server" | sed 's/^[ ]*//' |sort | uniq | awk {'sub(/^.*:[ \t]*/, "", $0); print $0;'}` + PROXYPORT=`system_profiler SPNetworkDataType|grep "HTTP Proxy Port" | sed 's/^[ ]*//' |sort | uniq | awk {'sub(/^.*:[ \t]*/, "", $0); print $0;'}` + if [ x"$PROXY" != x"" ] ; then + echo "using proxy as : $PROXY:$PROXYPORT ; hope this works" + export http_proxy=$PROXY:$PROXYPORT + fi + + echo "using $http_proxy as the proxy server" + else + echo "Proxy not found... Maybe you dont need one." + echo " You can set one by passing it as an argument (./getdeps nameofproxy), if required" + echo " eg: ./getdeps your_proxy_server:12345" + echo + echo "Or you can set it at the command line with " + echo " export http_proxy=your_proxy_server:12345" + echo "(where 12345 is the proxy server \"port\"), usually 8080 or 8000" + fi + else + echo "using $http_proxy as the proxy server" + fi +} + +function parseArgs() +{ + if [ $# -gt 1 ] ; then + echo "usage : getDeps [proxyserver]" + exit 1 + elif [ $# -eq 1 ] ; then + export http_proxy=$1 + echo "using $1 as the proxy server" + else + #User did not specify a proxy as argument - try to detect + echo "detecting proxy..." + detectProxy + fi +} + +function testCompiler() +{ + echo "int main(int argc, char *argv[]) { return 0; } ; " > gcctest.c + gcc gcctest.c -o gcctest + + if [ ! -f gcctest ] ; then + echo "You do not have gcc (GNU compiler frontend) installed?? Install it into your PATH, then try again." + exit 1 + fi + rm gcctest.c gcctest + + echo "int main(int argc, char *argv[]) { return 0; } ; " > gcctest.cpp + + g++ gcctest.cpp -o gcctest + if [ ! -f gcctest ] ; then + echo "You do not have g++ (C++ compiler) installed?? Install it into your PATH, then try again." + exit 1 + fi + + rm gcctest.cpp gcctest +} + +function handleMacDistro() +{ + + #Ensure fink/homebrew are not installed + for i in fink homebrew + do + if [ x"`which $i`" != x"" ] ; then + echo "$i was detected on your system - getDeps assumes macports is in use. Either install deps manually using fink, or use macports..." + exit 1 + fi + done + + + # install deps except mathgl + echo "installing 3Depict dependencies..." + sudo port install wget libpng freetype ftgl wxWidgets-devel dylibbundler qhull gsl cmake libtool pkgconfig + if [ $? -ne 0 ] ; then + echo "macports was not successful in getting the dependencies" + exit 1 + fi +} + +function handleLinuxDistro() +{ + #Attempt to detect some popular linux distros + echo "Trying to detect your linux system type. " + echo "If this fails, you should just try to use your package manager to do this" + + GUESS_DISTRIB_BY_PKGMAN="no" + if [ x`which lsb_release` == x"" ] ; then + GUESS_DISTRIB_BY_PKGMAN="yes" + else + # we have an lsb_release command - use it! + DISTRIBUTOR=`lsb_release -i -s` + if [ $? -eq 0 ] ; then + if [ x$DISTRIBUTOR == x"Debian" ] ; then + LINUXDISTRO="DebianLike" + elif [ x$DISTRIBUTOR == x"Ubuntu" ] ; then + LINUXDISTRO="DebianLike" + elif [ x$DISTRIBUTOR == x"LinuxMint" ] ; then + LINUXDISTRO="DebianLike" + elif [ x$DISTRIBUTOR == x"SUSE LINUX" ] ; then + LINUXDISTRO="SuseLike" + elif [ x$DISTRIBUTOR == x"Fedora" ] ; then + LINUXDISTRO="RedhatLike" + elif [ x$DISTRIBUTOR == x"CentOS" ] ; then + LINUXDISTRO="RedhatLike" + elif [ x`echo $DISTRIBUTOR | grep -i redhat` != x"" ] ; then + LINUXDISTRO="RedhatLike" + else + GUESS_DISTRIB_BY_PKGMAN="yes" + fi + else + LINUXDISTRO="Unknown" + fi + fi + + #Try to guess based upon package manager binary + if [ x"$GUESS_DISTRIB_BY_PKGMAN" != x"no" ] ; then + if [ x`which apt-get` != x"" ] ; then + LINUXDISTRO="DebianLike" + elif [ x`which yum` != x"" ] ; then + LINUXDISTRO="RedhatLike" + elif [ x`which zypper` != x"" ] ; then + LINUXDISTRO="SuseLike" + else + LINUXDISTRO="Unknown" + fi + fi + + case $LINUXDISTRO in + DebianLike) + echo "System appears to be Debian-esque (debian/ubuntu/mint...)." + echo "Running apt-get:" + + sudo apt-get build-dep 3depict && sudo apt-get install make g++ + if [ $? -ne 0 ] ; then + echo "Failed to install build-dependencies" + exit 1 + else + echo "All done." + exit 0 + fi + ;; + RedhatLike) + echo "System appears to be redhat like" + + sudo yum groupinstall "Development Tools" && sudo yum install yum-utils && sudo yum-builddep 3Depict + + if [ $? -ne 0 ] ; then + echo "Failed to install build dependencies" + exit 1 + else + echo "All done." + exit 0 + fi + + ;; + CentOS6) + echo "System appears to be CentOS6-like?" + + sudo yum groupinstall "Development Tools" && sudo yum install yum-utils && sudo yum install libxml2-devel ftgl-devel wxgtk-devel qhull-devel mathgl-devel + + echo " OK, so this gets tricky. Centos doesn't ship mathgl. So we have to grab it from fedora's Git repository, and build the RPM, the install that." + + + echo "Getting mgl dependencies" + sudo yum install gsl-devel libpng-devel libtool-ltdl-devel libtool swig freeglut-devel hdf-devel \ + hdf5-static libjpeg-devel libtiff-devel fltk-devel qt4-devel wxGTK-devel giflib-devel \ + autoconf automake libtool info texi2html texinfo-tex + if [ $? -eq 0 ] ; then + echo "Yum installation failed" + exit 1 + fi + + if [ x`which git` == x"" ] ; then + echo "Installing git...." + sudo yum install git + if [ $? -eq 0 ] ; then + echo "Yum git installation failed" + exit 1 + fi + fi + + git clone git://pkgs.fedoraproject.org/mathgl.git + if [ $? -eq 0 ] ; then + echo "git clone failed - couldn't retreive mathgl spec and patch data" + exit 1 + elif [ ! -f mathgl ] ; then + echo "Git clone succeded, but couldn't locate checkout dir, \"mathgl\"" + exit 1 + fi + + cd mathgl + # We want this version + git checkout 152ad15 + + if [ $? -ne 0 ] ; then + echo "Something went wrong when trying to check out the version of the repository we wanted" + exit 1 + fi + + if [ ! -f ~/rpmbuild/SOURCES ] + rpmdev-setuptree + if [ $? -ne 0 ] ; then + echo "Could not set up rpm development tree ??" + exit 1 + fi + fi + + cp mathgl.spec ~/rpmbuild/SPECS/ + cp *patch ~/rpmbuild/SOURCES/ + + MATHGLVER=1.11.2 + setCentOS6Deps + pushd ~/rpmbuild/SOURCES/ + runDownloads + checkHashes + mv sources/mathgl-${MATHGLVER}.tar..gz . + popd + + pushd ~/rpmbuild/SPEC/ + rpmbuild -ba mathgl.spec + + if [ $? -ne 0 ] ; then + echo "Runing RPMBuild failed - but we are close to getting mathgl installed, so please fix rpmbuild, and run rpmbuild -ba mathgl.spec from ~/rpmbuild/SPEC/" + exit 1 + fi + popd + + + ARCH=`uname -m` + pushd ~/rpmbuild/RPMS/${ARCH}/ + rpm -i mathgl-${MATHGLVER}*rpm + + if [ $? -ne 0 ] ; then + echo "So we built the RPMs OK, but for some reason we cannot isntall them. Not sure whats going on here. Aborting." + exit 1 + fi + popd + exit 0; + ;; + SuseLike) + echo "System appears to be suse-like" + sudo zypper install -t devel_C_C++ && sudo zypper install libxml2-devel wxGTK-devel ftgl-devel libpng14-devel freetype2-devel qhull-devel + + echo "Installed as much as is available from repo. Still need some extra deps... Proceeding to source install" + setSuseDeps + + ;; + *) + #Call setFullDeps to set depnames for error message below + setFullDeps + + echo "--------" + echo "Are you sure you need to run this?? " + echo "You are running some unrecognised version of linux " + echo "you should use your package manager to install these " + echo "libraries : ${dep_names[*]}" + echo + echo "Refusing to continue, otherwise script could break your system..." + echo "--------" + echo + exit 1 + ;; + esac +} + +function runDownloads() +{ + echo "OK, we need to download some libraries, compile them, and try to install them." + echo " This is a bit of a long-shot, but this script will try to do this automagically." + echo " Ensure your net connection is good." + + echo "---------" + echo "Let's go!" + echo "---------" + + HAVE_ALL_DEPS=0 + if [ -d sources ] ; then + echo "OK, found the \"sources\" folder. Cool" + else + echo "making the source folder" + mkdir sources + fi + + echo "Looking for dependencies" + + for i in ${DEPIDS[*]} + do + j=${DEPFILENAMES[$i]} + k=${DEPURLS[$i]} + + if [ ! -f "sources/$j" ] ; then + echo "Missing sources/$j. Will attempt to download" + +case $OS_NAME in + Darwin) + wget $k -O sources/$j + ;; + *) + + if [ x`which curl` == x"" ] ; then + echo "the program -curl- was not present. Aborting" + echo "Need the files:" + echo ${DEPFILENAMES[*]} + echo "supposedly at:" + echo ${DEPURLS[*]} + echo "try to find these online, and place in the sources folder" + fi + + #use CURL to download the file and save it to source/$k + curl -L --progress-bar $k -o sources/$j + ;; +esac + if [ $? -ne 0 ] ; then + echo "Couldn't download dependency : $j, from $k :" + echo "try to find it online, and put it in the sources folder" + fi + + if [ ! -f "sources/$j" ] ; then + echo + echo "That's not right... i was told it was downloaded, but now I can't find it." + echo "Something is wrong, you may have to download the file yourself," + echo " and place it in the sources folder" + echo + echo "Try $k" + echo "or look online for \"$j\"" + echo + echo "will continue in 8 seconds..." + sleep 8 + fi + else + echo "found $j; this is good" + fi + + + done + + echo + echo + echo " -------------------------" + echo + echo +} + +function checkHashes() +{ + + for i in ${DEPIDS[*]} + do + j=${DEPFILENAMES[$i]} + +case $OS_NAME in + Darwin) + #Mac OSX has an undocumented md5sum compat function. Use it + HASH_SUM=`md5 sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'}` + ;; + *) + HASH_SUM=`md5sum sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'}` + ;; +esac + + if [ x"$HASH_SUM" != x"${DEPMDSUM[$i]}" ] ; then + echo "Warning! The file contents for sources/$j appear to be wrong (hash mismatch). " + echo "I recommend pressing ctrl+c and downloading the file manually and overwriting it" + + echo "continuing in 20 seconds. Press ctrl+c to abort (recommended)" + sleep 20 + else + echo " $j looks OK. Good -- moving on" + sleep 1 + fi + done +} + +function prepBuildDir() +{ + echo "------------------------------" + echo " Extraction" + echo + + + if [ -d decompress ] ; then + echo "deleting existing decompress folder" + rm -rf ./decompress + fi + + + echo " Decompressing archives; this can be slow..." + + + + mkdir -p decompress + + if [ $? -ne 0 ] ; then + echo "Oh dear, I couldn't make a folder called \"decompress\". Thats odd. Giving up" + exit 1 + fi + + cd decompress + for i in ${DEPIDS[*]} + do + j=${DEPFILENAMES[$i]} + + echo "Extracting $j" + if [ x"`echo $j | grep \.tar\.gz`" != x"" ] ; then + tar -zxf ../sources/$j + elif [ x"`echo $j | grep \.tar\.bz2`" != x"" ] ; then + tar -jxf ../sources/$j + elif [ x"`echo $j | grep \.tgz`" != x"" ] ; then + tar -zxf ../sources/$j + elif [ x"`echo $j | grep \.zip`" != x"" ] ; then + unzip ../sources/$j + else + echo "$j apparently not a tar-gz or zip file! Aborting!" + exit 1 + fi + + if [ $? -ne 0 ] ; then + echo "There was a problem extracting $j, aborting" + exit 1 + fi + done + + sleep 2 + + +} + +#-----------Entry point------------ +OS_NAME=`uname` +parseArgs $* + +#Each platform needs to be initialised in a different way +case $OS_NAME in + Darwin) + #Mac OSX has an undocumented md5sum compat function. Use it + setMacDeps + installMacPorts + handleMacDistro + sleep 1; + ;; + MINGW*) + #This doesn't work under windows. + echo "This is not functional under windows, due to the difficulty of providing a robust tool chain." + + echo "---------------" + echo " If you want to fix this, please do, and send me the fix!" + echo "---------------" + exit 1 + ;; + Linux) + handleLinuxDistro + + ;; + *) + echo "Your platform was not recognised. Program will proceed, but may fail" + sleep 1 + setFullDeps + ;; +esac + +testCompiler + +runDownloads + + +echo "So it looks like we have downloaded all the files." +echo "I'm just going to check the integrity of these files first." +echo + +checkHashes + +prepBuildDir + + +echo "------------------------------" +echo " Compilation" + +######## +for i in ${DEPIDS[*]} +do + j=${DEPFILENAMES[$i]} + + #Strip the extension from the filename + if [ x"`echo $j | grep \.tar\.gz`" != x"" ] ; then + foldername=${j%.tar.gz} + elif [ x"`echo $j | grep \.tar\.bz2`" != x"" ] ; then + foldername=${j%.tar.bz2} + elif [ x"`echo $j | grep \.tgz`" != x"" ] ; then + foldername=${j%.tgz} + elif [ x"`echo $j | grep \.zip`" != x"" ] ; then + foldername=${j%.zip} + else + echo "$j apparently not a tar-gz or zip file! Aborting!" + exit 1 + fi + + pushd $foldername + + echo "Attempting to compile ${DEPNAMES[$i]}" + case "${DEPNAMES[$i]}" in + libpng) + # Compile libpng + case "$OS_NAME" in + Linux) + make -f scripts/makefile.linux + ;; + *) + echo "Unable to build libpng, unknown platform" + exit 1 + ;; + esac + + if [ $? -ne 0 ] ; then + echo "Damn. Unable to build. Aborting" + exit 1 + fi + + echo "I want to install ${DEPNAMES[$i]} to the system:" + #install + sudo make install -f scripts/makefile.linux + if [ $? -ne 0 ] ; then + echo "Damn. Unable to install. Aborting" + exit 1 + fi + + ;; + wxwidgets) + # Configure wxwidgets; to let it find this bits its wants + ./configure --enable-unicode --with-opengl + + if [ $? -ne 0 ] ; then + echo "Damn. Unable to configure. Aborting" + exit 1 + fi + + echo "OK, configure was good. Building, this will take a while" + sleep 2 + + make + + if [ $? -ne 0 ] ; then + echo "Damn. Unable to build. Aborting" + exit 1 + fi + + echo "I want to install ${DEPNAMES[$i]} to the system:" + #install + sudo make install + if [ $? -ne 0 ] ; then + echo "Damn. Unable to install. Aborting" + exit 1 + fi + ;; + + freetype) + # Configure freetype + ./configure + + if [ $? -ne 0 ] ; then + echo "Damn. unable to configure. aborting" + exit 1 + fi + + echo "OK, configure was good. Building, this will take a while" + sleep 2 + + make + + if [ $? -ne 0 ] ; then + echo "Damn. unable to build. aborting" + exit 1 + fi + + echo "I want to install ${DEPNAMES[$i]} to the system:" + #install + sudo make install + if [ $? -ne 0 ] ; then + echo "Damn. unable to install. aborting" + exit 1 + fi + ;; + + ftgl) + echo "Re-arranging build directory" + #FTGL has a tilde in the filename, but not the download, move it. + mv "ftgl-2.1.3~rc5" "ftgl-2.1.3-rc5" + + # Configure ftgl + ./configure CXXFLAGS="-fpermissive" + + if [ $? -ne 0 ] ; then + echo "Damn. unable to configure. aborting" + exit 1 + fi + + echo "OK, configure was good. Building, this will take a while" + sleep 2 + + make + + if [ $? -ne 0 ] ; then + echo "Damn. unable to build. aborting" + exit 1 + fi + + echo "I want to install ${DEPNAMES[$i]} to the system:" + #install + sudo make install + if [ $? -ne 0 ] ; then + echo "Damn. unable to install. aborting" + exit 1 + fi + ;; + + mathgl) + # Configure mathgl. Disable GNU scientific library to remove that dependency + if [ x"$OS_NAME" == x"Darwin" ] ; then + PNGDIR=/opt/local + PNGLIBS=" CXXFLAGS=-I$PNGDIR/include LDFLAGS=-L$PNGDIR/lib " + echo $PNGLIBS + pwd + patch mgl/mgl_eps.cpp < ../../sources/mgl_eps.patch + patch mgl/mgl_export.cpp < ../../sources/mgl_export.patch + #After upgrade to 1.5.13, this patch required. + patch mgl/mgl_data_png.cpp < ../../sources/mgl_data_png.patch + fi + ./configure --disable-gsl $PNGLIBS + + if [ $? -ne 0 ] ; then + echo "Damn. unable to configure. aborting" + exit 1 + fi + + echo "OK, configure was good. Building, this will take a while" + sleep 2 + + make + + if [ $? -ne 0 ] ; then + echo "Damn. unable to build. aborting" + exit 1 + fi + + echo "I want to install ${DEPNAMES[$i]} to the system:" + #install + sudo make install + if [ $? -ne 0 ] ; then + echo "Mathgl said it failed, but is known to misreport. Continuing in 10 seconds" + sleep 10 + fi + ;; + + qhull) + if [ x`which cmake` == "" ] ; then + echo "Cmake not found on your system. This is needed to build qhull (sigh.). You can install it from http://www.cmake.org/cmake/resources/software.html" + else + #build + cmake . + make + + #OK, lets install! + echo "I want to install ${DEPNAMES[$i]} to the system:" + sudo make install + if [ $? -ne 0 ] ; then + echo "Damn. unable to install. aborting" + exit 1 + fi + fi + + ;; + *) + echo "There is a bug in the script. I do not know the dependency ${DEPNAMES[$i]}. Aborting" + exit 1 + ;; + esac + + + + popd +done + + +######## + +echo "------------------------------" +echo " All done!" + +echo + +echo " You should hopefully be able to build and run 3Depict now!" +echo +echo + + + + diff -Nru 3depict-0.0.12/packaging/deps/sources/mgl_data_png.patch 3depict-0.0.13/packaging/deps/sources/mgl_data_png.patch --- 3depict-0.0.12/packaging/deps/sources/mgl_data_png.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/deps/sources/mgl_data_png.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,2 @@ +23a24 +> #include diff -Nru 3depict-0.0.12/packaging/deps/sources/mgl_eps.patch 3depict-0.0.13/packaging/deps/sources/mgl_eps.patch --- 3depict-0.0.12/packaging/deps/sources/mgl_eps.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/deps/sources/mgl_eps.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,22 @@ +306,308c306,308 +< +< bool gz = fname[strlen(fname)-1]=='z'; +< void *fp = gz ? gzopen(fname,"wt") : fopen(fname,"wt"); +--- +> +> bool gz = fname[strlen(fname)-1]=='z'; +> void *fp = ( gz ? gzopen(fname,"wt") : (void *)fopen(fname,"wt")); +456c456 +< if(gz) gzclose(fp); else fclose((FILE *)fp); +--- +> if(gz) gzclose((gzFile_s*)fp); else fclose((FILE *)fp); +466,467c466,467 +< bool gz = fname[strlen(fname)-1]=='z'; +< void *fp = gz ? gzopen(fname,"wt") : fopen(fname,"wt"); +--- +> bool gz = fname[strlen(fname)-1]=='z'; +> void *fp = (gz ? gzopen(fname,"wt") : (void *)fopen(fname,"wt")); +623c623 +< if(gz) gzclose(fp); else fclose((FILE *)fp); +--- +> if(gz) gzclose((gzFile_s*)fp); else fclose((FILE *)fp); diff -Nru 3depict-0.0.12/packaging/deps/sources/mgl_export.patch 3depict-0.0.13/packaging/deps/sources/mgl_export.patch --- 3depict-0.0.12/packaging/deps/sources/mgl_export.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/deps/sources/mgl_export.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,12 @@ +235c235 +< if(gz) gzprintf(fp, "%s", buf); +--- +> if(gz) gzprintf((gzFile_s*)fp, "%s", buf); +246c246 +< void *fp = gz ? gzopen(fname,"wt") : fopen(fname,"wt"); +--- +> void *fp = gz ? gzopen(fname,"wt") : (void*)fopen(fname,"wt"); +258c258 +< if(gz) gzclose(fp); else fclose((FILE *)fp); +--- +> if(gz) gzclose((gzFile_s*)fp); else fclose((FILE *)fp); diff -Nru 3depict-0.0.12/packaging/mac/1compile.sh 3depict-0.0.13/packaging/mac/1compile.sh --- 3depict-0.0.12/packaging/mac/1compile.sh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mac/1compile.sh 2013-03-27 17:41:19.000000000 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +cp makeMacOSXApp ../.. +cp -R 3Depict.app ../.. +cd ../.. +time ./makeMacOSXApp --update-config=yes --parallel=yes --debug=yes > out.txt 2>&1 + +#check compile OK +if [ $? -eq 0 ] ; then + echo "Finished compiling" +else + echo "Failed" + vi out.txt + exit 1 +fi +time ./3Depict.app/Contents/MacOS/3Depict -t > out2.txt 2>&1 +#Check return value from debug +if [ $? -eq 0 ] ; then + echo "Finished testing" +else + echo "Failed" + vi out2.txt + exit 1 +fi + diff -Nru 3depict-0.0.12/packaging/mac/2compile.sh 3depict-0.0.13/packaging/mac/2compile.sh --- 3depict-0.0.12/packaging/mac/2compile.sh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mac/2compile.sh 2013-03-27 17:41:19.000000000 +0000 @@ -0,0 +1,21 @@ +#!/bin/bash +cp makeMacOSXApp ../.. +cp -R 3Depict.app ../.. +cd ../.. +time ./makeMacOSXApp --update-config=no > out.txt 2>&1 +if [ $? -eq 0 ] ; then + echo "Finished compiling" +else + echo "Failed" + vi out.txt + exit 1 +fi +time ./3Depict.app/Contents/MacOS/3Depict -t > out2.txt 2>&1 +if [ $? -eq 0 ] ; then + echo "Finished testing" +else + echo "Failed" + vi out2.txt + exit 1 +fi + diff -Nru 3depict-0.0.12/packaging/mac/3Depict.app/Contents/Info.plist 3depict-0.0.13/packaging/mac/3Depict.app/Contents/Info.plist --- 3depict-0.0.12/packaging/mac/3Depict.app/Contents/Info.plist 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/packaging/mac/3Depict.app/Contents/Info.plist 2013-04-07 09:57:45.000000000 +0000 @@ -21,13 +21,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + BUNDLE_VERSION CFBundleSignature ???? CFBundleURLTypes CFBundleVersion - 1 + BUNDLE_VERSION DTCompiler DTPlatformBuild diff -Nru 3depict-0.0.12/packaging/mac/3package.sh 3depict-0.0.13/packaging/mac/3package.sh --- 3depict-0.0.12/packaging/mac/3package.sh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mac/3package.sh 2013-04-07 09:57:45.000000000 +0000 @@ -0,0 +1,39 @@ +#!/bin/bash + +PROGRAM_NAME=3Depict + +cp makeMacOSXApp ../.. +cp -R ${PROGRAM_NAME}.app ../.. +cd ../.. + +#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'` +BUILT_PROGRAMS_DIR=. +MAC_OS_VER=`sw_vers | grep ProductVersion | awk '{print $2}'` + +#Set bundle version +sed "s/BUNDLE_VERSION/${VERSION}/" ./3Depict.app/Contents/Info.plist > ./test.txt +mv ./test.txt ./3Depict.app/Contents/Info.plist + +time ./makeMacOSXApp --update-config=yes --parallel=yes --debug=no > out.txt 2>&1 +if [ x"`tail -1 out.txt`" == x"Done" ] ; then + echo "Finished compiling" +else + echo "Failed" + vi out.txt + exit 1 +fi + + +#Perform some QA checks +#-- +#TODO: Check debug symbols are stripped + +#-- + +ARCHIVE_FILENAME=`echo "${BUILT_PROGRAMS_DIR}/${PROGRAM_NAME}-${VERSION}-${MAC_OS_VER}.pkg"` +pkgbuild --root "${PROGRAM_NAME}.app" \ + --identifier "net.sourceforge.threedepict.${PROGRAM_NAME}" \ + --version "${VERSION}" \ + --install-location "/Applications/${PROGRAM_NAME}.app" \ + ${ARCHIVE_FILENAME} diff -Nru 3depict-0.0.12/packaging/mac/makeMacOSXApp 3depict-0.0.13/packaging/mac/makeMacOSXApp --- 3depict-0.0.12/packaging/mac/makeMacOSXApp 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/packaging/mac/makeMacOSXApp 2013-04-07 09:57:45.000000000 +0000 @@ -13,25 +13,12 @@ if [ $3 = '--debug=no' ]; then echo "Building debug off" - DISABLE_DEBUG="--enable-no-debug-checks" + DISABLE_DEBUG="--disable-debug-checks" fi - ./configure $SHOULD_PARALLEL $DISABLE_DEBUG \ - --with-libqhull-link=" -L/opt/local/lib -lqhull" \ - --with-libqhull-flags="-I/opt/local/include " \ - --with-mgl-libs="-L/usr/local/lib -lmgl" \ - --with-mgl-flags="-I/usr/local/include -I/opt/local/include" \ - --with-freetype=/opt/local \ - --with-gsl-flags=-I`gsl-config --prefix`/include \ - --with-gsl-libs="-L`gsl-config --prefix`/lib -lgsl" \ - --with-wx-prefix=`wx-config --prefix` \ - --with-xml-config=`which xml2-config` \ - --with-libpng-flags=-I`libpng14-config --prefix`/include \ - --with-libpng-link="-L`libpng14-config --prefix`/lib -lpng14" \ - --with-intl-libs="-L/opt/local/lib -lintl " \ - LDFLAGS="-headerpad_max_install_names" -# --build=x86_64-apple-darwin11.0.0 - + CFLAGS="$CFLAGS -I/opt/local/include -I/usr/local/include" \ + LDFLAGS="$LDFLAGS -L/opt/local/lib -L/usr/local/lib -headerpad_max_install_names" \ + ./configure $SHOULD_PARALLEL $DISABLE_DEBUG if [ $? -ne 0 ]; then echo "Configure unsuccessful - exiting" @@ -54,17 +41,17 @@ mkdir -p ./3Depict.app/Contents/Resources/ mkdir -p ./3Depict.app/Contents/libs/ cp ./src/3Depict ./3Depict.app/Contents/MacOS/3Depict -cp src/tex-source/3Depict-icon.icns ./3Depict.app/Contents/Resources/3Depict-icon.icns +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 -R ./src/textures ./3Depict.app/Contents/Resources +cp ./data/textures/* ./3Depict.app/Contents/Resources +cp ./data/textures/tex-source/3Depict-icon.icns ./3Depict.app/Contents/Resources #Update gettext translation #---- echo "Updating translation files..." -#cp -Rp locales/* ./3Depict.app/Contents/Resources/ for i in `ls ./translations/3Depict_*.mo` do j=`echo $i | sed 's/.\/translations\/3Depict_//' | sed 's/.mo//'` @@ -75,13 +62,12 @@ #---- - # relabel libraries for packaging if [ x`which dylibbundler` == x"" ] ; then echo "dyllibbundler command does not appear to be available. Package built, but cannot relabel libaries to use in-package versions" exit 1 fi -/opt/local/bin/dylibbundler -od -b -x ./3Depict.app/Contents/MacOS/3Depict -d ./3Depict.app/Contents/libs +dylibbundler -od -b -x ./3Depict.app/Contents/MacOS/3Depict -d ./3Depict.app/Contents/libs echo "Done" diff -Nru 3depict-0.0.12/packaging/makeTarball.sh 3depict-0.0.13/packaging/makeTarball.sh --- 3depict-0.0.12/packaging/makeTarball.sh 2012-11-24 21:13:16.000000000 +0000 +++ 3depict-0.0.13/packaging/makeTarball.sh 2013-04-10 20:58:19.000000000 +0000 @@ -15,46 +15,46 @@ MSG_FILE=tmp-$MSG_FILE done - -#Try building in debug mode -#------- -make distclean - -./configure --disable-debug-checks -if [ $? -ne 0 ] ; then - echo "no-debug mode failed to configure" -fi - -make -j $NUM_PROCS -if [ $? -ne 0 ] ; then - echo "no-debug mode failed to build" -fi -make distclean +#Check build for all 4 combinations of enable/disable parallel and debug checking #------- +CONF_ARGS=" --enable-openmp-parallel, --disable-debug-checks, --enable-debug-checks, --enable-openmp-parallel --disable-debug-checks" -#Try building in parallel mode -#------- -./configure --enable-openmp-parallel -if [ $? -ne 0 ] ; then - echo "parallel mode failed to configure" -fi -make -j$NUM_PROCS -if [ $? -ne 0 ] ; then - echo "parallel mode failed to build" -fi -make distclean +OLD_IFS=$IFS +IFS="," +for i in ${CONF_ARGS[*]} +do + echo "$i" + + make distclean + + ./configure + if [ $? -ne 0 ] ; then + echo "no-debug mode failed to configure" + fi + + make -j $NUM_PROCS + if [ $? -ne 0 ] ; then + echo "no-debug mode failed to build" + fi + + #Check for unit test availability, and run them + # where possible + pushd src + TEST_FLAG=`./3Depict --help 2>&1 | grep "\-\-test"` + if [ x"$TEST_FLAG" != x"" ] ; then + ./3Depict -t + if [ $? -ne 0 ] ; then + echo "Unit tests failed for configure flag : $i" + exit 1 + fi + fi + popd + + make distclean +done +IFS=$OLD_IFS #------- - -#Reconfigure -./configure -make distclean - -if [ $? -ne 0 ] ; then - echo "Something went wrong with distclean. Cannot continue" - exit 1 -fi - ./configure if [ $? -ne 0 ] ; then echo "Something went wrong with configure. Cannot continue" @@ -87,7 +87,7 @@ echo " WARNING: Program version not set to match between configure.ac. and ChangeLog">> $MSG_FILE fi -if [ x"`grep PROGRAM_VERSION src/basics.cpp | grep $VER`" == x"" ] ; then +if [ x"`grep PROGRAM_VERSION src/common/basics.cpp | grep $VER`" == x"" ] ; then echo " WARNING: Program version not set to match between configure.ac. and basics.cpp">> $MSG_FILE fi @@ -164,6 +164,16 @@ if [ x$SPAN_ELEMENT != x"" ] ; then echo "WARNING : Found \"span\" element in translation file - normally this is due to transifex incorrectly parsing translation files" >> $MSG_FILE fi + +#Run licensecheck over files, if available +if [ x`which licensecheck` != x"" ] ; then + LIC_CHECK_OUT=`licensecheck -r --ignore ".*\.(sh|sci|py|tex)$" | grep -v "GPL (v3 or later)" | grep -v "GENERATED FILE" ` + + if [ x$LIC_CHECK_OUT != x"" ] ; then + echo "WARNING:" $LIC_CHECK_OUT >> $MSG_FILE + fi +fi + #---- @@ -227,7 +237,7 @@ - for i in packaging docs m4 translations deps test + for i in packaging docs m4 translations deps test data do if [ -d $i/$i ] ; then mv $i/$i/* $i/ diff -Nru 3depict-0.0.12/packaging/mingw-debian-cross/bootstrap.sh 3depict-0.0.13/packaging/mingw-debian-cross/bootstrap.sh --- 3depict-0.0.12/packaging/mingw-debian-cross/bootstrap.sh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mingw-debian-cross/bootstrap.sh 2013-04-07 10:36:32.000000000 +0000 @@ -0,0 +1,988 @@ +#!/bin/bash + +#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" + exit 1 +fi + +PREFIX=/ +NUM_PROCS=4 + +IS_RELEASE=1 + +if [ `id -u` -eq 0 ]; then + echo "This script should not be run as root." + echo " If you know what you are doing, you can disable this check, but be aware you _can_ break your system by doing this." + exit 1; +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" +#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" + +#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. +# should be fixed for gettext > 0.18.1.1 ? +# 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" + +BUILD_STATUS_FILE="$BASE/build-status" +PATCH_STATUS_FILE="$BASE/patch-status" +PATCH_LEVEL=1 + +function isBuilt() +{ + if [ x`cat ${BUILD_STATUS_FILE} | grep $ISBUILT_ARG` != x"" ] ; then + ISBUILT=1 + else + ISBUILT=0 + fi +} + +function applyPatches() +{ + for i in $APPLY_PATCH_ARG + do + if [ x`cat $PATCH_STATUS_FILE | grep "$i"` != x"" ] ; then + echo "Patch already applied :" $i + continue + fi + + echo "Applying patch:" $i + patch -tN -p$PATCH_LEVEL < $BASE/patches/$i + + if [ $? -ne 0 ] ; then + echo "Failed applying patch :" $i + exit 1 + fi + echo "applied patch" + echo $i >> $PATCH_STATUS_FILE + done +} + +function install_mingw() +{ + echo "Requesting install of mingw :" $MINGW_PACKAGES + + #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 + 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 + fi + + mv *.orig.* *.debian.* *.dsc *.diff.* 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" + exit 1 + fi + fi + + tar -zxf libiconv-1.14.tar.gz || { echo "failed extracting iconv "; exit 1; } + + + popd 2> /dev/null + +} + +function createBaseBinaries() +{ + pushd bin >/dev/null + + #Create symlinks to the compiler, which will be in our + # primary path, and thus override the normal compiler + + #use ccache if it is around + if [ x`which ccache` != x"" ] ; then + echo -n "Enabling ccache support..." + USE_CCACHE=1 + else + echo -n "Making direct compiler symlinks..." + USE_CCACHE=0 + fi + + for i in g++ cpp gcc c++ + do + #Skip existing links + if [ -f ${HOST_VAL}-$i ] ; then + continue; + fi + + if [ $USE_CCACHE == 1 ] ; then + + ln -s `which ccache` ${HOST_VAL}-$i + else + + ln -s `which ${HOST_VAL}-$i` + + fi + + if [ $? -ne 0 ] ; then + echo "Failed when making compiler symlinks" + exit 1 + fi + done + + echo "done" + popd >/dev/null +} + +function fix_la_file +{ + #Need to fix .la files which have wrong path + # due to libtool not liking cross-compile + pushd lib/ >/dev/null + sed -i 's@//lib@'${BASE}/lib@ ${FIX_LA_FILE_ARG}*.la + sed -i 's@/lib/lib/@/lib/@' ${FIX_LA_FILE_ARG}*.la + popd >/dev/null +} + +function build_zlib() +{ + ISBUILT_ARG="zlib" + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + + pushd deps >/dev/null + pushd zlib-* >/dev/null + + + if [ $? -ne 0 ] ; then + echo "Zlib dir missing, or duplicated?" + exit 1 + fi + + make clean + rm -f configure.log + + + ./configure --prefix="/" || { echo "ZLib configure failed"; exit 1; } + + APPLY_PATCH_ARG="$PATCHES_ZLIB" + applyPatches + + make -j $NUM_PROCS || { echo "ZLib build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "ZLib install failed"; exit 1; } + + #Move the .so to a .dll + mv ${BASE}/lib/libz.so ${BASE}/lib/libz.dll + + #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_libpng() +{ + ISBUILT_ARG="libpng" + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd libpng-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "libpng dir missing, or duplicated?" + exit 1 + fi + + make clean + + ./configure --host=$HOST_VAL --enable-shared --disable-static || { echo "Libpng configure failed"; exit 1; } + + #Hack to strip linker version script + # eg as discussed : + # https://github.com/Pivosgroup/buildroot-linux/issues/2 + # The error is not 100% clear. if the build script has + # access to standard debian -I paths, then it goes away + # version script documentation is sparse to non-existant. + # the only really useful thing i've found is this: + # http://www.akkadia.org/drepper/dsohowto.pdf + sed -i 's/.*version-script.*//' Makefile Makefile.am + + make -j $NUM_PROCS || { echo "libpng build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "libpng install failed"; exit 1; } + + #The new libpng shoudl install (when it works, which it does not for us) + # the headers in a new subfolder, which is not compatible with most buildsystems + # so make some symlinks + #--- + # First simulate libpng's installer working (TODO: Why is this not working? It did before..) + mkdir -p ../../include/libpng12/ + cp -p png.h pngconf.h ../../include/libpng12/ + # Then actually make the symlinks + pushd ../../include/ > /dev/null + ln -s libpng12/pngconf.h + ln -s libpng12/png.h + popd >/dev/null + + #Aaand it doesn't install the libraries, so do that too. + cp -p .libs/*.dll $BASE/lib/ + cp -p .libs/*.la $BASE/lib/ + #---- + + + #Remove superseded libpng3 + rm ${BASE}/lib/libpng-3* + ln -s ${BASE}/lib/libpng12-0.dll ${BASE}/lib/libpng.dll + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libpng + fix_la_file + + echo "libpng" >> $BUILD_STATUS_FILE +} + +function build_libxml2() +{ + NAME="libxml2" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + + pushd deps >/dev/null + pushd libxml2-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "libxml2 dir missing, or duplicated?" + exit 1 + fi + make clean + + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "Libxml2 configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "libxml2 build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "libxml2 install failed"; exit 1; } + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libxml2 + fix_la_file + + #For compat, link libxml2/libxml to libxml/ + pushd include >/dev/null + ln -s libxml2/libxml libxml + popd >/dev/null + + #The dll gets installed into bin/, link it to lib/ + pushd lib > /dev/null + ln -s ../bin/libxml2-[0-9]*.dll + popd > /dev/null + + + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_libjpeg() +{ + NAME="libjpeg" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd libjpeg[0-9]*-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "libjpeg dir missing, or duplicated?" + exit 1 + fi + + make clean + + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "Libjpeg configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "libjpeg build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "libjpeg install failed"; exit 1; } + + #DLL needs to be copied into lib manually + cp -p .libs/${NAME}-[0-9]*.dll $BASE/lib/ + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libjpeg + fix_la_file + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_libtiff() +{ + NAME="libtiff" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd tiff[0-9]*-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "libtiff dir missing, or duplicated?" + exit 1 + fi + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "Libtiff configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "libtiff build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "libtiff install failed"; exit 1; } + + #DLL needs to be copied into lib manually + cp -p .libs/${NAME}-[0-9]*.dll $BASE/lib/ + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libtiff + fix_la_file + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_qhull() +{ + NAME="libqhull" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + + pushd deps >/dev/null + pushd qhull-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "qhull dir missing, or duplicated?" + exit 1 + fi + + make clean + + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "qhull configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "qhull build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "qhull install failed"; exit 1; } + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libqhull + fix_la_file + echo ${NAME} >> $BUILD_STATUS_FILE +} + + +function build_expat() +{ + NAME="libexpat" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd expat-** >/dev/null + + if [ $? -ne 0 ] ; then + echo "expat dir missing, or duplicated?" + exit 1 + fi + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "Libtiff configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "expat build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "expat install failed"; exit 1; } + + #DLL needs to be copied into lib manually + cp -p .libs/${NAME}-[0-9]*.dll $BASE/lib/ + + popd >/dev/null + popd >/dev/null + + + + FIX_LA_FILE_ARG=libexpat + fix_la_file + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_gsl() +{ + NAME="libgsl" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + + pushd deps >/dev/null + pushd gsl-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "gsl dir missing, or duplicated?" + exit 1 + fi + + make clean + + mkdir -p doc + echo "all:" > doc/Makefile.in + echo "install:" >> doc/Makefile.in + echo "clean:" >> doc/Makefile.in + + APPLY_PATCH_ARG=$PATCHES_GSL + applyPatches + + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "gsl configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "gsl build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "gsl install failed"; exit 1; } + + popd >/dev/null + popd >/dev/null + + + FIX_LA_FILE_ARG=libgsl + fix_la_file + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_wx() +{ + NAME="libwx" + ISBUILT_ARG=${NAME} + isBuilt + + if [ $ISBUILT -eq 1 ] ; then + return; + fi + + pushd deps >/dev/null + pushd wxwidgets[23].[0-9]-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "wxwidgets dir missing, or duplicated?" + exit 1 + fi + + make clean + + APPLY_PATCH_ARG=$PATCHES_WXWIDGETS_PRE + applyPatches + + ./configure --host=$HOST_VAL --enable-shared --disable-static --with-opengl --enable-unicode --without-regex --prefix=/ || { echo "wxwidgets configure failed"; exit 1; } + + #TODO: Where is this coming from ??? + for i in `find ./ -name Makefile | grep -v samples | grep -v wxPython` + do + sed -i "s@-luuid-L@ -luuid -L@" $i + done + + make -j $NUM_PROCS || { echo "wxwidgets build failed"; exit 1; } + make install DESTDIR="$BASE"|| { echo "wxwidgets install failed"; exit 1; } + + + + popd >/dev/null + popd >/dev/null + + pushd ./bin/ + unlink wx-config + ln -s `find ${BASE}/lib/wx/config/ -name \*release-2.8` wx-config + APPLY_PATCH_ARG=$PATCHES_WXWIDGETS_POST + PATCH_LEVEL=0 + applyPatches + PATCH_LEVEL=1 + popd + + pushd ./lib/ + ln -s wx-2.8/wx/ wx + popd + + sed -i "s@REPLACE_BASENAME@${BASE}@" wx-config + + echo ${NAME} >> $BUILD_STATUS_FILE + +} + +function build_freetype() +{ + NAME="libfreetype" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd freetype-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "freetype dir missing, or duplicated?" + exit 1 + fi + + tar -xjf freetype-[0-9]*bz2 || { echo "freetype decompress failed" ; exit 1; } + + pushd freetype-[0-9]* + make clean + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "freetype configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "freetype build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "freetype install failed"; exit 1; } + + popd >/dev/null + + popd >/dev/null + popd >/dev/null + + + FIX_LA_FILE_ARG=libfreetype + fix_la_file + + #freetype has moved headers. Add symlink for backwards compat + + pushd include >/dev/null + ln -s freetype2/freetype/ + popd >/dev/null + + echo ${NAME} >> $BUILD_STATUS_FILE +} + + +function build_libiconv() +{ + NAME="iconv" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + + pushd deps >/dev/null + pushd libiconv-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "libiconv dir missing, or duplicated?" + exit 1 + fi + + make clean + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "libiconv configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "libiconv build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "libiconv install failed"; exit 1; } + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libiconv + fix_la_file + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_gettext() +{ + NAME="gettext" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd gettext-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "gettext dir missing, or duplicated?" + exit 1 + fi + + make clean + + APPLY_PATCH_ARG=$PATCHES_GETTEXT + applyPatches + automake + + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "gettext configure failed"; exit 1; } + + make -j $NUM_PROCS || { echo "gettext build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "gettext install failed"; exit 1; } + + popd >/dev/null + popd >/dev/null + + FIX_LA_FILE_ARG=libintl + fix_la_file + FIX_LA_FILE_ARG=libcharset + fix_la_file + + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_mathgl() +{ + NAME="libmgl" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd mathgl-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "mathgl dir missing, or duplicated?" + exit 1 + fi + make clean + + libtoolize --copy --force + aclocal + + autoreconf + LIBS="${LIBS} -lz" ./configure --host=$HOST_VAL --disable-pthread --enable-shared --disable-static --prefix=/ || { echo "mathgl configure failed"; exit 1; } + + #RPATH disable hack + sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool + sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool + + #Hack to fix mathgl's libpng dll search + mkdir -p $BASE/lib/.libs/ + ln -s $BASE/lib/libpng.dll $BASE/lib/.libs/libpng.dll.a + + make -j $NUM_PROCS || { echo "mathgl build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "mathgl install failed"; exit 1; } + + #DLL needs to be copied into lib manually + cp -p .libs/${NAME}-[0-9]*.dll $BASE/lib/ + + popd >/dev/null + popd >/dev/null + FIX_LA_FILE_ARG=libmgl + fix_la_file + + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function build_ftgl() +{ + NAME="libftgl" + ISBUILT_ARG=${NAME} + isBuilt + if [ $ISBUILT -eq 1 ] ; then + return; + fi + pushd deps >/dev/null + pushd ftgl-* >/dev/null + + if [ $? -ne 0 ] ; then + echo "ftgl dir missing, or duplicated?" + exit 1 + fi + make clean + + + #rename GLU to glu32 and gl to opengl32 + sed -i s/'\-lGLU'/-lglu32/ configure + sed -i s/'\-lGL'/-lopengl32/ configure + +# APPLY_PATCH_ARG="$PATCHES_FTGL" +# applyPatches + + ./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "ftgl configure failed"; exit 1; } + + + make -j $NUM_PROCS || { echo "ftgl build failed"; exit 1; } + + make install DESTDIR="$BASE"|| { echo "ftgl install failed"; exit 1; } + + popd >/dev/null + popd >/dev/null + FIX_LA_FILE_ARG=libftgl + fix_la_file + + echo ${NAME} >> $BUILD_STATUS_FILE +} + +function createDirLayout() +{ + NEEDED_DIRS="bin lib include deps/packages" + for i in $NEEDED_DIRS + do + if [ ! -d $i ] ; then + mkdir -p $i; + fi + done +} + +function checkPatchesExist() +{ + echo -n "checking patches exist..." + if [ x"$PATCH_LIST" == x"" ] ; then + return; + fi + + if [ ! -d patches ] ; then + echo "Patch directory does not exist, but patches are needed" + echo "Need : " $PATCH_LIST + exit 1 + fi + + for i in $PATCH_LIST + do + if [ ! -f "patches/$i" ] ; then + echo "patches/$i" does not exist + exit 1; + fi + done + echo "done" +} + +#Ensure we are running under a whitelisted host +function checkHost() +{ + echo -n "Host checks... " + if [ x`which uname` == x"" ] ; then + echo "Uname missing... Shouldn't be... Can't determine arch - bailing out." + exit 1 + fi + + if [ x`uname -s` != x"Linux" ] ; then + echo "This is only meant to run under linux.. and probably only debian-like systems." + exit 1 + fi + + + HOSTTYPE=`uname -m` + + if [ x"$HOSTTYPE" != x"x86_64" ] ; then + echo "This only works on x86_64 builder machines - you'll need to modify the script to handle other arches. Sorry." + exit 1 + fi + + BINARIES_NEEDED="apt-get sudo patch grep sed awk" + + for i in $BINARIES_NEEDED + do + if [ x`which $i` == x"" ] ; then + echo "Missing binary : $i - aborting" + exit 1 + fi + done + + if [ x`which lsb_release` != x"" ] ; then + + 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." + fi + fi + + echo "done" +} + +#Build the nsis package +function make_package() +{ + pushd ./code/3Depict 2> /dev/null + + NSI_FILE=./packaging/windows-installer/windows-installer.nsi + if [ ! -f $NSI_FILE ] ; then + echo "NSI file missing whilst trying to build package" + exit 1; + fi + + #copy as needed + # 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 . + fi + + + echo -n " Copying dll files... " + DLL_FILES=`grep File windows-installer.nsi | egrep '(\.dll|\.so)' | sed 's/.*src.//' | sed 's/\"//' | sed 's/\r/ /g'` + + SYS_DIR=/usr/lib/gcc/${HOST_VAL}/ + #copy the DLL files from system or + # from the build locations + for i in ${DLL_FILES} + do + HAVE_DLL=0 + for j in ${BASE}/lib/ ${BASE}/bin/ $SYS_DIR + do + FIND_RES=`find $j -name $i | head -n 1` + if [ x$FIND_RES != x"" ] ; then + HAVE_DLL=1; + cp $FIND_RES ./src/ + break; + fi + done + + if [ $HAVE_DLL -eq 0 ] ; then + echo "Couldnt find DLL :" + echo " $i " + echo " looked in ${BASE}/lib/ and $SYS_DIR" + exit 1; + fi + done + echo "done." + + + if [ $IS_RELEASE -ne 0 ] ; then + pushd src/ 2> /dev/null + strip *.dll *.exe + popd 2> /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 + fi +} + +#Check that we have a suitable host system +checkHost + +#Check we have the patches we need +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} + + x86_64-w64-mingw32) + MINGW_PACKAGES="gcc-mingw32" + ;; + HOST_VAL=i686-w64-mingw32) + MINGW_PACKAGES="mingw-w64-x86-64-dev g++-mingw-w64-x86-64" + ;; + *) + echo "Unknown host... please install deps manually,or alter script" + return + ;; +esac + +install_mingw + +#set our needed environment variables +PATH=${BASE}/bin/:/usr/$HOST_VAL/bin/:$PATH +export CXX=${HOST_VAL}-g++ +export CPP=${HOST_VAL}-cpp +export CC=${HOST_VAL}-gcc +export CPPFLAGS=-I${BASE}/include/ +export CFLAGS=-I${BASE}/include/ +export CXXFLAGS=-I${BASE}/include/ +export LDFLAGS=-L${BASE}/lib/ +export RANLIB=${HOST_VAL}-ranlib +export LIBS="-L${BASE}/lib/" +DESTDIR=${BASE} + +build_zlib +build_libtiff +build_libpng +build_libjpeg +build_libxml2 +build_gsl +build_qhull +build_expat +build_wx # I'm not sure I've done this 100% right. Check wx-config output +build_freetype +build_libiconv +build_gettext +build_mathgl +build_ftgl + + + +make_package + diff -Nru 3depict-0.0.12/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype 3depict-0.0.13/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype --- 3depict-0.0.12/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype 2013-04-07 10:37:05.000000000 +0000 @@ -0,0 +1,77 @@ +--- 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 +@@ -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 + builtin and then its argument prototype would still apply. */ +- +-#include ++#ifdef __cplusplus ++extern "C" ++#endif ++char glBegin (); + int + main () + { +-glBegin (GL_LINES); ++return glBegin (); ++ ; + return 0; + } + _ACEOF +@@ -22591,12 +22594,15 @@ + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +- +-#include ++#ifdef __cplusplus ++extern "C" ++#endif ++char glBegin (); + int + main () + { +-glBegin (GL_LINES); ++return glBegin (); ++ ; + return 0; + } + _ACEOF +@@ -23005,12 +23011,15 @@ + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +- +-#include ++#ifdef __cplusplus ++extern "C" ++#endif ++char gluNewTess (); + int + main () + { +- GLUquadricObj *p=gluNewQuadric(); ++return gluNewTess (); ++ ; + return 0; + } + _ACEOF +@@ -23055,11 +23064,15 @@ + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +-#include ++#ifdef __cplusplus ++extern "C" ++#endif ++char gluNewTess (); + int + main () + { +- GLUquadricObj *p=gluNewQuadric(); ++return gluNewTess (); ++ ; + return 0; + } + _ACEOF diff -Nru 3depict-0.0.12/packaging/mingw-debian-cross/patches/gsl-config.patch 3depict-0.0.13/packaging/mingw-debian-cross/patches/gsl-config.patch --- 3depict-0.0.12/packaging/mingw-debian-cross/patches/gsl-config.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mingw-debian-cross/patches/gsl-config.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,36 @@ +--- gsl-config 2013-02-23 12:01:38.000000000 +0100 ++++ /usr/bin/gsl-config 2011-05-08 15:12:21.000000000 +0200 +@@ -1,9 +1,8 @@ + #! /bin/sh + +-BASEDIR=/home/pcuser/mingw64-cross +-prefix=/ +-exec_prefix=/ +-includedir=$BASEDIR/include ++prefix=/usr ++exec_prefix=/usr ++includedir=/usr/include + + usage() + { +@@ -59,16 +58,16 @@ + ;; + + --cflags) +- echo -I/$BASEDIR/include ++ echo -I/usr/include + ;; + + --libs) + : ${GSL_CBLAS_LIB=-lgslcblas} +- echo -L/$BASEDIR/lib -lgsl $GSL_CBLAS_LIB -lm ++ echo -L/usr/lib -lgsl $GSL_CBLAS_LIB -lm + ;; + + --libs-without-cblas) +- echo -L/$BASEDIR/lib -lgsl -lm ++ echo -L/usr/lib -lgsl -lm + ;; + *) + usage + diff -Nru 3depict-0.0.12/packaging/mingw-debian-cross/patches/wx-config-sysroot.patch 3depict-0.0.13/packaging/mingw-debian-cross/patches/wx-config-sysroot.patch --- 3depict-0.0.12/packaging/mingw-debian-cross/patches/wx-config-sysroot.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mingw-debian-cross/patches/wx-config-sysroot.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,19 @@ +--- wx-config 2013-02-23 15:56:01.000000000 +0100 ++++ ./wx-config-fixed 2013-02-23 15:08:17.000000000 +0100 +@@ -900,12 +900,13 @@ + # 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/ + prefix=${this_prefix-$prefix} + exec_prefix=${this_exec_prefix-$exec_prefix} + +-includedir="${prefix}/include" +-libdir="${exec_prefix}/lib" +-bindir="${exec_prefix}/bin" ++includedir="${sysroot}${prefix}/include" ++libdir="${sysroot}${exec_prefix}/lib" ++bindir="${sysroot}${exec_prefix}/bin" + + # Trivial queries we can answer now. + [ -z "$output_option_prefix" ] || echo $prefix diff -Nru 3depict-0.0.12/packaging/mingw-debian-cross/patches/wxWidgets-2.8.12-mingw64-1.patch 3depict-0.0.13/packaging/mingw-debian-cross/patches/wxWidgets-2.8.12-mingw64-1.patch --- 3depict-0.0.12/packaging/mingw-debian-cross/patches/wxWidgets-2.8.12-mingw64-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mingw-debian-cross/patches/wxWidgets-2.8.12-mingw64-1.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,559 @@ +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/configure wxWidgets-2.8.12.patched/configure +--- wxWidgets-2.8.12/configure 2011-03-22 19:59:37 +0800 ++++ wxWidgets-2.8.12.patched/configure 2011-04-07 11:33:02 +0800 +@@ -27805,10 +27805,10 @@ + + case "${host}" in + x86_64-*-mingw32* ) +- LIBS="$LIBS -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -lwctl3d32 -ladvapi32 -lwsock32 -lgdi32" ++ LIBS="$LIBS -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -ladvapi32 -lws2_32 -lgdi32" + ;; + * ) +- LIBS="$LIBS -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -lctl3d32 -ladvapi32 -lwsock32 -lgdi32" ++ LIBS="$LIBS -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -ladvapi32 -lws2_32 -lgdi32" + ;; + esac + if test "$wxUSE_ACCESSIBILITY" = "yes" ; then +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/include/wx/msw/menuitem.h wxWidgets-2.8.12.patched/include/wx/msw/menuitem.h +--- wxWidgets-2.8.12/include/wx/msw/menuitem.h 2011-03-22 20:00:56 +0800 ++++ wxWidgets-2.8.12.patched/include/wx/msw/menuitem.h 2011-04-07 12:35:30 +0800 +@@ -54,7 +54,7 @@ + // the id for a popup menu is really its menu handle (as required by + // ::AppendMenu() API), so this function will return either the id or the + // menu handle depending on what we're +- int GetRealId() const; ++ WXWPARAM GetRealId() const; + + // mark item as belonging to the given radio group + void SetAsRadioGroupStart(); +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/aui/framemanager.cpp wxWidgets-2.8.12.patched/src/aui/framemanager.cpp +--- wxWidgets-2.8.12/src/aui/framemanager.cpp 2011-03-22 19:59:45 +0800 ++++ wxWidgets-2.8.12.patched/src/aui/framemanager.cpp 2011-04-07 11:43:23 +0800 +@@ -974,7 +974,7 @@ + if (pinfo.name.empty() || already_exists) + { + pinfo.name.Printf(wxT("%08lx%08x%08x%08lx"), +- ((unsigned long)pinfo.window) & 0xffffffff, ++ ((unsigned long)(intptr_t)pinfo.window) & 0xffffffff, + (unsigned int)time(NULL), + #ifdef __WXWINCE__ + (unsigned int)GetTickCount(), +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/common/debugrpt.cpp wxWidgets-2.8.12.patched/src/common/debugrpt.cpp +--- wxWidgets-2.8.12/src/common/debugrpt.cpp 2011-03-22 19:59:40 +0800 ++++ wxWidgets-2.8.12.patched/src/common/debugrpt.cpp 2011-04-07 11:43:57 +0800 +@@ -54,6 +54,8 @@ + #include "wx/zipstrm.h" + #endif // wxUSE_ZIPSTREAM + ++#include ++ + WX_CHECK_BUILD_OPTIONS("wxQA") + + // ---------------------------------------------------------------------------- +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/common/filefn.cpp wxWidgets-2.8.12.patched/src/common/filefn.cpp +--- wxWidgets-2.8.12/src/common/filefn.cpp 2011-03-22 19:59:41 +0800 ++++ wxWidgets-2.8.12.patched/src/common/filefn.cpp 2011-04-07 11:44:23 +0800 +@@ -70,6 +70,8 @@ + #endif + #endif // __GNUWIN32__ + ++ #include ++ + // io.h is needed for _get_osfhandle() + // Already included by filefn.h for many Windows compilers + #if defined __MWERKS__ || defined __CYGWIN__ +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/common/utilscmn.cpp wxWidgets-2.8.12.patched/src/common/utilscmn.cpp +--- wxWidgets-2.8.12/src/common/utilscmn.cpp 2011-03-22 19:59:42 +0800 ++++ wxWidgets-2.8.12.patched/src/common/utilscmn.cpp 2011-04-07 13:34:01 +0800 +@@ -822,7 +822,7 @@ + //hInstApp member is only valid if the function fails, in which case it + //receives one of the following error values, which are less than or + //equal to 32. +- const int nResult = (int) sei.hInstApp; ++ const intptr_t nResult = (intptr_t)sei.hInstApp; + + // Firefox returns file not found for some reason, so make an exception + // for it +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/dcprint.cpp wxWidgets-2.8.12.patched/src/msw/dcprint.cpp +--- wxWidgets-2.8.12/src/msw/dcprint.cpp 2011-03-22 20:00:53 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/dcprint.cpp 2011-04-07 12:01:29 +0800 +@@ -319,7 +319,7 @@ + } + + +- HGLOBAL hDevMode = (HGLOBAL)(DWORD) data->GetDevMode(); ++ HGLOBAL hDevMode = (HGLOBAL) data->GetDevMode(); + + DEVMODE *lpDevMode = hDevMode ? (DEVMODE *)::GlobalLock(hDevMode) : NULL; + +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/frame.cpp wxWidgets-2.8.12.patched/src/msw/frame.cpp +--- wxWidgets-2.8.12/src/msw/frame.cpp 2011-03-22 20:00:53 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/frame.cpp 2011-04-07 12:11:13 +0800 +@@ -855,7 +855,7 @@ + HDC hdc = ::BeginPaint(GetHwnd(), &ps); + + // Erase background before painting or we get white background +- MSWDefWindowProc(WM_ICONERASEBKGND, (WORD)(LONG)ps.hdc, 0L); ++ MSWDefWindowProc(WM_ICONERASEBKGND, (intptr_t)ps.hdc, 0L); + + if ( hIcon ) + { +@@ -1085,7 +1085,7 @@ + const wxIcon& icon = GetIcon(); + HICON hIcon = icon.Ok() ? GetHiconOf(icon) + : (HICON)GetDefaultIcon(); +- rc = (long)hIcon; ++ rc = (intptr_t)hIcon; // WXLRESULT is int64 in win64 + processed = rc != 0; + } + break; +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/helpwin.cpp wxWidgets-2.8.12.patched/src/msw/helpwin.cpp +--- wxWidgets-2.8.12/src/msw/helpwin.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/helpwin.cpp 2011-04-07 12:15:22 +0800 +@@ -98,7 +98,7 @@ + + wxString str = GetValidFilename(m_helpFile); + +- return (WinHelp(GetSuitableHWND(this), (const wxChar*) str, HELP_PARTIALKEY, (DWORD)(const wxChar*) k) != 0); ++ return (WinHelp(GetSuitableHWND(this), (const wxChar*) str, HELP_PARTIALKEY, (intptr_t)(const wxChar*) k) != 0); + } + + // Can't close the help window explicitly in WinHelp +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/mdi.cpp wxWidgets-2.8.12.patched/src/msw/mdi.cpp +--- wxWidgets-2.8.12/src/msw/mdi.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/mdi.cpp 2011-04-07 12:22:05 +0800 +@@ -763,7 +763,7 @@ + wxWindowCreationHook hook(this); + + m_hWnd = (WXHWND)::SendMessage(GetWinHwnd(parent->GetClientWindow()), +- WM_MDICREATE, 0, (LONG)(LPSTR)&mcs); ++ WM_MDICREATE, 0, (intptr_t)&mcs); + + if ( !m_hWnd ) + { +@@ -1433,14 +1433,14 @@ + { + success = true; + ::InsertMenu(hmenu, i, MF_BYPOSITION | MF_POPUP | MF_STRING, +- (UINT)subMenu, _("&Window")); ++ (intptr_t)subMenu, _("&Window")); + break; + } + } + + if ( !success ) + { +- ::AppendMenu(hmenu, MF_POPUP, (UINT)subMenu, _("&Window")); ++ ::AppendMenu(hmenu, MF_POPUP, (intptr_t)subMenu, _("&Window")); + } + } + +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/menu.cpp wxWidgets-2.8.12.patched/src/msw/menu.cpp +--- wxWidgets-2.8.12/src/msw/menu.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/menu.cpp 2011-04-07 13:37:06 +0800 +@@ -370,19 +370,19 @@ + + // id is the numeric id for normal menu items and HMENU for submenus as + // required by ::AppendMenu() API +- UINT id; ++ UINT_PTR id; + wxMenu *submenu = pItem->GetSubMenu(); + if ( submenu != NULL ) { + wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); + + submenu->SetParent(this); + +- id = (UINT)submenu->GetHMenu(); ++ id = (intptr_t)submenu->GetHMenu(); + + flags |= MF_POPUP; + } + else { +- id = pItem->GetId(); ++ id = pItem->GetRealId(); + } + + +@@ -963,7 +963,7 @@ + for ( i = 0, it = m_menus.begin(); i < count; i++, it++ ) + { + if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, +- (UINT)(*it)->GetHMenu(), ++ (intptr_t)(*it)->GetHMenu(), + m_titles[i]) ) + { + wxLogLastError(wxT("AppendMenu")); +@@ -1035,7 +1035,7 @@ + + int mswpos = MSWPositionForWxMenu(GetMenu(pos),pos); + +- UINT id; ++ UINT_PTR id; + UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, mswpos, MF_BYPOSITION); + if ( flagsOld == 0xFFFFFFFF ) + { +@@ -1048,7 +1048,7 @@ + { + // HIBYTE contains the number of items in the submenu in this case + flagsOld &= 0xff; +- id = (UINT)::GetSubMenu((HMENU)m_hMenu, mswpos); ++ id = (intptr_t)::GetSubMenu((HMENU)m_hMenu, mswpos); + } + else + { +@@ -1124,7 +1124,7 @@ + + if ( !::InsertMenu(GetHmenu(), (UINT)mswpos, + MF_BYPOSITION | MF_POPUP | MF_STRING, +- (UINT)GetHmenuOf(menu), title) ) ++ (intptr_t)GetHmenuOf(menu), title) ) + { + wxLogLastError(wxT("InsertMenu")); + } +@@ -1191,7 +1191,7 @@ + #else + if ( !::InsertMenu(GetHmenu(), mswpos, + MF_BYPOSITION | MF_POPUP | MF_STRING, +- (UINT)GetHmenuOf(menu), title) ) ++ (intptr_t)GetHmenuOf(menu), title) ) + { + wxLogLastError(wxT("InsertMenu")); + } +@@ -1250,7 +1250,7 @@ + } + #else + if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, +- (UINT)submenu, title) ) ++ (intptr_t)submenu, title) ) + { + wxLogLastError(wxT("AppendMenu")); + } +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/menuitem.cpp wxWidgets-2.8.12.patched/src/msw/menuitem.cpp +--- wxWidgets-2.8.12/src/msw/menuitem.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/menuitem.cpp 2011-04-07 12:37:02 +0800 +@@ -186,9 +186,14 @@ + // ---- + + // return the id for calling Win32 API functions +-int wxMenuItem::GetRealId() const ++WXWPARAM wxMenuItem::GetRealId() const + { +- return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId(); ++ // we must use ids in unsigned short range with Windows functions, if we ++ // pass ids > USHRT_MAX to them they get very confused (e.g. start ++ // generating WM_COMMAND messages with negative high word of wParam), so ++ // use the cast to ensure the id is in range ++ return m_subMenu ? (intptr_t)m_subMenu->GetHMenu() ++ : static_cast(GetId()); + } + + // get item state +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/pen.cpp wxWidgets-2.8.12.patched/src/msw/pen.cpp +--- wxWidgets-2.8.12/src/msw/pen.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/pen.cpp 2011-04-07 12:47:35 +0800 +@@ -172,9 +172,9 @@ + case wxSTIPPLE: + logb.lbStyle = BS_PATTERN ; + if (M_PENDATA->m_stipple.Ok()) +- logb.lbHatch = (LONG)M_PENDATA->m_stipple.GetHBITMAP(); ++ logb.lbHatch = (intptr_t)M_PENDATA->m_stipple.GetHBITMAP(); + else +- logb.lbHatch = (LONG)0; ++ logb.lbHatch = (intptr_t)0; + break; + case wxBDIAGONAL_HATCH: + logb.lbStyle = BS_HATCHED; +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/printdlg.cpp wxWidgets-2.8.12.patched/src/msw/printdlg.cpp +--- wxWidgets-2.8.12/src/msw/printdlg.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/printdlg.cpp 2011-04-07 12:51:01 +0800 +@@ -175,10 +175,10 @@ + + wxWindowsPrintNativeData::~wxWindowsPrintNativeData() + { +- HGLOBAL hDevMode = (HGLOBAL)(DWORD) m_devMode; ++ HGLOBAL hDevMode = (HGLOBAL) m_devMode; + if ( hDevMode ) + GlobalFree(hDevMode); +- HGLOBAL hDevNames = (HGLOBAL)(DWORD) m_devNames; ++ HGLOBAL hDevNames = (HGLOBAL) m_devNames; + if ( hDevNames ) + GlobalFree(hDevNames); + } +@@ -190,8 +190,8 @@ + + bool wxWindowsPrintNativeData::TransferTo( wxPrintData &data ) + { +- HGLOBAL hDevMode = (HGLOBAL)(DWORD) m_devMode; +- HGLOBAL hDevNames = (HGLOBAL)(DWORD) m_devNames; ++ HGLOBAL hDevMode = (HGLOBAL) m_devMode; ++ HGLOBAL hDevNames = (HGLOBAL) m_devNames; + + if (!hDevMode) + { +@@ -396,8 +396,8 @@ + + bool wxWindowsPrintNativeData::TransferFrom( const wxPrintData &data ) + { +- HGLOBAL hDevMode = (HGLOBAL)(DWORD) m_devMode; +- HGLOBAL hDevNames = (HGLOBAL)(DWORD) m_devNames; ++ HGLOBAL hDevMode = (HGLOBAL) m_devMode; ++ HGLOBAL hDevNames = (HGLOBAL) m_devNames; + WinPrinter printer; + LPTSTR szPrinterName = (LPTSTR)data.GetPrinterName().wx_str(); + +@@ -493,7 +493,7 @@ + else + { + hDevMode = pd.hDevMode; +- m_devMode = (void*)(long) hDevMode; ++ m_devMode = (void*)(intptr_t) hDevMode; + pd.hDevMode = NULL; + + // We'll create a new DEVNAMEs structure below. +@@ -502,7 +502,7 @@ + pd.hDevNames = NULL; + + // hDevNames = pd->hDevNames; +- // m_devNames = (void*)(long) hDevNames; ++ // m_devNames = (void*)(intptr_t) hDevNames; + // pd->hDevnames = NULL; + + } +@@ -688,7 +688,7 @@ + } + + // TODO: I hope it's OK to pass some empty strings to DEVNAMES. +- m_devNames = (void*) (long) wxCreateDevNames(wxEmptyString, data.GetPrinterName(), wxEmptyString); ++ m_devNames = (void*) (intptr_t) wxCreateDevNames(wxEmptyString, data.GetPrinterName(), wxEmptyString); + + return true; + } +@@ -820,13 +820,13 @@ + if (pd->hDevNames) + GlobalFree(pd->hDevNames); + +- pd->hDevMode = (HGLOBAL)(DWORD) native_data->GetDevMode(); ++ pd->hDevMode = (HGLOBAL) native_data->GetDevMode(); + native_data->SetDevMode( (void*) NULL); + + // Shouldn't assert; we should be able to test Ok-ness at a higher level + //wxASSERT_MSG( (pd->hDevMode), wxT("hDevMode must be non-NULL in ConvertToNative!")); + +- pd->hDevNames = (HGLOBAL)(DWORD) native_data->GetDevNames(); ++ pd->hDevNames = (HGLOBAL) native_data->GetDevNames(); + native_data->SetDevNames( (void*) NULL); + + +@@ -897,9 +897,9 @@ + if (native_data->GetDevMode()) + { + // Make sure we don't leak memory +- GlobalFree( (HGLOBAL)(DWORD) native_data->GetDevMode() ); ++ GlobalFree( (HGLOBAL) native_data->GetDevMode() ); + } +- native_data->SetDevMode( (void*)(long) pd->hDevMode ); ++ native_data->SetDevMode( (void*)(intptr_t) pd->hDevMode ); + pd->hDevMode = NULL; + } + +@@ -909,9 +909,9 @@ + if (native_data->GetDevNames()) + { + // Make sure we don't leak memory +- GlobalFree((HGLOBAL)(DWORD) native_data->GetDevNames()); ++ GlobalFree((HGLOBAL) native_data->GetDevNames()); + } +- native_data->SetDevNames((void*)(long) pd->hDevNames); ++ native_data->SetDevNames((void*)(intptr_t) pd->hDevNames); + pd->hDevNames = NULL; + } + +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/tbar95.cpp wxWidgets-2.8.12.patched/src/msw/tbar95.cpp +--- wxWidgets-2.8.12/src/msw/tbar95.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/tbar95.cpp 2011-04-07 12:53:09 +0800 +@@ -802,8 +802,8 @@ + TBREPLACEBITMAP replaceBitmap; + replaceBitmap.hInstOld = NULL; + replaceBitmap.hInstNew = NULL; +- replaceBitmap.nIDOld = (UINT) oldToolBarBitmap; +- replaceBitmap.nIDNew = (UINT) hBitmap; ++ replaceBitmap.nIDOld = (intptr_t) oldToolBarBitmap; ++ replaceBitmap.nIDNew = (intptr_t) hBitmap; + replaceBitmap.nButtons = nButtons; + if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP, + 0, (LPARAM) &replaceBitmap) ) +@@ -832,7 +832,7 @@ + { + TBADDBITMAP addBitmap; + addBitmap.hInst = 0; +- addBitmap.nID = (UINT) hBitmap; ++ addBitmap.nID = (intptr_t) hBitmap; + if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP, + (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 ) + { +@@ -912,7 +912,7 @@ + { + const wxString& label = tool->GetLabel(); + if ( !label.empty() ) +- button.iString = (int)label.c_str(); ++ button.iString = (intptr_t)label.c_str(); + } + + button.idCommand = tool->GetId(); +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/textctrl.cpp wxWidgets-2.8.12.patched/src/msw/textctrl.cpp +--- wxWidgets-2.8.12/src/msw/textctrl.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/textctrl.cpp 2011-04-07 12:54:27 +0800 +@@ -960,7 +960,7 @@ + // finally, stream it in the control + EDITSTREAM eds; + wxZeroMemory(eds); +- eds.dwCookie = (DWORD)&wpc; ++ eds.dwCookie = (intptr_t)&wpc; + // the cast below is needed for broken (very) old mingw32 headers + eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn; + +@@ -1013,7 +1013,7 @@ + + EDITSTREAM eds; + wxZeroMemory(eds); +- eds.dwCookie = (DWORD)&data; ++ eds.dwCookie = (intptr_t)&data; + eds.pfnCallback = wxRichEditStreamOut; + + ::SendMessage +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/thread.cpp wxWidgets-2.8.12.patched/src/msw/thread.cpp +--- wxWidgets-2.8.12/src/msw/thread.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/thread.cpp 2011-04-07 13:32:55 +0800 +@@ -522,7 +522,7 @@ + return (THREAD_RETVAL)-1; + } + +- rc = (THREAD_RETVAL)thread->Entry(); ++ rc = (THREAD_RETVAL)(intptr_t)thread->Entry(); + } + wxCATCH_ALL( wxTheApp->OnUnhandledException(); ) + +@@ -842,7 +842,7 @@ + break; + } + +- if ( (DWORD)rc != STILL_ACTIVE ) ++ if ( (intptr_t)rc != STILL_ACTIVE ) + break; + + // give the other thread some time to terminate, otherwise we may be +@@ -1000,7 +1000,7 @@ + // could we set all bits? + if ( level != 0 ) + { +- wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level); ++ wxLogDebug(_T("bad level %Iu in wxThread::SetConcurrency()"), level); + + return false; + } +@@ -1162,7 +1162,7 @@ + } + + #ifdef wxUSE_BEGIN_THREAD +- _endthreadex((unsigned)status); ++ _endthreadex((unsigned)(intptr_t)status); + #else // !VC++ + ::ExitThread((DWORD)status); + #endif // VC++/!VC++ +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/tooltip.cpp wxWidgets-2.8.12.patched/src/msw/tooltip.cpp +--- wxWidgets-2.8.12/src/msw/tooltip.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/tooltip.cpp 2011-04-07 13:12:26 +0800 +@@ -106,7 +106,7 @@ + uFlags |= TTF_TRANSPARENT; + } + +- uId = (UINT)hwndOwner; ++ uId = (intptr_t)hwndOwner; + } + }; + +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/toplevel.cpp wxWidgets-2.8.12.patched/src/msw/toplevel.cpp +--- wxWidgets-2.8.12/src/msw/toplevel.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/toplevel.cpp 2011-04-07 13:13:54 +0800 +@@ -1122,7 +1122,7 @@ + { + // restore focus to the child which was last focused unless we already + // have it +- wxLogTrace(_T("focus"), _T("wxTLW %08x activated."), (int) m_hWnd); ++ wxLogTrace(_T("focus"), _T("wxTLW %p activated."), (intptr_t) m_hWnd); + + wxWindow *winFocus = FindFocus(); + if ( !winFocus || wxGetTopLevelParent(winFocus) != this ) +@@ -1157,9 +1157,9 @@ + } + + wxLogTrace(_T("focus"), +- _T("wxTLW %08x deactivated, last focused: %08x."), +- (int) m_hWnd, +- (int) (m_winLastFocused ? GetHwndOf(m_winLastFocused) ++ _T("wxTLW %p deactivated, last focused: %p."), ++ (intptr_t) m_hWnd, ++ (intptr_t) (m_winLastFocused ? GetHwndOf(m_winLastFocused) + : NULL)); + + event.Skip(); +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/utils.cpp wxWidgets-2.8.12.patched/src/msw/utils.cpp +--- wxWidgets-2.8.12/src/msw/utils.cpp 2011-03-22 20:00:54 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/utils.cpp 2011-04-07 13:14:32 +0800 +@@ -713,7 +713,7 @@ + return -1; + } + +- wxON_BLOCK_EXIT1(::CloseHandle, hProcess); ++ wxON_BLOCK_EXIT1((WINBOOL (*)(void *))::CloseHandle, hProcess); + + bool ok = true; + switch ( sig ) +diff --strip-trailing-cr -Nur wxWidgets-2.8.12/src/msw/window.cpp wxWidgets-2.8.12.patched/src/msw/window.cpp +--- wxWidgets-2.8.12/src/msw/window.cpp 2011-03-22 20:00:55 +0800 ++++ wxWidgets-2.8.12.patched/src/msw/window.cpp 2011-04-07 13:17:11 +0800 +@@ -2596,8 +2596,8 @@ + // trace all messages - useful for the debugging + #ifdef __WXDEBUG__ + wxLogTrace(wxTraceMessages, +- wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"), +- wxGetMessageName(message), (long)hWnd, (long)wParam, lParam); ++ wxT("Processing %s(hWnd=%Ix, wParam=%Ix, lParam=%Ix)"), ++ wxGetMessageName(message), (intptr_t)hWnd, (intptr_t)wParam, (intptr_t)lParam); + #endif // __WXDEBUG__ + + wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd); +@@ -3438,7 +3438,7 @@ + + wxWindow *wxFindWinFromHandle(WXHWND hWnd) + { +- return (wxWindow*)wxWinHandleHash->Get((long)hWnd); ++ return (wxWindow*)wxWinHandleHash->Get((intptr_t)hWnd); + } + + void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win) +@@ -3452,20 +3452,20 @@ + #ifdef __WXDEBUG__ + if ( oldWin && (oldWin != win) ) + { +- wxLogDebug(wxT("HWND %X already associated with another window (%s)"), +- (int) hWnd, win->GetClassInfo()->GetClassName()); ++ wxLogDebug(wxT("HWND %IX already associated with another window (%s)"), ++ (intptr_t) hWnd, win->GetClassInfo()->GetClassName()); + } + else + #endif // __WXDEBUG__ + if (!oldWin) + { +- wxWinHandleHash->Put((long)hWnd, (wxWindow *)win); ++ wxWinHandleHash->Put((intptr_t)hWnd, (wxWindow *)win); + } + } + + void wxRemoveHandleAssociation(wxWindowMSW *win) + { +- wxWinHandleHash->Delete((long)win->GetHWND()); ++ wxWinHandleHash->Delete((intptr_t)win->GetHWND()); + } + + // ---------------------------------------------------------------------------- diff -Nru 3depict-0.0.12/packaging/mingw-debian-cross/patches/zlib-no-lc.patch 3depict-0.0.13/packaging/mingw-debian-cross/patches/zlib-no-lc.patch --- 3depict-0.0.12/packaging/mingw-debian-cross/patches/zlib-no-lc.patch 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/packaging/mingw-debian-cross/patches/zlib-no-lc.patch 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,13 @@ +diff -r 5cc2e4c24bef Makefile +--- a/Makefile Sat Feb 23 00:14:40 2013 +0100 ++++ b/Makefile Sat Feb 23 00:15:49 2013 +0100 +@@ -40,7 +40,7 @@ + ARFLAGS=rc + RANLIB=x86_64-w64-mingw32-ranlib + LDCONFIG=ldconfig +-LDSHAREDLIBC=-lc ++LDSHAREDLIBC= + TAR=tar + SHELL=/bin/sh + EXE= + diff -Nru 3depict-0.0.12/packaging/windows-installer/windows-installer.nsi 3depict-0.0.13/packaging/windows-installer/windows-installer.nsi --- 3depict-0.0.12/packaging/windows-installer/windows-installer.nsi 2012-11-11 20:09:30.000000000 +0000 +++ 3depict-0.0.13/packaging/windows-installer/windows-installer.nsi 2013-03-24 16:46:52.000000000 +0000 @@ -2,7 +2,7 @@ ; HM NIS Edit Wizard helper defines !define PRODUCT_NAME "3Depict" -!define PRODUCT_VERSION "0.0.12" +!define PRODUCT_VERSION "0.0.13" !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" @@ -62,10 +62,16 @@ File "src\libgslcblas-0.dll" File "src\libgsl-0.dll" File "src\libfreetype-6.dll" - File "src\pthreadGC2.dll" - File "src\libgomp-1.dll" File "src\libintl-8.dll" File "src\libiconv-2.dll" + File "src\libexpat-1.dll" + File "src\libjpeg-8.dll" + File "src\libpng12-0.dll" + File "src\libtiff-4.dll" + File "src\libz.so.1.2.7" + File "src\libstdc++-6.dll" + File "src\libmgl-5.dll" + File "src\libgcc_s_sjlj-1.dll" File "docs\manual-latex\manual.pdf" CreateDirectory "$SMPROGRAMS\3Depict" @@ -81,19 +87,19 @@ File /r locales\*.* SetOutPath "$INSTDIR\textures\" - File "src\textures\enlarge.png" - File "src\textures\keyboard-alt.png" - File "src\textures\keyboard-command.png" - File "src\textures\keyboard-ctrl.png" - File "src\textures\keyboard-shift.png" - File "src\textures\keyboard-tab.png" - File "src\textures\Left-Right-arrow.png" - File "src\textures\Left_clicked_mouse.png" - File "src\textures\middle_clicked_mouse.png" - File "src\textures\Right-arrow.png" - File "src\textures\Right_clicked_mouse.png" - File "src\textures\rotateArrow.png" - File "src\textures\scroll_wheel_mouse.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-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\Right_clicked_mouse.png" + File "data\textures\rotateArrow.png" + File "data\textures\scroll_wheel_mouse.png" SectionEnd Section -AdditionalIcons @@ -160,10 +166,16 @@ Delete "$INSTDIR\libgslcblas-0.dll" Delete "$INSTDIR\libgsl-0.dll" Delete "$INSTDIR\libfreetype-6.dll" - Delete "$INSTDIR\pthreadGC2.dll" - Delete "$INSTDIR\libgomp-1.dll" Delete "$INSTDIR\libintl-8.dll" Delete "$INSTDIR\libiconv-2.dll" + Delete "$INSTDIR\libexpat-1.dll" + Delete "$INSTDIR\libjpeg-8.dll" + Delete "$INSTDIR\libpng12-0.dll" + Delete "$INSTDIR\libtiff-4.dll" + Delete "$INSTDIR\libz.so.1.2.7" + Delete "$INSTDIR\libstdc++-6.dll" + Delete "$INSTDIR\libmgl-5.dll" + Delete "$INSTDIR\libgcc_s_sjlj-1.dll" Delete "$INSTDIR\uninst.exe" diff -Nru 3depict-0.0.12/src/3Depict.cpp 3depict-0.0.13/src/3Depict.cpp --- 3depict-0.0.12/src/3Depict.cpp 2012-11-24 21:04:42.000000000 +0000 +++ 3depict-0.0.13/src/3Depict.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -1,6 +1,6 @@ /* * threeDepict.cpp - main program user interface and control implementation - * 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 @@ -16,5584 +16,25 @@ * along with this program. If not, see . */ -//DEBUG NaN and INF -#ifdef DEBUG -#ifdef __linux__ -#include -#include -void trapfpe () { -// feenableexcept(FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW); -} -#endif -#endif - -#ifdef __APPLE__ -//FIXME: workaround for UI layout under apple platform -// wxMac appears to have problems with nested panels. -#define APPLE_EFFECTS_WORKAROUND 1 -#endif - - -enum -{ - MESSAGE_ERROR=1, - MESSAGE_INFO, - MESSAGE_HINT, - MESSAGE_NONE_BUT_HINT, - MESSAGE_NONE -}; - -enum -{ - WINDOW_LOCK_REFRESH, - WINDOW_LOCK_NONE -}; - -#ifdef __WXMSW__ -//Force a windows console to show for cerr/cout -#ifdef DEBUG -#include "winconsole.h" -winconsole winC; -#endif -#endif - -//OS specific stuff -#ifdef __APPLE__ -#include "CoreFoundation/CoreFoundation.h" -#endif - -#include "3Depict.h" -#include - -//wxWidgets stuff -#include "wxcomponents.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if wxCHECK_VERSION(2, 9, 0) - #include // Needed for wxLaunchDefaultApplication -#else - #include //Needed for GetOpenCommand -#endif - -//Custom program dialog windows -#include "dialogs/StashDialog.h" //Stash editor -#include "dialogs/resolutionDialog.h" // resolution selection dialog -#include "dialogs/ExportRngDialog.h" // Range export dialog -#include "dialogs/ExportPos.h" // Ion export dialog -#include "dialogs/prefDialog.h" // Preferences dialog -#include "dialogs/autosaveDialog.h" // startup autosave dialog for multiple load options -#include "dialogs/filterErrorDialog.h" // Dialog for displaying details for filter analysis error messages -#include "dialogs/animateFilterDialog.h" // Dialog for performing property sweeps on filters - -#include "translation.h" - -//Program Icon -#include "art.h" - -//Filter imports -#include "filters/rangeFile.h" -#include "filters/dataLoad.h" - -//Unit testing code -#include "testing.h" - -using std::pair; -using std::max; - -//milliseconds before clearing status bar (by invoking a status timer event) -const unsigned int STATUS_TIMER_DELAY=10000; -//Milliseconds between querying viscontrol for needing update -const unsigned int UPDATE_TIMER_DELAY=50; -//Milliseconds between progress bar updates -const unsigned int PROGRESS_TIMER_DELAY=100; -//Seconds between autosaves -const unsigned int AUTOSAVE_DELAY=180; - -//Default window size -const unsigned int DEFAULT_WIN_WIDTH=1024; -const unsigned int DEFAULT_WIN_HEIGHT=800; - -//minimum startup window size -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; - -//The conversion factor from the baseline shift slider to camera units -const float BASELINE_SHIFT_FACTOR=0.0002f; - - -const char *cameraIntroString=NTRANS("New camera name..."); -const char *stashIntroString=NTRANS("New stash name...."); - -//Name of autosave state file. MUST end in .xml middle -const char *AUTOSAVE_PREFIX= "autosave."; -const char *AUTOSAVE_SUFFIX=".xml"; - - -//This is the dropdown matching list. This must match -//the order for comboFilters_choices, as declared in -//MainFrame's constructor - -//--- These settings must be modified concomitantly. -const unsigned int FILTER_DROP_COUNT=14; - -#ifdef DEBUG -EventLogger evtlog(10, &std::cerr); -#endif -const char * comboFilters_choices[FILTER_DROP_COUNT] = -{ - NTRANS("Annotation"), - NTRANS("Bounding Box"), - NTRANS("Clipping"), - NTRANS("Cluster Analysis"), - NTRANS("Compos. Profiles"), - NTRANS("Downsampling"), - NTRANS("Extern. Prog."), - NTRANS("Ion Colour"), - NTRANS("Ion Info"), - NTRANS("Ion Transform"), - NTRANS("Spectrum"), - NTRANS("Range File"), - NTRANS("Spat. Analysis"), - NTRANS("Voxelisation") -}; - -//Mapping between filter ID and combo position -const unsigned int comboFiltersTypeMapping[FILTER_DROP_COUNT] = { - FILTER_TYPE_ANNOTATION, - FILTER_TYPE_BOUNDBOX, - FILTER_TYPE_IONCLIP, - FILTER_TYPE_CLUSTER_ANALYSIS, - FILTER_TYPE_COMPOSITION, - FILTER_TYPE_IONDOWNSAMPLE, - FILTER_TYPE_EXTERNALPROC, - FILTER_TYPE_IONCOLOURFILTER, - FILTER_TYPE_IONINFO, - FILTER_TYPE_TRANSFORM, - FILTER_TYPE_SPECTRUMPLOT, - FILTER_TYPE_RANGEFILE, - FILTER_TYPE_SPATIAL_ANALYSIS, - FILTER_TYPE_VOXELS - }; -//---- - -//Constant identifiers for binding events in wxwidgets "event table" -enum { - - //File menu - ID_MAIN_WINDOW= wxID_ANY+1, - - ID_FILE_EXIT, - ID_FILE_OPEN, - ID_FILE_MERGE, - ID_FILE_SAVE, - ID_FILE_SAVEAS, - ID_FILE_EXPORT_PLOT, - ID_FILE_EXPORT_IMAGE, - ID_FILE_EXPORT_IONS, - ID_FILE_EXPORT_RANGE, - ID_FILE_EXPORT_ANIMATION, - ID_FILE_EXPORT_FILTER_ANIMATION, - ID_FILE_EXPORT_PACKAGE, - - //Edit menu - ID_EDIT_UNDO, - ID_EDIT_REDO, - ID_EDIT_PREFERENCES, - - //Help menu - ID_HELP_ABOUT, - ID_HELP_HELP, - ID_HELP_CONTACT, - - //View menu - ID_VIEW_BACKGROUND, - ID_VIEW_CONTROL_PANE, - ID_VIEW_RAW_DATA_PANE, - ID_VIEW_SPECTRA, - ID_VIEW_PLOT_LEGEND, - ID_VIEW_WORLDAXIS, - ID_VIEW_FULLSCREEN, - //Left hand note pane - ID_NOTEBOOK_CONTROL, - ID_NOTE_CAMERA, - ID_NOTE_DATA, - ID_NOTE_PERFORMANCE, - ID_NOTE_TOOLS, - ID_NOTE_VISUALISATION, - //Lower pane - ID_PANEL_DATA, - ID_PANEL_VIEW, - ID_NOTE_SPECTRA, - ID_NOTE_RAW, - ID_GRID_RAW_DATA, - ID_BUTTON_GRIDCOPY, - ID_LIST_PLOTS, - - //Splitter IDs - ID_SPLIT_LEFTRIGHT, - ID_SPLIT_FILTERPROP, - ID_SPLIT_TOP_BOTTOM, - ID_SPLIT_SPECTRA, - ID_RAWDATAPANE_SPLIT, - ID_CONTROLPANE_SPLIT, - - //Camera panel - ID_COMBO_CAMERA, - ID_GRID_CAMERA_PROPERTY, - - //Filter panel - ID_COMBO_FILTER, - ID_COMBO_STASH, - ID_BTN_STASH_MANAGE, - ID_CHECK_AUTOUPDATE, - ID_FILTER_NAMES, - ID_GRID_FILTER_PROPERTY, - ID_LIST_FILTER, - ID_TREE_FILTERS, - ID_BUTTON_REFRESH, - ID_BTN_EXPAND, - ID_BTN_COLLAPSE, - ID_BTN_FILTERTREE_ERRS, - - //Effects panel - ID_EFFECT_ENABLE, - ID_EFFECT_CROP_ENABLE, - ID_EFFECT_CROP_AXISONE_COMBO, - ID_EFFECT_CROP_PANELONE, - ID_EFFECT_CROP_PANELTWO, - ID_EFFECT_CROP_AXISTWO_COMBO, - ID_EFFECT_CROP_CHECK_COORDS, - ID_EFFECT_CROP_TEXT_DX, - ID_EFFECT_CROP_TEXT_DY, - ID_EFFECT_CROP_TEXT_DZ, - ID_EFFECT_STEREO_ENABLE, - ID_EFFECT_STEREO_COMBO, - ID_EFFECT_STEREO_BASELINE_SLIDER, - ID_EFFECT_STEREO_LENSFLIP, - - //Options panel - ID_CHECK_ALPHA, - ID_CHECK_LIGHTING, - ID_CHECK_CACHING, - ID_CHECK_WEAKRANDOM, - ID_SPIN_CACHEPERCENT, - - //Misc - ID_PROGRESS_ABORT, - ID_STATUS_TIMER, - ID_PROGRESS_TIMER, - ID_UPDATE_TIMER, - ID_AUTOSAVE_TIMER, - - -}; - - -void setWxTreeImages(wxTreeCtrl *t, const map &artFilters) -{ -#if defined(__WIN32) || defined(__WIN64) - const int winTreeIconSize=9; - wxImageList *imList = new wxImageList(winTreeIconSize,winTreeIconSize); -#else - wxImageList *imList = new wxImageList; -#endif - //map to map wxArtIDs to position in the image list - map artMap; - - size_t offset=0; - //Construct an image list for the tree - for(map::const_iterator it=artFilters.begin();it!=artFilters.end();++it) - { - #if defined(__WIN32) || defined(__WIN64) - - imList->Add(wxBitmap(wxBitmap(wxArtProvider::GetBitmap(it->second)). - ConvertToImage().Rescale(winTreeIconSize, winTreeIconSize))); - #else - imList->Add(wxArtProvider::GetBitmap(it->second)); - #endif - - artMap[it->second] = offset; - offset++; - } - - //Assign the image list - note wx will delete the image list here - we don't need to. - t->AssignImageList(imList); - - //Now do a DFS run through the tree, checking to see if any of the elements need - // a particular image - std::stack items; - if (t->GetRootItem().IsOk()) - items.push(t->GetRootItem()); - - while (!items.empty()) - { - wxTreeItemId next = items.top(); - items.pop(); - - //Get the filter pointer - //-- - size_t tItemVal; - wxTreeItemData *tData; - - tData=t->GetItemData(next); - tItemVal=((wxTreeUint *)tData)->value; - //-- - - - map::const_iterator it; - it = artFilters.find(tItemVal); - - if (next != t->GetRootItem() && it!=artFilters.end()) - t->SetItemImage(next,artMap[it->second]); - else - { - t->SetItemImage(next,-1); - } - - wxTreeItemIdValue cookie; - wxTreeItemId nextChild = t->GetFirstChild(next, cookie); - while (nextChild.IsOk()) - { - items.push(nextChild); - nextChild = t->GetNextSibling(nextChild); - } - } - - return; -} - -void clearWxTreeImages(wxTreeCtrl *t) -{ - t->AssignImageList(NULL); -} - -MainWindowFrame::MainWindowFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxFrame(parent, id, title, pos, size, style) -{ - initedOK=false; - programmaticEvent=false; - fullscreenState=0; - verCheckThread=0; - lastMessageType=MESSAGE_NONE; - //Set up the program icon handler - wxArtProvider::Push(new MyArtProvider); - SetIcon(wxArtProvider::GetIcon(wxT("MY_ART_ID_ICON"))); - - //Set up the drag and drop handler - dropTarget = new FileDropTarget(this); - SetDropTarget(dropTarget); - - //Set up the recently used files menu - // Note that this cannot exceed 9. Items show up, but do not trigger events. - // This is bug 12141 in wxWidgets : http://trac.wxwidgets.org/ticket/12141 - ASSERT(configFile.getMaxHistory() <=9); - recentHistory= new wxFileHistory(configFile.getMaxHistory()); - - - programmaticEvent=false; - currentlyUpdatingScene=false; - statusTimer = new wxTimer(this,ID_STATUS_TIMER); - progressTimer = new wxTimer(this,ID_PROGRESS_TIMER); - updateTimer= new wxTimer(this,ID_UPDATE_TIMER); - autoSaveTimer= new wxTimer(this,ID_AUTOSAVE_TIMER); - requireFirstUpdate=true; - - - //Tell the vis controller which window is to remain - //semi-active during calls to wxSafeYield from callback system - visControl.setYieldWindow(this); - //Set up keyboard shortcuts "accelerators" - wxAcceleratorEntry entries[1]; - entries[0].Set(0,WXK_ESCAPE,ID_PROGRESS_ABORT); - wxAcceleratorTable accel(1, entries); - SetAcceleratorTable(accel); - - // begin wxGlade: MainWindowFrame::MainWindowFrame - splitLeftRight = new wxSplitterWindow(this, ID_SPLIT_LEFTRIGHT, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); - panelRight = new wxPanel(splitLeftRight, wxID_ANY); - splitTopBottom = new wxSplitterWindow(panelRight, ID_SPLIT_TOP_BOTTOM, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); - noteDataView = new wxNotebook(splitTopBottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT); - noteDataViewConsole = new wxPanel(noteDataView, wxID_ANY); - noteRaw = new wxPanel(noteDataView, ID_NOTE_RAW); - splitterSpectra = new wxSplitterWindow(noteDataView, ID_SPLIT_SPECTRA, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); - window_2_pane_2 = new wxPanel(splitterSpectra, wxID_ANY); - 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 construtor, and then testing simultaneously - //on a broken and working Gl install. booyah. - glPanelOK=panelTop->m_glWidget; - #elif defined(__WIN32) || defined(__WIN64) || defined(__APPLE__) - //I hope this works. I'm not 100% sure -- I can't seem to reliably break my GL under windows. - glPanelOK=panelTop->GetContext(); - #else - //lets just hope it worked. - glPanelOK=true; - #endif -#endif - - if(!glPanelOK) - { - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please check your video drivers.") - ,wxTRANS("OpenGL Failed"),wxICON_ERROR|wxOK); - - wxD->ShowModal(); - wxD->Destroy(); - - cerr << wxTRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please check your video drivers.") << endl; - return; - } - - panelLeft = new wxPanel(splitLeftRight, wxID_ANY); - notebookControl = new wxNotebook(panelLeft, ID_NOTEBOOK_CONTROL, wxDefaultPosition, wxDefaultSize, wxNB_RIGHT); - noteTools = new wxPanel(notebookControl, ID_NOTE_PERFORMANCE, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - notePost = new wxPanel(notebookControl, wxID_ANY); - noteEffects = new wxNotebook(notePost, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT); - noteFxPanelStereo = new wxPanel(noteEffects, wxID_ANY); - noteFxPanelCrop = new wxPanel(noteEffects, wxID_ANY); - noteCamera = new wxScrolledWindow(notebookControl, ID_NOTE_CAMERA, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - noteData = new wxPanel(notebookControl, ID_NOTE_DATA, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - filterSplitter = new wxSplitterWindow(noteData,ID_SPLIT_FILTERPROP , wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); - filterPropertyPane = new wxPanel(filterSplitter, wxID_ANY); - //topPanelSizer_staticbox = new wxStaticBox(panelTop, -1, wxT("")); - filterTreePane = new wxPanel(filterSplitter, wxID_ANY); - MainFrame_Menu = new wxMenuBar(); - wxMenu* File = new wxMenu(); - File->Append(ID_FILE_OPEN, wxTRANS("&Open...\tCtrl+O"), wxTRANS("Open state file"), wxITEM_NORMAL); - File->Append(ID_FILE_MERGE, wxTRANS("&Merge...\tCtrl+Shift+O"), wxTRANS("Merge other file"), wxITEM_NORMAL); - - recentFilesMenu=new wxMenu(); - recentHistory->UseMenu(recentFilesMenu); - File->AppendSubMenu(recentFilesMenu,wxTRANS("&Recent")); - fileSave = File->Append(ID_FILE_SAVE, wxTRANS("&Save\tCtrl+S"), wxTRANS("Save state to file"), wxITEM_NORMAL); - fileSave->Enable(false); - File->Append(ID_FILE_SAVEAS, wxTRANS("Save &As...\tCtrl+Shift+S"), wxTRANS("Save current state to new file"), wxITEM_NORMAL); - File->AppendSeparator(); - wxMenu* FileExport = new wxMenu(); - FileExport->Append(ID_FILE_EXPORT_PLOT, wxTRANS("&Plot...\tCtrl+P"), wxTRANS("Export Current Plot"), wxITEM_NORMAL); - FileExport->Append(ID_FILE_EXPORT_IMAGE, wxTRANS("&Image...\tCtrl+I"), wxTRANS("Export Current 3D View"), wxITEM_NORMAL); - FileExport->Append(ID_FILE_EXPORT_IONS, wxTRANS("Ion&s...\tCtrl+N"), wxTRANS("Export Ion Data"), wxITEM_NORMAL); - FileExport->Append(ID_FILE_EXPORT_RANGE, wxTRANS("Ran&ges...\tCtrl+G"), wxTRANS("Export Range Data"), wxITEM_NORMAL); - FileExport->Append(ID_FILE_EXPORT_FILTER_ANIMATION, wxTRANS("&Animate Filters...\tCtrl+A"), wxTRANS("Export Animated Filter"), wxITEM_NORMAL); - FileExport->Append(ID_FILE_EXPORT_ANIMATION, wxTRANS("Ani&mate Camera...\tCtrl+M"), wxTRANS("Export Animated Camera"), wxITEM_NORMAL); - FileExport->Append(ID_FILE_EXPORT_PACKAGE, wxTRANS("Pac&kage...\tCtrl+K"), wxTRANS("Export analysis package"), wxITEM_NORMAL); - - File->AppendSubMenu(FileExport,wxTRANS("&Export")); - File->AppendSeparator(); -#ifdef __APPLE__ - File->Append(ID_FILE_EXIT, wxTRANS("&Quit\tCtrl+Q"), wxTRANS("Exit Program"), wxITEM_NORMAL); -#else - File->Append(ID_FILE_EXIT, wxTRANS("E&xit"), wxTRANS("Exit Program"), wxITEM_NORMAL); -#endif - MainFrame_Menu->Append(File, wxTRANS("&File")); - wxMenu* wxglade_tmp_menu_1 = new wxMenu(); - wxglade_tmp_menu_1->Append(ID_VIEW_BACKGROUND, - wxTRANS("&Background Colour...\tCtrl+B"),wxTRANS("Change background colour")); - wxglade_tmp_menu_1->AppendSeparator(); //Separator -#ifndef __APPLE__ - checkMenuControlPane= wxglade_tmp_menu_1->Append(ID_VIEW_CONTROL_PANE, - wxTRANS("&Control Pane\tF3"), wxTRANS("Toggle left control pane"), wxITEM_CHECK); -#else - checkMenuControlPane= wxglade_tmp_menu_1->Append(ID_VIEW_CONTROL_PANE, - wxTRANS("&Control Pane\tAlt+C"), wxTRANS("Toggle left control pane"), wxITEM_CHECK); - -#endif - checkMenuControlPane->Check(); -#ifndef __APPLE__ - checkMenuRawDataPane= wxglade_tmp_menu_1->Append(ID_VIEW_RAW_DATA_PANE, - wxTRANS("&Raw Data Pane\tF4"), wxTRANS("Toggle raw data pane (bottom)"), wxITEM_CHECK); -#else - checkMenuRawDataPane= wxglade_tmp_menu_1->Append(ID_VIEW_RAW_DATA_PANE, - wxTRANS("&Raw Data Pane\tAlt+R"), wxTRANS("Toggle raw data pane (bottom)"), wxITEM_CHECK); -#endif - checkMenuRawDataPane->Check(); -#ifndef __APPLE__ - checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, wxTRANS("&Plot List\tF5"),wxTRANS("Toggle plot list"), wxITEM_CHECK); -#else - checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, wxTRANS("&Plot List\tAlt+P"),wxTRANS("Toggle plot list"), wxITEM_CHECK); -#endif - checkMenuSpectraList->Check(); - - wxglade_tmp_menu_1->AppendSeparator(); //Separator - wxMenu* viewPlot= new wxMenu(); - checkViewLegend=viewPlot->Append(ID_VIEW_PLOT_LEGEND,wxTRANS("&Legend\tCtrl+L"),wxTRANS("Toggle Legend display"),wxITEM_CHECK); - checkViewLegend->Check(); - wxglade_tmp_menu_1->AppendSubMenu(viewPlot,wxTRANS("P&lot...")); - checkViewWorldAxis=wxglade_tmp_menu_1->Append(ID_VIEW_WORLDAXIS,wxTRANS("&Axis\tCtrl+Shift+I"),wxTRANS("Toggle World Axis display"),wxITEM_CHECK); - checkViewWorldAxis->Check(); - - wxglade_tmp_menu_1->AppendSeparator(); //Separator -#ifndef __APPLE__ - menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, wxTRANS("&Fullscreen mode\tF11"),wxTRANS("Next fullscreen mode: with toolbars")); -#else - menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, wxTRANS("&Fullscreen mode\tCtrl+Shift+F"),wxTRANS("Next fullscreen mode: with toolbars")); -#endif - - - wxMenu *Edit = new wxMenu(); - editUndoMenuItem = Edit->Append(ID_EDIT_UNDO,wxTRANS("&Undo\tCtrl+Z")); - editUndoMenuItem->Enable(false); - editRedoMenuItem = Edit->Append(ID_EDIT_REDO,wxTRANS("&Redo\tCtrl+Y")); - editRedoMenuItem->Enable(false); - Edit->AppendSeparator(); - Edit->Append(ID_EDIT_PREFERENCES,wxTRANS("&Preferences")); - - MainFrame_Menu->Append(Edit, wxTRANS("&Edit")); - - - MainFrame_Menu->Append(wxglade_tmp_menu_1, wxTRANS("&View")); - wxMenu* Help = new wxMenu(); - Help->Append(ID_HELP_HELP, wxTRANS("&Help...\tCtrl+H"), wxTRANS("Show help files and documentation"), wxITEM_NORMAL); - Help->Append(ID_HELP_CONTACT, wxTRANS("&Contact..."), wxTRANS("Open contact page"), wxITEM_NORMAL); - Help->AppendSeparator(); - Help->Append(ID_HELP_ABOUT, wxTRANS("&About..."), wxTRANS("Information about this program"), wxITEM_NORMAL); - MainFrame_Menu->Append(Help, wxTRANS("&Help")); - SetMenuBar(MainFrame_Menu); - lblSettings = new wxStaticText(noteData, wxID_ANY, wxTRANS("Stashed Filters")); - - - comboStash = new wxComboBox(noteData, ID_COMBO_STASH, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER|SAFE_CB_SORT); - btnStashManage = new wxButton(noteData, ID_BTN_STASH_MANAGE, wxT("..."),wxDefaultPosition,wxSize(28,28)); - filteringLabel = new wxStaticText(noteData, wxID_ANY, wxTRANS("Data Filtering")); - - - //Workaround for wx bug http://trac.wxwidgets.org/ticket/4398 - //Combo box wont sort even when asked under wxGTK<3.0 - // use sortedArrayString, rather than normal arraystring - wxSortedArrayString filterNames; - for(unsigned int ui=0;uicomboFilters_choices offset. - filterMap[TRANS(str)] = ui; - //Add to filter name wxArray - wxString wxStrTrans = wxTRANS(str); - filterNames.Add(wxStrTrans); - } - - - - comboFilters = new wxComboBox(filterTreePane, ID_COMBO_FILTER, wxT(""), wxDefaultPosition, wxDefaultSize, filterNames, wxCB_DROPDOWN|wxCB_READONLY|SAFE_CB_SORT); - - - treeFilters = new wxTreeCtrl(filterTreePane, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_EDIT_LABELS); - lastRefreshLabel = new wxStaticText(filterTreePane, wxID_ANY, wxTRANS("Last Outputs")); - listLastRefresh = new wxListCtrl(filterTreePane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); - checkAutoUpdate = new wxCheckBox(filterTreePane, ID_CHECK_AUTOUPDATE, wxTRANS("Auto Refresh")); - refreshButton = new wxButton(filterTreePane, wxID_REFRESH, wxEmptyString); - btnFilterTreeExpand= new wxButton(filterTreePane, ID_BTN_EXPAND, wxT("▼"),wxDefaultPosition,wxSize(30,30)); - btnFilterTreeCollapse = new wxButton(filterTreePane, ID_BTN_COLLAPSE, wxT("▲"),wxDefaultPosition,wxSize(30,30)); - btnFilterTreeErrs = new wxBitmapButton(filterTreePane,ID_BTN_FILTERTREE_ERRS,wxArtProvider::GetBitmap(wxART_INFORMATION),wxDefaultPosition,wxSize(40,40)); - - propGridLabel = new wxStaticText(filterPropertyPane, wxID_ANY, wxTRANS("Filter settings")); - gridFilterPropGroup = new wxPropertyGrid(filterPropertyPane, ID_GRID_FILTER_PROPERTY); - labelCameraName = new wxStaticText(noteCamera, wxID_ANY, wxTRANS("Camera Name")); - comboCamera = new wxComboBox(noteCamera, ID_COMBO_CAMERA, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER ); - buttonRemoveCam = new wxButton(noteCamera, wxID_REMOVE, wxEmptyString); - cameraNamePropertySepStaticLine = new wxStaticLine(noteCamera, wxID_ANY); - gridCameraProperties = new wxPropertyGrid(noteCamera, ID_GRID_CAMERA_PROPERTY); -#ifndef APPLE_EFFECTS_WORKAROUND - checkPostProcessing = new wxCheckBox(notePost, ID_EFFECT_ENABLE, wxTRANS("3D Post-processing")); -#endif - checkFxCrop = new wxCheckBox(noteFxPanelCrop, ID_EFFECT_CROP_ENABLE, wxTRANS("Enable Cropping")); - const wxString comboFxCropAxisOne_choices[] = { - wxTRANS("x-y"), - wxTRANS("x-z"), - wxTRANS("y-x"), - wxTRANS("y-z"), - wxTRANS("z-x"), - wxTRANS("z-y") - }; - comboFxCropAxisOne = new wxComboBox(noteFxPanelCrop, ID_EFFECT_CROP_AXISONE_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 6, comboFxCropAxisOne_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY); - panelFxCropOne = new CropPanel(noteFxPanelCrop, ID_EFFECT_CROP_AXISONE_COMBO, - wxDefaultPosition,wxDefaultSize,wxEXPAND); - const wxString comboFxCropAxisTwo_choices[] = { - wxTRANS("x-y"), - wxTRANS("x-z"), - wxTRANS("y-x"), - wxTRANS("y-z"), - wxTRANS("z-x"), - wxTRANS("z-y") - }; - comboFxCropAxisTwo = new wxComboBox(noteFxPanelCrop, ID_EFFECT_CROP_AXISTWO_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 6, comboFxCropAxisTwo_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY); - panelFxCropTwo = new CropPanel(noteFxPanelCrop, ID_EFFECT_CROP_AXISTWO_COMBO,wxDefaultPosition,wxDefaultSize,wxEXPAND); - checkFxCropCameraFrame = new wxCheckBox(noteFxPanelCrop,ID_EFFECT_CROP_CHECK_COORDS,wxTRANS("Use camera coordinates")); - labelFxCropDx = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dX")); - textFxCropDx = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DX, wxEmptyString); - labelFxCropDy = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dY")); - textFxCropDy = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DY, wxEmptyString); - labelFxCropDz = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dZ")); - textFxCropDz = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DZ, wxEmptyString); - checkFxEnableStereo = new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_ENABLE, wxTRANS("Enable Anaglyphic Stereo")); - checkFxStereoLensFlip= new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_LENSFLIP, wxTRANS("Flip Channels")); - lblFxStereoMode = new wxStaticText(noteFxPanelStereo, wxID_ANY, wxTRANS("Anaglyph Mode"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - const wxString comboFxStereoMode_choices[] = { - wxTRANS("Red-Blue"), - wxTRANS("Red-Green"), - wxTRANS("Red-Cyan"), - wxTRANS("Green-Magenta"), - }; - comboFxStereoMode = new wxComboBox(noteFxPanelStereo, ID_EFFECT_STEREO_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 4, comboFxStereoMode_choices, wxCB_DROPDOWN|wxCB_SIMPLE|wxCB_READONLY); - 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); - 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); - checkWeakRandom = new wxCheckBox(noteTools, ID_CHECK_WEAKRANDOM, wxTRANS("Fast and weak randomisation.")); - checkWeakRandom->SetValue(true); - 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); - spinCachePercent = new wxSpinCtrl(noteTools, ID_SPIN_CACHEPERCENT, wxT("50"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100); - panelView = new wxPanel(panelTop, ID_PANEL_VIEW); - panelSpectra = new MathGLPane(splitterSpectra, wxID_ANY); - plotListLabel = new wxStaticText(window_2_pane_2, wxID_ANY, wxTRANS("Plot List")); - plotList = new wxListBox(window_2_pane_2, ID_LIST_PLOTS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE|wxLB_NEEDED_SB|wxLB_SORT); - gridRawData = new CopyGrid(noteRaw, ID_GRID_RAW_DATA); - btnRawDataSave = new wxButton(noteRaw, wxID_SAVE, wxEmptyString); - btnRawDataClip = new wxButton(noteRaw, wxID_COPY, wxEmptyString); - textConsoleOut = new wxTextCtrl(noteDataViewConsole, - wxID_ANY, wxEmptyString,wxDefaultPosition, - wxDefaultSize,wxTE_MULTILINE|wxTE_READONLY); - MainFrame_statusbar = CreateStatusBar(3, 0); - - set_properties(); - do_layout(); - - //Disable post-processing -#ifndef APPLE_EFFECTS_WORKAROUND - checkPostProcessing->SetValue(false); - noteFxPanelCrop->Enable(false); - noteFxPanelStereo->Enable(false); -#else - //Disable Fx panel stereo controls explicitly - comboFxStereoMode->Enable(false); - sliderFxStereoBaseline->Enable(false); - checkFxStereoLensFlip->Enable(false); - - //Disable Crop controls explicitly - checkFxCropCameraFrame->Enable(false); - comboFxCropAxisOne->Enable(false); - panelFxCropOne->Enable(false); - comboFxCropAxisTwo->Enable(false); - panelFxCropTwo->Enable(false); - textFxCropDx->Enable(false); - textFxCropDy->Enable(false); - textFxCropDz->Enable(false); - labelFxCropDx->Enable(false); - labelFxCropDy->Enable(false); - labelFxCropDz->Enable(false); - -#endif - - //Link the crop panels in the post section appropriately - panelFxCropOne->link(panelFxCropTwo,CROP_LINK_BOTH); - panelFxCropTwo->link(panelFxCropOne,CROP_LINK_BOTH); - - - - //Manually tuned splitter parameters. - filterSplitter->SetMinimumPaneSize(80); - filterSplitter->SetSashGravity(0.8); - splitLeftRight->SetSashGravity(0.15); - splitTopBottom->SetSashGravity(0.85); - splitterSpectra->SetSashGravity(0.82); - - //Last Refresh box - listLastRefresh->InsertColumn(0,wxTRANS("Type")); - listLastRefresh->InsertColumn(1,wxTRANS("Num")); - - //Inform top panel about timer and timeouts - panelTop->setParentStatus(MainFrame_statusbar,statusTimer,STATUS_TIMER_DELAY); - - panelTop->clearCameraUpdates(); - - // end wxGlade - // - - - - //Try to load config file. If we can't no big deal. - unsigned int errCode; - errCode=configFile.read(); - if(!errCode) - { - std::vector strVec; - - //Set the files that are listed in the recent files - //menu - configFile.getRecentFiles(strVec); - - for(unsigned int ui=0;uiAddFileToHistory(wxStr(strVec[ui])); - - //Set the panel defaults (hidden/shown) - if(!configFile.getPanelEnabled(CONFIG_STARTUPPANEL_CONTROL)) - { - splitLeftRight->Unsplit(panelLeft); - checkMenuControlPane->Check(false); - } - if(!configFile.getPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA)) - { - splitTopBottom->Unsplit(); - checkMenuRawDataPane->Check(false); - } - if(!configFile.getPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST)) - { - splitterSpectra->Unsplit(); - checkMenuSpectraList->Check(false); - } - - - //Set the mouse zoom speeds - float zoomRate,moveRate; - zoomRate=configFile.getMouseZoomRate(); - moveRate=configFile.getMouseMoveRate(); - - - panelTop->setMouseZoomFactor((float)zoomRate/100.0f); - panelTop->setMouseMoveFactor((float)moveRate/100.0f); - - } - else - { - switch(errCode) - { - case CONFIG_ERR_NOFILE: - break; - case CONFIG_ERR_BADFILE: - { - textConsoleOut->AppendText(wxTRANS("Warning: Your configuration file appears to be invalid:\n")); - wxString wxS = wxTRANS("\tConfig Load: "); - wxS+= wxStr( configFile.getErrMessage()); - textConsoleOut->AppendText(wxS); - break; - } - default: - ASSERT(false); - } - } - - //Try to set the window size to a nice size - SetSize(getNiceWindowSize()); - - //Restore the sash panel positions - //---------------- - if(configFile.configLoadedOK()) - { - wxSize winSize; - winSize=getNiceWindowSize(); - float val,oldGravity; - val=configFile.getLeftRightSashPos(); - if(val > std::numeric_limits::epsilon()) - { - oldGravity=splitLeftRight->GetSashGravity(); - splitLeftRight->SetSashGravity(1.0); - splitLeftRight->SetSashPosition((int)(val*(float)winSize.GetWidth())); - splitLeftRight->SetSashGravity(oldGravity); - - } - val=configFile.getTopBottomSashPos(); - if(val > std::numeric_limits::epsilon()) - { - oldGravity=splitTopBottom->GetSashGravity(); - splitTopBottom->SetSashGravity(1.0); - splitTopBottom->SetSashPosition((int)(val*(float)winSize.GetHeight())); - splitTopBottom->SetSashGravity(oldGravity); - } - val=configFile.getFilterSashPos(); - winSize=filterPropertyPane->GetSize(); - if(val > std::numeric_limits::epsilon()) - { - oldGravity=filterSplitter->GetSashGravity(); - filterSplitter->SetSashGravity(1.0); - filterSplitter->SetSashPosition((int)(val*(float)winSize.GetHeight())); - filterSplitter->SetSashGravity(oldGravity); - } - winSize=noteDataView->GetSize(); - val=configFile.getPlotListSashPos(); - if(val > std::numeric_limits::epsilon()) - { - oldGravity=splitterSpectra->GetSashGravity(); - splitterSpectra->SetSashGravity(1.0); - splitterSpectra->SetSashPosition((int)(val*(float)winSize.GetWidth())); - splitterSpectra->SetSashGravity(oldGravity); - } - } - //----------- - - - //Attempt to load the auto-save file, if it exists - //----------------- - checkReloadAutosave(); - //----------------- - - - initedOK=true; - - - updateTimer->Start(UPDATE_TIMER_DELAY,wxTIMER_CONTINUOUS); - autoSaveTimer->Start(AUTOSAVE_DELAY*1000,wxTIMER_CONTINUOUS); - -#ifndef DISABLE_ONLINE_UPDATE - wxDateTime datetime = wxDateTime::Today(); - - //Annoy the user, on average, every (% blah) days. - const int CHECK_FREQUENCY=7; - - //Generate a pseudorandom number of fixed sequence - LinearFeedbackShiftReg lfsr; - //Set the period to 2^9 (power of 2 > weeksinyear*daysinweek) - lfsr.setMaskPeriod(9); - lfsr.setState(109); //Guaranteed to be random. Chosen by fair random generator. - - unsigned int offset = datetime.GetWeekOfYear()*7 + datetime.GetWeekDay(); - while(offset--) - lfsr.clock(); //Discard a whole bunch of entires - - //Everyone will get the same pseudorandom number on the same day. - size_t pseudorandomVal=lfsr.clock(); - ASSERT(pseudorandomVal); //shouldn't be zero, or LFSR is in bad state - - if( configFile.getAllowOnlineVersionCheck() && - !(pseudorandomVal %CHECK_FREQUENCY)) - { - - verCheckThread=new VersionCheckThread(this); - verCheckThread->Create(); - verCheckThread->Run(); - } -#endif -} - -MainWindowFrame::~MainWindowFrame() -{ - - //Delete and stop all the timers. - delete statusTimer; - delete progressTimer; - delete updateTimer; - delete autoSaveTimer; - - //delete the file history pointer - delete recentHistory; - - - //wxwidgets can crash if objects are ->Connect-ed in - // wxWindowBase::DestroyChildren(), so Disconnect before destructing -#if wxCHECK_VERSION(2, 9, 0) - comboCamera->Unbind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboCameraSetFocus, this); - comboStash->Unbind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboStashSetFocus, this); - noteDataView->Unbind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MainWindowFrame::OnNoteDataView, this); -#else - noteDataView->Disconnect(); - comboStash->Disconnect(); - comboCamera->Disconnect(); -#endif -} - - -BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame) - EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_FILTER_PROPERTY,MainWindowFrame::OnFilterGridCellEditorShow) - EVT_GRID_CMD_EDITOR_HIDDEN(ID_GRID_FILTER_PROPERTY,MainWindowFrame::OnFilterGridCellEditorHide) - EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_CAMERA_PROPERTY,MainWindowFrame::OnCameraGridCellEditorShow) - EVT_GRID_CMD_EDITOR_HIDDEN(ID_GRID_CAMERA_PROPERTY,MainWindowFrame::OnCameraGridCellEditorHide) - EVT_TIMER(ID_STATUS_TIMER,MainWindowFrame::OnStatusBarTimer) - EVT_TIMER(ID_PROGRESS_TIMER,MainWindowFrame::OnProgressTimer) - EVT_TIMER(ID_UPDATE_TIMER,MainWindowFrame::OnUpdateTimer) - EVT_TIMER(ID_AUTOSAVE_TIMER,MainWindowFrame::OnAutosaveTimer) - EVT_SPLITTER_UNSPLIT(ID_SPLIT_TOP_BOTTOM, MainWindowFrame::OnRawDataUnsplit) - EVT_SPLITTER_UNSPLIT(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlUnsplit) - EVT_SPLITTER_UNSPLIT(ID_SPLIT_SPECTRA, MainWindowFrame::OnSpectraUnsplit) - EVT_SPLITTER_DCLICK(ID_SPLIT_FILTERPROP, MainWindowFrame::OnFilterPropDoubleClick) - EVT_SPLITTER_DCLICK(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlUnsplit) - EVT_SPLITTER_SASH_POS_CHANGED(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlSplitMove) - EVT_SPLITTER_SASH_POS_CHANGED(ID_SPLIT_TOP_BOTTOM, MainWindowFrame::OnTopBottomSplitMove) - // begin wxGlade: MainWindowFrame::event_table - EVT_MENU(ID_FILE_OPEN, MainWindowFrame::OnFileOpen) - EVT_MENU(ID_FILE_MERGE, MainWindowFrame::OnFileMerge) - EVT_MENU(ID_FILE_SAVE, MainWindowFrame::OnFileSave) - EVT_MENU(ID_FILE_SAVEAS, MainWindowFrame::OnFileSaveAs) - EVT_MENU(ID_FILE_EXPORT_PLOT, MainWindowFrame::OnFileExportPlot) - EVT_MENU(ID_FILE_EXPORT_IMAGE, MainWindowFrame::OnFileExportImage) - EVT_MENU(ID_FILE_EXPORT_IONS, MainWindowFrame::OnFileExportIons) - EVT_MENU(ID_FILE_EXPORT_RANGE, MainWindowFrame::OnFileExportRange) - EVT_MENU(ID_FILE_EXPORT_ANIMATION, MainWindowFrame::OnFileExportVideo) - EVT_MENU(ID_FILE_EXPORT_FILTER_ANIMATION, MainWindowFrame::OnFileExportFilterVideo) - EVT_MENU(ID_FILE_EXPORT_PACKAGE, MainWindowFrame::OnFileExportPackage) - EVT_MENU(ID_FILE_EXIT, MainWindowFrame::OnFileExit) - - EVT_MENU(ID_EDIT_UNDO, MainWindowFrame::OnEditUndo) - EVT_MENU(ID_EDIT_REDO, MainWindowFrame::OnEditRedo) - EVT_MENU(ID_EDIT_PREFERENCES, MainWindowFrame::OnEditPreferences) - - EVT_MENU(ID_VIEW_BACKGROUND, MainWindowFrame::OnViewBackground) - EVT_MENU(ID_VIEW_CONTROL_PANE, MainWindowFrame::OnViewControlPane) - EVT_MENU(ID_VIEW_RAW_DATA_PANE, MainWindowFrame::OnViewRawDataPane) - EVT_MENU(ID_VIEW_SPECTRA, MainWindowFrame::OnViewSpectraList) - EVT_MENU(ID_VIEW_PLOT_LEGEND, MainWindowFrame::OnViewPlotLegend) - EVT_MENU(ID_VIEW_WORLDAXIS, MainWindowFrame::OnViewWorldAxis) - EVT_MENU(ID_VIEW_FULLSCREEN, MainWindowFrame::OnViewFullscreen) - - EVT_MENU(ID_HELP_HELP, MainWindowFrame::OnHelpHelp) - EVT_MENU(ID_HELP_CONTACT, MainWindowFrame::OnHelpContact) - EVT_MENU(ID_HELP_ABOUT, MainWindowFrame::OnHelpAbout) - EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, MainWindowFrame::OnRecentFile) - - EVT_BUTTON(wxID_REFRESH,MainWindowFrame::OnButtonRefresh) - EVT_BUTTON(wxID_COPY,MainWindowFrame::OnButtonGridCopy) - EVT_BUTTON(wxID_SAVE,MainWindowFrame::OnButtonGridSave) - EVT_TEXT(ID_COMBO_STASH, MainWindowFrame::OnComboStashText) - EVT_TEXT_ENTER(ID_COMBO_STASH, MainWindowFrame::OnComboStashEnter) - EVT_COMBOBOX(ID_COMBO_STASH, MainWindowFrame::OnComboStash) - EVT_TREE_END_DRAG(ID_TREE_FILTERS, MainWindowFrame::OnTreeEndDrag) - EVT_TREE_KEY_DOWN(ID_TREE_FILTERS, MainWindowFrame::OnTreeKeyDown) - EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, MainWindowFrame::OnTreeSelectionChange) - EVT_TREE_DELETE_ITEM(ID_TREE_FILTERS, MainWindowFrame::OnTreeDeleteItem) - EVT_TREE_BEGIN_DRAG(ID_TREE_FILTERS, MainWindowFrame::OnTreeBeginDrag) - EVT_BUTTON(ID_BTN_EXPAND, MainWindowFrame::OnBtnExpandTree) - EVT_BUTTON(ID_BTN_COLLAPSE, MainWindowFrame::OnBtnCollapseTree) - EVT_BUTTON(ID_BTN_FILTERTREE_ERRS, MainWindowFrame::OnBtnFilterTreeErrs) - EVT_GRID_CMD_CELL_CHANGE(ID_GRID_FILTER_PROPERTY, MainWindowFrame::OnGridFilterPropertyChange) - EVT_GRID_CMD_CELL_CHANGE(ID_GRID_CAMERA_PROPERTY, MainWindowFrame::OnGridCameraPropertyChange) - EVT_TEXT(ID_COMBO_CAMERA, MainWindowFrame::OnComboCameraText) - EVT_TEXT_ENTER(ID_COMBO_CAMERA, MainWindowFrame::OnComboCameraEnter) - EVT_CHECKBOX(ID_CHECK_ALPHA, MainWindowFrame::OnCheckAlpha) - EVT_CHECKBOX(ID_CHECK_LIGHTING, MainWindowFrame::OnCheckLighting) - EVT_CHECKBOX(ID_CHECK_CACHING, MainWindowFrame::OnCheckCacheEnable) - EVT_CHECKBOX(ID_CHECK_WEAKRANDOM, MainWindowFrame::OnCheckWeakRandom) - EVT_SPINCTRL(ID_SPIN_CACHEPERCENT, MainWindowFrame::OnCacheRamUsageSpin) - EVT_COMBOBOX(ID_COMBO_CAMERA, MainWindowFrame::OnComboCamera) - EVT_COMBOBOX(ID_COMBO_FILTER, MainWindowFrame::OnComboFilter) - EVT_TEXT_ENTER(ID_COMBO_FILTER, MainWindowFrame::OnComboFilterEnter) - EVT_BUTTON(ID_BTN_STASH_MANAGE, MainWindowFrame::OnButtonStashDialog) - EVT_BUTTON(wxID_REMOVE, MainWindowFrame::OnButtonRemoveCam) - EVT_LISTBOX(ID_LIST_PLOTS, MainWindowFrame::OnSpectraListbox) - EVT_CLOSE(MainWindowFrame::OnClose) - EVT_TREE_END_LABEL_EDIT(ID_TREE_FILTERS,MainWindowFrame::OnTreeEndLabelEdit) - EVT_TREE_BEGIN_LABEL_EDIT(ID_TREE_FILTERS,MainWindowFrame::OnTreeBeginLabelEdit) - - //Post-processing stuff - EVT_CHECKBOX(ID_EFFECT_ENABLE, MainWindowFrame::OnCheckPostProcess) - EVT_CHECKBOX(ID_EFFECT_CROP_ENABLE, MainWindowFrame::OnFxCropCheck) - EVT_CHECKBOX(ID_EFFECT_CROP_CHECK_COORDS, MainWindowFrame::OnFxCropCamFrameCheck) - EVT_COMBOBOX(ID_EFFECT_CROP_AXISONE_COMBO, MainWindowFrame::OnFxCropAxisOne) - EVT_COMBOBOX(ID_EFFECT_CROP_AXISTWO_COMBO, MainWindowFrame::OnFxCropAxisTwo) - EVT_CHECKBOX(ID_EFFECT_STEREO_ENABLE, MainWindowFrame::OnFxStereoEnable) - 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_COMMAND(wxID_ANY, RemoteUpdateAvailEvent, MainWindowFrame::OnCheckUpdatesThread) - // end wxGlade -END_EVENT_TABLE(); - - - - -void MainWindowFrame::OnFileOpen(wxCommandEvent &event) -{ - //Do not allow any action if a scene update is in progress - if(currentlyUpdatingScene) - 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); - - //Show the file dialog - if( (wxF->ShowModal() == wxID_CANCEL)) - return; - - textConsoleOut->Clear(); - //Load the file - if(!loadFile(wxF->GetPath())) - return; - - - std::string tmp; - tmp = stlStr(wxF->GetPath()); - configFile.addRecentFile(tmp); - //Update the "recent files" menu - recentHistory->AddFileToHistory(wxF->GetPath()); - - - - //Get vis controller to update tree control to match internal - //structure - visControl.updateWxTreeCtrl(treeFilters); - refreshButton->Enable(visControl.numFilters()); - - bool updateOK; - updateOK =doSceneUpdate(); - //If we are using the default camera, - //move it to make sure that it is visible - if(updateOK) - { - if(visControl.numCams() == 1) - visControl.ensureSceneVisible(3); - - statusMessage(TRANS("Loaded file."),MESSAGE_INFO); - } - - panelTop->Refresh(); - - wxF->Destroy(); -} - -void MainWindowFrame::OnFileMerge(wxCommandEvent &event) -{ - //Do not allow any action if a scene update is in progress - if(currentlyUpdatingScene) - return; - - //Load a file, either a state file, or a new pos file, or text file - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Select Data or State File..."), wxT(""), - wxT(""),wxTRANS("3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|XML State File (*.xml)|*.xml|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST); - - //Show the file dialog - if( (wxF->ShowModal() == wxID_CANCEL)) - return; - - textConsoleOut->Clear(); - //Load the file - if(!loadFile(wxF->GetPath(),true)) - return; - - //Get vis controller to update tree control to match internal - //structure - visControl.updateWxTreeCtrl(treeFilters); - refreshButton->Enable(visControl.numFilters()); - - bool updateOK; - updateOK =doSceneUpdate(); - if(updateOK) - statusMessage(TRANS("Merged file."),MESSAGE_INFO); - - panelTop->Refresh(); - - wxF->Destroy(); -} - -void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y) -{ - //We can't alter the filter state if we are refreshing - if(visControl.isRefreshing()) - return ; - - textConsoleOut->Clear(); - wxMouseState wxm = wxGetMouseState(); - - - Filter *fToSelect=0; - - //Try opening the files as range (if ext. agrees) - // or as - bool loaded =false; - for(unsigned int ui=0;uiGetCount()) - { - //Check the extension to see if it should be a range file - wxFileName fileName; - fileName.Assign(files[ui]); - ext=stlStr(fileName.GetExt()); - - for(size_t uj=0;ujGetSelection(); - - if(id == treeFilters->GetRootItem()) - { - wxTreeItemIdValue cookie; - id = treeFilters->GetFirstChild(id,cookie); - } - - if(id.IsOk() && id!=treeFilters->GetRootItem()) - { - RangeFile rng; - string s; - s=stlStr(files[ui]); - if(rng.openGuessFormat(s.c_str())) - { - rangeOK=true; - - - //Load rangefile & construct filter - RangeFileFilter *f; - f=(RangeFileFilter *)configFile.getDefaultFilter(FILTER_TYPE_RANGEFILE); - //Copy across the range data - f->setRangeData(rng); - f->setRangeFilename(s.c_str()); - - //Get the tree data container - wxTreeItemData *tData=treeFilters->GetItemData(id); - //Get the parent filter pointer - visControl.addFilter(f,false,((wxTreeUint *)tData)->value); - - fToSelect=f; - } - else - { - //OK, we need to let the user know something went wrong. - //Less annoying than a dialog, but the statusbar is going - //to be useless, as it will be overwritten during the subsequent - //refresh (when we treat this as a pos file). - //FIXME: Something needs to go here... A queue for messages? - } - - - } - } - } - //--- - - //If it is a pos file, just handle it by trying to load - if(!rangeOK) - { - - //If command down, load first file using this, - //then merge the rest - if(!loaded) - { - if(loadFile(files[ui],!wxm.CmdDown())) - loaded=true; - } - else - loadFile(files[ui],true); - } - } - - - if(!wxm.CmdDown() && files.Count()) - { -#ifdef __APPLE__ - statusMessage(TRANS("Tip: You can use ⌘ (command) to merge"),MESSAGE_HINT); -#else - statusMessage(TRANS("Tip: You can use ctrl to merge"),MESSAGE_HINT); -#endif - } - - if(files.Count()) - { - if(fToSelect) - visControl.updateWxTreeCtrl(treeFilters,fToSelect); - else - visControl.updateWxTreeCtrl(treeFilters); - refreshButton->Enable(visControl.numFilters()); - doSceneUpdate(); - //If we are using the default camera, - //move it to make sure that it is visible - if(visControl.numCams() == 1) - visControl.ensureSceneVisible(3); - } -} - -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); - - //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")) - { - std::stringstream ss; - - //Load the file as if it were an XML file - if(!visControl.loadState(dataFile.c_str(),ss,merge)) - { - std::string str; - str=ss.str(); - textConsoleOut->AppendText(wxStr(str)); - //Note that the parent window must be NULL - // if the parent window is not visible (eg autosave startup) - wxWindow *parentWin=NULL; - if(this->IsShown()) - parentWin=this; - - wxMessageDialog *wxD =new wxMessageDialog(parentWin, - wxTRANS("Error loading state file.\nSee console for more info.") - ,wxTRANS("Load error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - 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()) - { - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("This state file contains filters that can be unsafe to run\nDo you wish to remove these before continuing?.") - ,wxTRANS("Security warning"),wxYES_NO|wxICON_WARNING|wxYES_DEFAULT ); - - wxD->SetAffirmativeId(wxID_YES); - wxD->SetEscapeId(wxID_NO); - - if(wxD->ShowModal()!= wxID_NO) - visControl.stripHazardousContents(); - - } - - //Update the background colour - if(panelTop->isInited()) - panelTop->updateClearColour(); - - checkViewWorldAxis->Check(visControl.getAxisVisible()); - - //Update the camera dropdown - vector > camData; - visControl.getCamData(camData); - - comboCamera->Clear(); - unsigned int uniqueID; - //Skip the first element, as it is a hidden camera. - for(unsigned int ui=1;uiAppend(wxStr(camData[ui].second), - (wxClientData *)new wxListUint(camData[ui].first)); - //If this is the active cam (1) set the selection and (2) remember - //the ID - if(camData[ui].first == 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) - { - //Use the remembered ID to update the grid. - visControl.updateCamPropertyGrid(gridCameraProperties,uniqueID); - } - else - { - //Reset the camera property fields & combo box - gridCameraProperties->clear(); - comboCamera->SetValue(wxCStr(TRANS(cameraIntroString))); - } - - //reset the stash combo box - comboStash->SetValue(wxCStr(TRANS(stashIntroString))); - - - //Check to see if we have any effects that we need to enable - vector effs; - panelTop->currentScene.getEffects(effs); - if(!effs.empty()) - { - //OK, we have some effects; we will need to update the UI - updateFxUI(effs); - } - - - - currentFile =fileStr; - fileSave->Enable(true); - - - - //Update the stash combo box - comboStash->Clear(); - - std::vector > stashList; - visControl.getStashes(stashList); - for(unsigned int ui=0;uiAppend(wxStr(stashList[ui].first),(wxClientData *)u); - ASSERT(comboStash->GetClientObject(comboStash->GetCount()-1)); - } - - gridFilterPropGroup->clear(); - - } - else - { - - FilterTree fTree; - - Filter *posFilter,*downSampleFilter; - 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") ) - fileMode=DATALOAD_TEXT_FILE; - else - fileMode=DATALOAD_FLOAT_FILE; - - ((DataLoadFilter*)posFilter)->setFileMode(fileMode); - ((DataLoadFilter*)posFilter)->setFilename(dataFile); - - - //Append a new filter to the filter tree - fTree.addFilter(posFilter,0); - fTree.addFilter(downSampleFilter,posFilter); - visControl.addFilterTree(fTree,true,0); - //Update the tree control - visControl.updateWxTreeCtrl(treeFilters); - - doSceneUpdate(); - currentFile.clear(); - } - - return true; -} - -void MainWindowFrame::OnRecentFile(wxCommandEvent &event) -{ - - if(currentlyUpdatingScene) - return; - - wxString f(recentHistory->GetHistoryFile(event.GetId() - wxID_FILE1)); - - if (!f.empty()) - { - textConsoleOut->Clear(); - - bool loadOK=false; - if(!wxFileExists(f)) - statusMessage("File does not exist",MESSAGE_ERROR); - else if(loadFile(f)) - { - //If we are using the default camera, - //move it to make sure that it is visible - if(visControl.numCams() == 1) - visControl.ensureSceneVisible(3); - - //set the viscontrol to match tree - visControl.updateWxTreeCtrl(treeFilters); - refreshButton->Enable(visControl.numFilters()); - - loadOK =doSceneUpdate(); - //If we are using the default camera, - //move it to make sure that it is visible - if(loadOK) - { - if(visControl.numCams() == 1) - visControl.ensureSceneVisible(3); - - statusMessage(TRANS("Loaded file."),MESSAGE_INFO); - } - panelTop->Refresh(); - } - - if(!loadOK) - { - //Didn't load? We don't want it. - recentHistory->RemoveFileFromHistory(event.GetId()-wxID_FILE1); - configFile.removeRecentFile(stlStr(f)); - } - } -} - -void MainWindowFrame::OnFileSave(wxCommandEvent &event) -{ - if(!currentFile.length()) - return; - - //If the file does not exist, use saveas instead - if(!wxFileExists(currentFile)) - { - OnFileSaveAs(event); - - return; - } - - - std::map dummyMap; - std::string dataFile = stlStr(currentFile); - - //Try to save the viscontrol state - if(!visControl.saveState(dataFile.c_str(),dummyMap)) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - 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); - - } - -} - -void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event) -{ - - if(!panelSpectra->getNumVisible()) - { - std::string errString; - errString=TRANS("No plot available. Please create a plot before exporting."); - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Unable to save"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - - wxD->Destroy(); - return; - } - - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save plot..."), wxT(""), - wxT(""),wxTRANS("By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*.svg|PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE); - - if( (wxF->ShowModal() == wxID_CANCEL)) - return; - - std::string dataFile = stlStr(wxF->GetPath()); - - //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(wxF->GetPath(),&volume, - &path,&name,&ext, &hasExt); - - - std::string strExt; - strExt=stlStr(ext); - strExt = lowercase(strExt); - wxF->Destroy(); - - unsigned int errCode; - - //Try to save the file (if we recognise the extension) - if(strExt == "svg") - errCode=panelSpectra->saveSVG(dataFile); - else if (strExt == "png") - { - //Show a resolution chooser dialog - ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution")); - - int plotW,plotH; - panelSpectra->GetClientSize(&plotW,&plotH); - d.setRes(plotW,plotH,true); - if(d.ShowModal() == wxID_CANCEL) - return; - - - errCode=panelSpectra->savePNG(dataFile,d.getWidth(),d.getHeight()); - - } - else - { - std::string errString; - errString=TRANS("Unknown file extension. Please use \"svg\" or \"png\""); - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Unable to save"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - - wxD->Destroy(); - return; - } - - //Did we save OK? If not, let the user know - if(errCode) - { - std::string errString; - errString=panelSpectra->getErrString(errCode); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - else - { - dataFile=std::string(TRANS("Saved plot: ")) + dataFile; - statusMessage(dataFile.c_str(),MESSAGE_INFO); - } -} - -void MainWindowFrame::OnFileExportImage(wxCommandEvent &event) -{ - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save Image..."), wxT(""), - wxT(""),wxTRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE); - - if( (wxF->ShowModal() == wxID_CANCEL)) - return; - - std::string dataFile = stlStr(wxF->GetPath()); - - //Show a resolution chooser dialog - ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution")); - - //Use the current res as the dialog default - int w,h; - panelTop->GetClientSize(&w,&h); - d.setRes(w,h,true); - - //Show dialog, skip save if user cancels dialog - if(d.ShowModal() == wxID_CANCEL) - return; - - if((d.getWidth() < w && d.getHeight() > h) || - (d.getWidth() > w && d.getHeight() < h)) - { - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("Limitation on the screenshot dimension; please ensure that both width and height exceed the initial values,\n or that they are smaller than the initial values.\n If this bothers you, please submit a bug."), - wxTRANS("Program limitation"),wxOK|wxICON_ERROR); - - wxD->ShowModal(); - - wxD->Destroy(); - - return; - } - - - bool saveOK=panelTop->saveImage(d.getWidth(),d.getHeight(),dataFile.c_str()); - - if(!saveOK) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - else - { - dataFile=std::string(TRANS("Saved 3D View :")) + dataFile; - statusMessage(dataFile.c_str(),MESSAGE_INFO); - } - -} - - -void MainWindowFrame::OnFileExportVideo(wxCommandEvent &event) -{ - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save Image..."), wxT(""), - wxT(""),wxTRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE); - - if( (wxF->ShowModal() == wxID_CANCEL)) - return; - - - //Show a resolution chooser dialog - ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution")); - - //Use the current res as the dialog default - int w,h; - panelTop->GetClientSize(&w,&h); - d.setRes(w,h,true); - - //Show dialog, skip save if user cancels dialo - if(d.ShowModal() == wxID_CANCEL) - { - wxF->Destroy(); - return; - } - - if((d.getWidth() < w && d.getHeight() > h) || - (d.getWidth() > w && d.getHeight() < h) ) - { - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("Limitation on the screenshot dimension; please ensure that both width and height exceed the initial values,\n or that they are smaller than the initial values.\n If this bothers, please submit a bug."), - wxTRANS("Program limitation"),wxOK|wxICON_ERROR); - - wxD->ShowModal(); - - wxD->Destroy(); - wxF->Destroy(); - - return; - } - - - wxFileName fname; - wxString volume,path,name,ext; - bool hasExt; - fname.SplitPath(wxF->GetPath(),&volume, - &path,&name,&ext, &hasExt); - - if(!hasExt) - ext=wxT("png"); - - ///TODO: This is nasty and hackish. We should present a nice, - //well laid out dialog for frame count (show angular increment) - wxTextEntryDialog *teD = new wxTextEntryDialog(this,wxTRANS("Number of frames"),wxTRANS("Frame count"), - wxT("180"),(long int)wxOK|wxCANCEL); - - unsigned int numFrames=0; - std::string strTmp; - do - { - if(teD->ShowModal() == wxID_CANCEL) - { - wxF->Destroy(); - teD->Destroy(); - return; - } - - - strTmp = stlStr(teD->GetValue()); - }while(stream_cast(numFrames,strTmp)); - - teD->Destroy(); - - - bool saveOK=panelTop->saveImageSequence(d.getWidth(),d.getHeight(), - numFrames,path,name,ext); - - - if(!saveOK) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - else - { - std::string dataFile = stlStr(wxF->GetPath()); - dataFile=std::string(TRANS("Saved 3D View :")) + dataFile; - statusMessage(dataFile.c_str(),MESSAGE_INFO); - } - wxF->Destroy(); - -} - - -void MainWindowFrame::setLockUI(bool locking=true, - unsigned int lockMode=WINDOW_LOCK_REFRESH) -{ - switch(lockMode) - { - case WINDOW_LOCK_REFRESH: - { - comboFilters->Enable(!locking); - refreshButton->Enable(!locking); - editUndoMenuItem->Enable(!locking); - editRedoMenuItem->Enable(!locking); - gridFilterPropGroup->Enable(!locking); - comboStash->Enable(!locking); - - //Locking of the tools pane - checkWeakRandom->Enable(!locking); - checkCaching->Enable(!locking); - spinCachePercent->Enable(!locking); - - - - panelSpectra->limitInteraction(!locking); - break; - } - default: - ASSERT(false); - } -} - -void MainWindowFrame::OnFileExportFilterVideo(wxCommandEvent &event) - -{ - - //Don't let the user run the animation dialog if they have - // no filters open - if(!visControl.numFilters()) - { - statusMessage(TRANS("Cannot run animate with no filters.")); - return; - } - - - ExportAnimationDialog *exportDialog = - new ExportAnimationDialog(this, wxID_ANY, wxEmptyString); - - int w, h; - panelTop->GetClientSize(&w,&h); - FilterTree origTree; - - //Steal the filter tree, and give the pointer to the export dialog - // viscontrol now has an empty tree, so watch out. - visControl.swapFilterTree(origTree); - exportDialog->setTree(origTree); - exportDialog->prepare(); - visControl.swapFilterTree(origTree); - - //Animate dialog - if( (exportDialog->ShowModal() == wxID_CANCEL)) - { - exportDialog->Destroy(); - return; - } - - - setLockUI(); - panelTop->Enable(false); - - size_t numFrames; - numFrames=exportDialog->getNumFrames(); - - - currentlyUpdatingScene=true; - //Modify the tree. - for(size_t ui=0;ui<=numFrames;ui++) - { - bool needsUp; - //steal tree from viscontrol - visControl.swapFilterTree(origTree); - - //Modify the tree, as needed - if(!exportDialog->getModifiedTree(ui,origTree,needsUp)) - { - std::string s; - stream_cast(ui,s); - s = TRANS("Filter property change failed") + s; - wxMessageDialog *wxMesD =new wxMessageDialog(this,wxStr(s), - wxTRANS("Filter change error"),wxOK|wxICON_ERROR); - wxMesD->ShowModal(); - - wxMesD->Destroy(); - setLockUI(false); - panelTop->Enable(true); - return; - } - - //restore tree to viscontrol - visControl.swapFilterTree(origTree); - - if(needsUp || !exportDialog->wantsOnlyChanges()) - { - typedef std::pair > PAIR_STREAMOUT; - typedef std::vector STREAMOUT; - std::list outData; - std::list outStreams; - - //First try to refresh the tree - if(visControl.refreshFilterTree(outData)) - { - std::string errMesg,tmpStr; - stream_cast(tmpStr,ui); - errMesg=TRANS("Refresh failed on frame :") + tmpStr; - - wxErrMsg(this,TRANS("Refresh failed"),errMesg); - - currentlyUpdatingScene=false; - setLockUI(false); - panelTop->Enable(true); - return; - } - - - //Now update the scene, if needed - for(list::iterator it=outData.begin(); - it!=outData.end();++it) - outStreams.push_back(it->second); - - - try - { - if(exportDialog->wantsImages()) - { - //update the output streams, but do not release - // the contents. - if(visControl.doUpdateScene(outStreams,false)) - { - pair errMsg; - string tmpStr; - stream_cast(tmpStr,ui); - errMsg.first=TRANS("Scene generation failed"); - errMsg.second = TRANS("Unable to generate scene for frame "); - errMsg.second+=tmpStr; - throw errMsg; - } - else - { - if(!panelTop->saveImage(exportDialog->getImageWidth(), - exportDialog->getImageHeight(), - exportDialog->getFilename(ui,FILENAME_IMAGE).c_str())) - { - pair errMsg; - string tmpStr; - stream_cast(tmpStr,ui); - errMsg.first=TRANS("Unable to save"); - errMsg.second = TRANS("Image save failed for frame "); - errMsg.second+=tmpStr; - throw errMsg; - } - } - } - - if(exportDialog->wantsIons()) - { - //merge all the output streams into one - vector mergedStreams; - for(list::iterator it=outStreams.begin(); - it!=outStreams.end();++it) - { - size_t origSize; - origSize=mergedStreams.size(); - mergedStreams.resize( origSize+ it->size()); - std::copy(it->begin(),it->end(),mergedStreams.begin() +origSize); - } - - if(visControl.exportIonStreams(mergedStreams,exportDialog->getFilename(ui,FILENAME_IONS))) - { - pair errMsg; - string tmpStr; - stream_cast(tmpStr,ui); - errMsg.first=TRANS("Ion save failed"); - errMsg.second = TRANS("Unable to save ions for frame "); - errMsg.second+=tmpStr; - throw errMsg; - } - } - - if(exportDialog->wantsPlots()) - { - - size_t plotNumber=0; - //Save each plot by name, where possible - for(list::iterator it=outStreams.begin(); it!=outStreams.end();++it) - { - for(size_t uj=0;ujsize();uj++) - { - //Skip non plot output - if((*it)[uj]->getStreamType() != STREAM_TYPE_PLOT ) - continue; - - //Save the plot output - std::string filename; - const PlotStreamData* p = (const PlotStreamData*)(*it)[uj]; - filename = exportDialog->getFilename(ui,FILENAME_PLOT,plotNumber); - - plotNumber++; - - if(!p->save(filename.c_str())) - { - pair errMsg; - string tmpStr; - stream_cast(tmpStr,ui); - errMsg.first=TRANS("Plot save failed"); - errMsg.second = TRANS("Unable to save plot or frame "); - errMsg.second+=tmpStr; - throw errMsg; - - } - - } - - } - } - - if(exportDialog->wantsRanges()) - { - size_t rangeNum=0; - - //TODO: Integrate enums for rangefiles? - map rangeEnumMap; - rangeEnumMap[RANGE_OAKRIDGE] = RANGE_FORMAT_ORNL; - rangeEnumMap[RANGE_AMETEK_RRNG] = RANGE_FORMAT_RRNG; - rangeEnumMap[RANGE_AMETEK_ENV] = RANGE_FORMAT_ENV; - //Save each range - for(list::iterator it=outStreams.begin(); it!=outStreams.end();++it) - { - for(size_t uj=0;ujsize();uj++) - { - //Skip non plot output - if((*it)[uj]->getStreamType() != STREAM_TYPE_RANGE) - continue; - - //Save the plot output - std::string filename; - const RangeStreamData* p = (const RangeStreamData*)(*it)[uj]; - filename = exportDialog->getFilename(ui,FILENAME_RANGE,rangeNum); - - size_t format; - format=rangeEnumMap.at(exportDialog->getRangeFormat()); - - if(!p->save(filename.c_str(),format)) - { pair errMsg; - string tmpStr; - stream_cast(tmpStr,ui); - errMsg.first=TRANS("Range save failed"); - errMsg.second = TRANS("Unable to save range for frame "); - - throw errMsg; - } - - } - } - } - - - if(exportDialog->wantsVoxels()) - { - size_t offset=0; - for(list::iterator it=outStreams.begin(); it!=outStreams.end();++it) - { - for(size_t uj=0;ujsize();uj++) - { - if( ((*it)[uj])->getStreamType() != STREAM_TYPE_VOXEL) - continue; - - const VoxelStreamData *v; - v=(const VoxelStreamData*)(*it)[uj]; - - std::string filename = exportDialog->getFilename(ui,FILENAME_VOXEL,offset); - if(v->data.writeFile(filename.c_str())) - { - pair errMsg; - string tmpStr; - stream_cast(tmpStr,ui); - errMsg.first=TRANS("Voxel save failed"); - errMsg.second = TRANS("Unable to save voxels for frame "); - errMsg.second+=tmpStr; - throw errMsg; - } - - offset++; - } - } - } - } - catch(std::pair errMsg) - { - //Display an error dialog to the user - wxErrMsg(this,errMsg.first,errMsg.second); - - //clean up data - visControl.safeDeleteFilterList(outData); - exportDialog->Destroy(); - currentlyUpdatingScene=false; - setLockUI(false); - panelTop->Enable(true); - - return; - } - - //Clean up date from this run, releasing stream pointers. - visControl.safeDeleteFilterList(outData); - outStreams.clear(); - } - - } - - currentlyUpdatingScene=false; - exportDialog->Destroy(); - setLockUI(false); - panelTop->Enable(true); - -} - -void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event) -{ - if(!treeFilters->GetCount()) - { - statusMessage(TRANS("No filters means no data to export"),MESSAGE_ERROR); - return; - - } - - //This could be nicer, or reordered - wxTextEntryDialog *wxT = new wxTextEntryDialog(this,wxTRANS("Package name"), - wxTRANS("Package directory name"),wxT(""),wxOK|wxCANCEL); - - wxT->SetValue(wxTRANS("AnalysisPackage")); - - if(wxT->ShowModal() == wxID_CANCEL) - { - wxT->Destroy(); - return; - } - - - //Pop up a directory dialog, to choose the base path for the new folder - wxDirDialog *wxD = new wxDirDialog(this); - - wxMessageDialog *wxMesD =new wxMessageDialog(this,wxTRANS("Package folder already exists, won't overwrite.") - ,wxTRANS("Not available"),wxOK|wxICON_ERROR); - - unsigned int res; - res = wxD->ShowModal(); - while(res != wxID_CANCEL) - { - //Dir cannot exist yet, as we want to make it. - if(wxDirExists(wxD->GetPath() + wxT->GetValue())) - { - wxMesD->ShowModal(); - res=wxD->ShowModal(); - } - else - break; - } - wxMesD->Destroy(); - - //User aborted directory choice. - if(res==wxID_CANCEL) - { - wxD->Destroy(); - wxT->Destroy(); - return; - } - - wxString folder; - folder=wxD->GetPath() + wxFileName::GetPathSeparator() + wxT->GetValue() + - wxFileName::GetPathSeparator(); - //Check to see that the folder actually exists - if(!wxMkdir(folder)) - { - wxMessageDialog *wxMesD =new wxMessageDialog(this,wxTRANS("Package folder creation failed\ncheck writing to this location is possible.") - ,wxTRANS("Folder creation failed"),wxOK|wxICON_ERROR); - - wxMesD->ShowModal(); - wxMesD->Destroy(); - - return; - } - - - //OK, so the folder exists, lets make the XML state file - std::string dataFile = string(stlStr(folder)) + "state.xml"; - - std::map fileMapping; - //Try to save the viscontrol state - if(!visControl.saveState(dataFile.c_str(),fileMapping,true)) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - else - { - //Copy the files in the mapping - wxProgressDialog *wxP = new wxProgressDialog(wxTRANS("Copying"), - wxTRANS("Copying referenced files"),fileMapping.size()); - - wxP->Show(); - for(map::iterator it=fileMapping.begin(); - it!=fileMapping.end();++it) - { - if(!wxCopyFile(wxStr(it->second),folder+wxStr(it->first))) - { - wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("Error copying file") - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - wxP->Destroy(); - - return; - } - wxP->Update(); - } - - wxP->Destroy(); - - - wxString s; - s=wxString(wxTRANS("Saved package: ")) + folder; - statusMessage(stlStr(s).c_str(),MESSAGE_INFO); - } - - wxD->Destroy(); -} - -void MainWindowFrame::OnFileExportIons(wxCommandEvent &event) -{ - if(!treeFilters->GetCount()) - { - statusMessage(TRANS("No filters means no data to export"),MESSAGE_ERROR); - return; - - } - - //Steal the filter tree (including caches) from viscontrol - FilterTree f; - visControl.switchoutFilterTree(f); - - //Load up the export dialog - ExportPosDialog *exportDialog=new ExportPosDialog(this,wxID_ANY,wxTRANS("Export")); - exportDialog->initialiseData(f); - - //create a file chooser for later. - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save pos..."), wxT(""), - wxT(""),wxTRANS("POS Data (*.pos)|*.pos|All Files (*)|*"),wxFD_SAVE); - - //If the user cancels the file chooser, - //drop them back into the export dialog. - do - { - //Show, then check for user cancelling export dialog - if(exportDialog->ShowModal() == wxID_CANCEL) - { - //Take control of the filter tree back from the export dialog, - // and return it to visControl - exportDialog->swapFilterTree(f); - visControl.swapFilterTree(f); - exportDialog->Destroy(); - - //Need this to reset the ID values - visControl.updateWxTreeCtrl(treeFilters); - return; - } - - } - while( (wxF->ShowModal() == wxID_CANCEL)); //Check for user abort in file chooser - - - - //Check file already exists (no overwrite without asking) - if(wxFileExists(wxF->GetPath())) - { - wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("File already exists, overwrite?") - ,wxTRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION); - if(wxD->ShowModal() == wxID_CANCEL) - { - wxD->Destroy(); - - //Take control of the filter tree back from the export dialog, - // and return it to visControl - exportDialog->swapFilterTree(f); - visControl.swapFilterTree(f); - - //Need this to reset the ID values - visControl.updateWxTreeCtrl(treeFilters); - exportDialog->Destroy(); - return; - } - } - - std::string dataFile = stlStr(wxF->GetPath()); - - //Retrieve the ion streams that we need to save - vector exportVec; - exportDialog->getExportVec(exportVec); - - - //write the ion streams to disk - if(visControl.exportIonStreams(exportVec,dataFile)) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - else - { - dataFile=std::string(TRANS("Saved ions: ")) + dataFile; - statusMessage(dataFile.c_str(),MESSAGE_INFO); - } - - //Take control of the filter tree back from the export dialog, - // and return it to visControl - exportDialog->swapFilterTree(f); - visControl.swapFilterTree(f); - - //Call ->Destroy to invoke destructor, which will safely delete the - //filterstream pointers it generated - exportDialog->Destroy(); - //Need this to reset the ID values - visControl.updateWxTreeCtrl(treeFilters); -} - -void MainWindowFrame::OnFileExportRange(wxCommandEvent &event) -{ - - if(!treeFilters->GetCount()) - { - statusMessage(TRANS("No filters means no data to export"), - MESSAGE_ERROR); - return; - } - ExportRngDialog *rngDialog = new ExportRngDialog(this,wxID_ANY,wxTRANS("Export Ranges"), - wxDefaultPosition,wxSize(600,400)); - - vector rangeData; - //Retrieve all the range filters in the viscontrol - visControl.getFiltersByType(rangeData,FILTER_TYPE_RANGEFILE); - //pass this to the range dialog - rngDialog->addRangeData(rangeData); - - if(rngDialog->ShowModal() == wxID_CANCEL) - { - rngDialog->Destroy(); - return; - } - - - -} - - -void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event) -{ - //Show a file save dialog - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save state..."), wxT(""), - wxT(""),wxTRANS("XML state file (*.xml)|*.xml|All Files (*)|*"),wxFD_SAVE); - - //Show, then check for user cancelling dialog - if( (wxF->ShowModal() == wxID_CANCEL)) - return; - - std::string dataFile = stlStr(wxF->GetPath()); - - wxFileName fname; - wxString volume,path,name,ext; - bool hasExt; - fname.SplitPath(wxF->GetPath(),&volume, - &path,&name,&ext, &hasExt); - - //Check file already exists (no overwrite without asking) - if(wxFileExists(wxF->GetPath())) - { - wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("File already exists, overwrite?") - ,wxTRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION); - if(wxD->ShowModal() == wxID_CANCEL) - { - wxD->Destroy(); - return; - } - } - if(hasExt) - { - //Force the string to end in ".xml" - std::string strExt; - strExt=stlStr(ext); - strExt = lowercase(strExt); - if(strExt != "xml") - dataFile+=".xml"; - } - else - dataFile+=".xml"; - - - bool oldRelPath=visControl.usingRelPaths(); - //Check to see if we have are using relative paths, - //and if so, do any of our filters - if(visControl.usingRelPaths() && visControl.hasStateOverrides()) - { - wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("Files have been referred to using relative paths. Keep relative paths?") - ,wxTRANS("Overwrite?"),wxYES|wxNO|wxICON_QUESTION); - - wxD->SetEscapeId(wxID_NO); - wxD->SetAffirmativeId(wxID_YES); - //Just for the moment, set relative paths to false, if the user asks. - //we will restore this later - if(wxD->ShowModal() == wxID_NO) - { - oldRelPath=true; - visControl.setUseRelPaths(false); - } - - } - - - std::map dummyMap; - //Try to save the viscontrol state - if(!visControl.saveState(dataFile.c_str(),dummyMap)) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - } - else - { - currentFile = wxF->GetPath(); - fileSave->Enable(true); - - //Update the recent files, and the menu. - configFile.addRecentFile(dataFile); - recentHistory->AddFileToHistory(wxStr(dataFile)); - - dataFile=std::string(TRANS("Saved state: ")) + dataFile; - statusMessage(dataFile.c_str(),MESSAGE_INFO); - } - - //Restore the relative path behaviour - visControl.setUseRelPaths(oldRelPath); -} - - -void MainWindowFrame::OnFileExit(wxCommandEvent &event) -{ - //Close query is handled by OnClose() - Close(); -} - -void MainWindowFrame::OnEditUndo(wxCommandEvent &event) -{ - visControl.popUndoStack(); - - //Update tree control - visControl.updateWxTreeCtrl(treeFilters); - - //Get the parent filter from the tree selection - wxTreeItemId id=treeFilters->GetSelection(); - if(id !=treeFilters->GetRootItem() && id.IsOk()) - { - //Get the parent filter pointer - wxTreeItemData *parentData=treeFilters->GetItemData(id); - //Update property grid - visControl.updateFilterPropGrid(gridFilterPropGroup, - ((wxTreeUint *)parentData)->value); - - } - else - { - gridFilterPropGroup->clear(); - updateLastRefreshBox(); - } - - - - doSceneUpdate(); -} - -void MainWindowFrame::OnEditRedo(wxCommandEvent &event) -{ - visControl.popRedoStack(); - - //Update tree control - visControl.updateWxTreeCtrl(treeFilters); - - //Get the parent filter from the tree selection - wxTreeItemId id=treeFilters->GetSelection(); - if(id !=treeFilters->GetRootItem() && id.IsOk()) - { - //Get the parent filter pointer - wxTreeItemData *parentData=treeFilters->GetItemData(id); - //Update property grid - visControl.updateFilterPropGrid(gridFilterPropGroup, - ((wxTreeUint *)parentData)->value); - - } - else - { - gridFilterPropGroup->clear(); - updateLastRefreshBox(); - } - - - - doSceneUpdate(); -} - -void MainWindowFrame::OnEditPreferences(wxCommandEvent &event) -{ - //Create a new preference dialog - PrefDialog *p = new PrefDialog(this); - - vector filterDefaults; - - //obtain direct copies of the cloned Filter pointers - configFile.getFilterDefaults(filterDefaults); - p->setFilterDefaults(filterDefaults); - - //Get the default mouse parameters - unsigned int mouseZoomRate,mouseMoveRate; - mouseZoomRate=configFile.getMouseZoomRate(); - mouseMoveRate=configFile.getMouseMoveRate(); - - - unsigned int panelMode; - - //Set Panel startup flags - bool rawStartup,controlStartup,plotStartup; - controlStartup=configFile.getPanelEnabled(CONFIG_STARTUPPANEL_CONTROL); - rawStartup=configFile.getPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA); - plotStartup=configFile.getPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST); - - panelMode=configFile.getStartupPanelMode(); - - p->setPanelDefaults(panelMode,controlStartup,rawStartup,plotStartup); - -#ifndef DISABLE_ONLINE_UPDATE - p->setAllowOnlineUpdate(configFile.getAllowOnlineVersionCheck()); -#endif - - - p->setMouseZoomRate(mouseZoomRate); - p->setMouseMoveRate(mouseMoveRate); - - //Initialise panel - p->initialise(); - //show panel - if(p->ShowModal() !=wxID_OK) - { - p->cleanup(); - p->Destroy(); - return; - } - - filterDefaults.clear(); - - //obtain cloned copies of the pointers - p->getFilterDefaults(filterDefaults); - - mouseZoomRate=p->getMouseZoomRate(); - mouseMoveRate=p->getMouseMoveRate(); - - panelTop->setMouseZoomFactor((float)mouseZoomRate/100.0f); - panelTop->setMouseMoveFactor((float)mouseMoveRate/100.0f); - - configFile.setMouseZoomRate(mouseZoomRate); - configFile.setMouseMoveRate(mouseMoveRate); - - //Note that this transfers control of pointer to the config file - configFile.setFilterDefaults(filterDefaults); - - //Retrieve pane settings, and pass to config manager - p->getPanelDefaults(panelMode,controlStartup,rawStartup,plotStartup); - - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,controlStartup,true); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,rawStartup,true); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,plotStartup,true); - - configFile.setStartupPanelMode(panelMode); - -#ifndef DISABLE_ONLINE_UPDATE - configFile.setAllowOnline(p->getAllowOnlineUpdate()); - configFile.setAllowOnlineVersionCheck(p->getAllowOnlineUpdate()); -#endif - p->cleanup(); - p->Destroy(); -} - -void MainWindowFrame::OnViewBackground(wxCommandEvent &event) -{ - - //retrieve the current colour from the openGL panel - float r,g,b; - panelTop->getGlClearColour(r,g,b); - //Show a wxColour choose dialog. - wxColourData d; - d.SetColour(wxColour((unsigned char)(r*255),(unsigned char)(g*255), - (unsigned char)(b*255),(unsigned char)(255))); - wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); - - if( colDg->ShowModal() == wxID_OK) - { - wxColour c; - //Change the colour - c=colDg->GetColourData().GetColour(); - - //Scale colour ranges to 0-> 1 and set in the gl pane - panelTop->setGlClearColour(c.Red()/255.0f,c.Green()/255.0f,c.Blue()/255.0f); - } -} - -void MainWindowFrame::OnViewControlPane(wxCommandEvent &event) -{ - if(event.IsChecked()) - { - if(!splitLeftRight->IsSplit()) - { - const float SPLIT_FACTOR=0.3; - int x,y; - GetClientSize(&x,&y); - splitLeftRight->SplitVertically(panelLeft, - panelRight,(int)(SPLIT_FACTOR*x)); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,true); - - } - } - else - { - if(splitLeftRight->IsSplit()) - { - splitLeftRight->Unsplit(panelLeft); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,false); - } - } -} - - -void MainWindowFrame::OnViewRawDataPane(wxCommandEvent &event) -{ - if(event.IsChecked()) - { - if(!splitTopBottom->IsSplit()) - { - const float SPLIT_FACTOR=0.3; - - int x,y; - GetClientSize(&x,&y); - splitTopBottom->SplitHorizontally(panelTop, - noteDataView,(int)(SPLIT_FACTOR*x)); - - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,true); - } - } - else - { - if(splitTopBottom->IsSplit()) - { - splitTopBottom->Unsplit(); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,false); - } - } -} - -void MainWindowFrame::OnViewSpectraList(wxCommandEvent &event) -{ - if(event.IsChecked()) - { - if(!splitterSpectra->IsSplit()) - { - const float SPLIT_FACTOR=0.6; - - int x,y; - splitterSpectra->GetClientSize(&x,&y); - splitterSpectra->SplitVertically(panelSpectra, - window_2_pane_2,(int)(SPLIT_FACTOR*x)); - - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,true); - } - } - else - { - if(splitterSpectra->IsSplit()) - { - splitterSpectra->Unsplit(); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,false); - } - } -} - -void MainWindowFrame::OnViewPlotLegend(wxCommandEvent &event) -{ - panelSpectra->setLegendVisible(event.IsChecked()); - panelSpectra->Refresh(); -} - -void MainWindowFrame::OnViewWorldAxis(wxCommandEvent &event) -{ - panelTop->currentScene.setWorldAxisVisible(event.IsChecked()); - panelTop->Refresh(); -} - -void MainWindowFrame::OnHelpHelp(wxCommandEvent &event) -{ - //First attempt to locate the local copy of the manual. - string s; - s=locateDataFile("3Depict-manual.pdf"); - - //Also Debian makes us use the lowercase "D", so check there too. - if(!s.size()) - s=locateDataFile("3depict-manual.pdf"); - - - //If we found it, use the default program associated with that data file - bool launchedOK=false; - if( wxFileExists(wxStr(s)) && s.size()) - { - //we found the manual. Launch the default handler. -#if wxCHECK_VERSION(2, 9, 0) - launchedOK=wxLaunchDefaultApplication(wxStr(s)); -#else - //its a bit more convoluted for earlier versions of wx. - //we have to try xdg-open or open for Linux and mac respectively - //for windows, we need to use the wxWidgets GetOpenCommand - - long appPID; - - #if defined(__linux__) - //Try xdg-open first - wxString str; - str= wxT("xdg-open "); - str+=wxStr(s); - appPID=wxExecute(str,wxEXEC_ASYNC); - launchedOK=(appPID!=0); - #elif defined(__APPLE__) - //Try open first - wxString str; - str= wxT("open "); - str+=wxStr(s); - appPID=wxExecute(str,wxEXEC_ASYNC); - launchedOK=(appPID!=0); - #endif - - //No luck still? Try wx's quirky GetOpenCommand - if(!launchedOK) - { - wxString command; - //Sigh. In version < 2.9; wx uses the mime-type - //manager to wrap up the construction - //of wxFileType object (private constructor). - //so we can't just *make* a wxFileType - //we have to derive one from a "mime-type manager". - //the only way to do this is from the file extension - //or by passing the mime-string. - wxMimeTypesManager m; - wxFileType *t; - - t=m.GetFileTypeFromExtension(wxT("pdf")); - command=t->GetOpenCommand(wxStr(s)); - appPID=wxExecute(command,wxEXEC_ASYNC); - launchedOK=(appPID!=0); - } -#endif - } - - //Still no go? Give up and launch a browser. - if(!launchedOK) - { - std::string helpFileLocation("http://threedepict.sourceforge.net/documentation.html"); - wxLaunchDefaultBrowser(wxStr(helpFileLocation),wxBROWSER_NEW_WINDOW); - - statusMessage(TRANS("Manual not found locally. Launching web browser"),MESSAGE_INFO); - } -} - -void MainWindowFrame::OnHelpContact(wxCommandEvent &event) -{ - std::string contactFileLocation("http://threedepict.sourceforge.net/contact.html"); - wxLaunchDefaultBrowser(wxStr(contactFileLocation),wxBROWSER_NEW_WINDOW); - - statusMessage(TRANS("Opening contact page in external web browser"),MESSAGE_INFO); -} - -void MainWindowFrame::OnButtonStashDialog(wxCommandEvent &event) -{ - std::vector > stashVec; - visControl.getStashes(stashVec); - - ASSERT(comboStash->GetCount() == stashVec.size()) - - if(stashVec.empty()) - { - statusMessage(TRANS("No filter stashes to edit."),MESSAGE_ERROR); - return; - } - - StashDialog *s = new StashDialog(this,wxID_ANY,wxTRANS("Filter Stashes")); - s->setVisController(&visControl); - s->ready(); - s->ShowModal(); - - s->Destroy(); - - //Stash list may have changed. Force update - stashVec.clear(); - visControl.getStashes(stashVec); - - comboStash->Clear(); - for(unsigned int ui=0;uiAppend(wxStr(stashVec[ui].first),(wxClientData *)u); - ASSERT(comboStash->GetClientObject(comboStash->GetCount()-1)); - } - - -} - - -void MainWindowFrame::OnHelpAbout(wxCommandEvent &event) -{ - wxAboutDialogInfo info; - info.SetName(wxCStr(PROGRAM_NAME)); - info.SetVersion(wxCStr(PROGRAM_VERSION)); - info.SetDescription(wxTRANS("Quick and dirty analysis for point data.")); - info.SetWebSite(wxT("https://sourceforge.net/apps/phpbb/threedepict/")); - - info.AddDeveloper(wxT("D. Haley")); - info.AddDeveloper(wxT("A. Ceguerra")); - //GNU GPL v3 - info.SetCopyright(_T("Copyright (C) 2011 3Depict team\n This software is licenced under the GPL Version 3.0 or later\n This program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions; Please see the file COPYING in the program directory for details")); - - info.AddArtist(_T("Thanks go to all who have developed the libraries that I use, which make this program possible.\n This includes the wxWidgets team, Alexy Balakin (MathGL), the FTGL and freetype people, the GNU Scientific Library contributors, the tree.h guy (Kasper Peeters) and more.")); - - info.AddArtist(wxString(wxTRANS("Compiled with wx Version: " )) + - wxString(wxSTRINGIZE_T(wxVERSION_STRING))); - - wxArrayString s; - s.Add(_T("Deutsch (German) : Erich (de)")); - info.SetTranslators(s); - - wxAboutBox(info); -} - - -void MainWindowFrame::OnComboStashText(wxCommandEvent &event) -{ - std::string s; - s=stlStr(comboStash->GetValue()); - if(!s.size()) - return; - - int n = comboStash->FindString(comboStash->GetValue()); - - if ( n== wxNOT_FOUND ) - statusMessage(TRANS("Press enter to store new stash"),MESSAGE_HINT); - else - { - //The combo generates an ontext event when a string - //is selected (yeah, I know, weird..) Block this case. - if(comboStash->GetSelection() != n) - statusMessage(TRANS("Press enter to restore stash"),MESSAGE_HINT); - } -} - -void MainWindowFrame::OnComboStashEnter(wxCommandEvent &event) -{ - //The user has pressed enter, in the combo box. If there is an existing stash of this name, - //use it. Otherwise store the current tree control as part of the new stash - std::string userText; - - userText=stlStr(comboStash->GetValue()); - - //Forbid names with no text content - userText=stripWhite(userText); - if(!userText.size()) - return; - - std::vector > stashList; - visControl.getStashes(stashList); - - unsigned int stashPos = (unsigned int ) -1; - for(unsigned int ui=0;uiGetSelection(); - //If there is a problem with the selection, abort - if(!id.IsOk() || (id == treeFilters->GetRootItem())) - { - statusMessage(TRANS("Unable to create stash, selection invalid"),MESSAGE_ERROR); - return; - } - - - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - - unsigned int n =visControl.stashFilters(((wxTreeUint *)tData)->value,userText.c_str()); - n=comboStash->Append(wxStr(userText),(wxClientData *)new wxListUint(n)); - ASSERT(comboStash->GetClientObject(n)); - - statusMessage(TRANS("Created new filter tree stash"),MESSAGE_INFO); - - } - else - { - //Found it. Restore the existing stash - //Find the stash associated with this item - int index; - index= comboStash->FindString(comboStash->GetValue()); - ASSERT(index != wxNOT_FOUND); - wxListUint *l; - l =(wxListUint*)comboStash->GetClientObject(index); - //Get the parent filter from the tree selection - wxTreeItemId id=treeFilters->GetSelection(); - if(id !=treeFilters->GetRootItem() && id.IsOk()) - { - //Get the parent filter pointer - wxTreeItemData *parentData=treeFilters->GetItemData(id); - const Filter *parentFilter=(const Filter *)visControl.getFilterById( - ((wxTreeUint *)parentData)->value); - - visControl.addStashedToFilters(parentFilter,l->value); - - visControl.updateWxTreeCtrl(treeFilters, - parentFilter); - - statusMessage("",MESSAGE_NONE); - if(checkAutoUpdate->GetValue()) - doSceneUpdate(); - - } - - //clear the text in the combo box - comboStash->SetValue(wxT("")); - } - - //clear the text in the combo box - comboStash->SetValue(wxT("")); -} - - -void MainWindowFrame::OnComboStash(wxCommandEvent &event) -{ - //Find the stash associated with this item - wxListUint *l; - l =(wxListUint*)comboStash->GetClientObject(comboStash->GetSelection()); - //Get the parent filter from the tree selection - wxTreeItemId id=treeFilters->GetSelection(); - if(id !=treeFilters->GetRootItem() && id.IsOk()) - { - //Get the parent filter pointer - wxTreeItemData *parentData=treeFilters->GetItemData(id); - const Filter *parentFilter=(const Filter *)visControl.getFilterById( - ((wxTreeUint *)parentData)->value); - - visControl.addStashedToFilters(parentFilter,l->value); - - visControl.updateWxTreeCtrl(treeFilters, - parentFilter); - - if(checkAutoUpdate->GetValue()) - doSceneUpdate(); - - - } - - //clear the text in the combo box - comboStash->SetValue(wxT("")); -} - - - -void MainWindowFrame::OnTreeEndDrag(wxTreeEvent &event) -{ - - if(visControl.isRefreshing() ) - { - event.Veto(); - return; - } - - //Should be enforced by ::Allow() in start drag. - ASSERT(filterTreeDragSource && filterTreeDragSource->IsOk()); - //Allow tree to be manhandled, so you can move filters around - wxTreeItemId newParent = event.GetItem(); - - bool needRefresh=false; - size_t sId; - wxTreeItemData *sourceDat=treeFilters->GetItemData(*filterTreeDragSource); - sId = ((wxTreeUint *)sourceDat)->value; - - wxMouseState wxm = wxGetMouseState(); - - //if we have a parent node to reparent this to - if(newParent.IsOk()) - { - size_t pId; - wxTreeItemData *parentDat=treeFilters->GetItemData(newParent); - pId = ((wxTreeUint *)parentDat)->value; - //Copy elements from a to b, if a and b are not the same - if(pId != sId) - { - visControl.setWxTreeFilterViewPersistence(sId); - visControl.setWxTreeFilterViewPersistence(pId); - //If command button down (ctrl or clover on mac), - //then copy, otherwise move - if(wxm.CmdDown()) - needRefresh=visControl.copyFilter(sId,pId); - else - needRefresh=visControl.reparentFilter(sId,pId); - } - } - else - { - //Only filters that are a data source are allowed to be in the base. - if( visControl.filterIsPureDataSource(sId)) - { - if(wxm.CmdDown()) - needRefresh=visControl.copyFilter(sId,0); - else - needRefresh=visControl.reparentFilter(sId,0); - } - else - statusMessage(TRANS("Filter type not a data source - can't be at tree base"),MESSAGE_ERROR); - } - - if(needRefresh ) - { - //Refresh the treecontrol - visControl.updateWxTreeCtrl(treeFilters); - - //We have finished the drag - statusMessage("",MESSAGE_NONE); - if(checkAutoUpdate->GetValue()) - doSceneUpdate(); - } - delete filterTreeDragSource; - filterTreeDragSource=0; -} - - -void MainWindowFrame::OnTreeSelectionChange(wxTreeEvent &event) -{ - wxTreeItemId id; - id=treeFilters->GetSelection(); - - if(currentlyUpdatingScene) - { - event.Veto(); - return; - } - - if(!id.IsOk() || id == treeFilters->GetRootItem()) - { - gridFilterPropGroup->clear(); - return; - } - - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - - visControl.updateFilterPropGrid(gridFilterPropGroup, - ((wxTreeUint *)tData)->value); - - - updateLastRefreshBox(); - - - treeFilters->Fit(); - panelTop->Refresh(); - -} - - -void MainWindowFrame::updateLastRefreshBox() -{ - wxTreeItemId id; - id=treeFilters->GetSelection(); - if(id.IsOk() && id != treeFilters->GetRootItem()) - { - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - //retrieve the current active filter - const Filter *f= visControl.getFilterById(((wxTreeUint *)tData)->value); - - //Prevent update flicker by disabling interaction - listLastRefresh->Freeze(); - - listLastRefresh->DeleteAllItems(); - for(unsigned int ui=0;uigetNumOutput(ui); - if(numOut) - { - long index; - stream_cast(n,numOut); - index=listLastRefresh->InsertItem(0,wxCStr(TRANS(STREAM_NAMES[ui]))); - listLastRefresh->SetItem(index,1,wxStr(n)); - } - } - listLastRefresh->Thaw(); - } -} - -void MainWindowFrame::OnTreeDeleteItem(wxTreeEvent &event) -{ - if(visControl.isRefreshing() ) - { - event.Veto(); - return; - } - //This event is only generated programatically, - //Currently it *purposely* does nothing in the - //not updating case -} - -void MainWindowFrame::OnTreeBeginLabelEdit(wxTreeEvent &event) -{ - if(visControl.isRefreshing() ) - { - event.Veto(); - return; - } -} - -void MainWindowFrame::OnTreeEndLabelEdit(wxTreeEvent &event) -{ - if(event.IsEditCancelled()) - { - treeFilters->Fit(); - return; - } - - wxTreeItemId id; - id=treeFilters->GetSelection(); - - wxTreeItemData *selItemDat=treeFilters->GetItemData(id); - - - //There is a case where the tree doesn't quite clear - //when there is an editor involved. - if(visControl.numFilters()) - { - std::string s; - s=stlStr(event.GetLabel()); - if(s.size()) - { - - //If the string has been changed, then we need to update - if(visControl.setFilterString(((wxTreeUint *)selItemDat)->value,s)) - { - //We need to reupdate the scene, in order to re-fill the - //spectra list box - doSceneUpdate(); - } - } - else - { - event.Veto(); // Disallow blank strings. - } - } - - treeFilters->Fit(); -} - -void MainWindowFrame::OnTreeBeginDrag(wxTreeEvent &event) -{ - if(visControl.isRefreshing() ) - { - event.Veto(); - return; - } - - //No dragging if editing, or if no filters - if(treeFilters->GetEditControl() || event.GetItem() == treeFilters->GetRootItem()) - { - event.Veto(); - return; - } - - //Record the drag source - wxTreeItemId t = event.GetItem(); - - if(t.IsOk()) - { - filterTreeDragSource = new wxTreeItemId; - *filterTreeDragSource =t; - event.Allow(); - -#ifdef __APPLE__ - statusMessage(TRANS("Moving - Hold ⌘ (command) to copy"),MESSAGE_HINT); -#else - statusMessage(TRANS("Moving - Hold control to copy"),MESSAGE_HINT); -#endif - } - -} - -void MainWindowFrame::OnBtnExpandTree(wxCommandEvent &event) -{ - treeFilters->ExpandAll(); -} - - -void MainWindowFrame::OnBtnCollapseTree(wxCommandEvent &event) -{ - treeFilters->CollapseAll(); -} - -void MainWindowFrame::OnBtnFilterTreeErrs(wxCommandEvent &event) -{ - - //Grab the error strings - vector res; - visControl.getAnalysisResults(res); - - ASSERT(res.size()); - - vector errStrings; - - for(unsigned int ui=0;uigetUserString() + "\n"; - } - - errStrings.push_back(s); - s.clear(); - - } - res.clear(); - - FilterErrorDialog *f= new FilterErrorDialog(this); - f->SetText(errStrings); - - f->ShowModal(); - - delete f; - -} - -void MainWindowFrame::OnTreeKeyDown(wxTreeEvent &event) -{ - if(currentlyUpdatingScene) - { - event.Veto(); - return; - } - const wxKeyEvent k = event.GetKeyEvent(); - switch(k.GetKeyCode()) - { - case WXK_BACK: - case WXK_DELETE: - { - wxTreeItemId id; - - if(!treeFilters->GetCount()) - return; - - id=treeFilters->GetSelection(); - - if(!id.IsOk() || id == treeFilters->GetRootItem()) - return; - - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - - - - //Rebuild the tree control, ensuring that the parent is visible, - //if it has a parent (recall root node of wx control is hidden) - - //Get the parent & its data - wxTreeItemId parent = treeFilters->GetItemParent(id); - wxTreeItemData *parentData=treeFilters->GetItemData(parent); - - //Ask viscontrol to ensure that the tree stays persistantly - // visible when next rebuilding the tree control - visControl.setWxTreeFilterViewPersistence( - ((wxTreeUint*)parentData)->value); - - //Remove the item from the Tree - visControl.removeFilterSubtree(((wxTreeUint *)tData)->value); - //Clear property grid - gridFilterPropGroup->clear(); - if(parent !=treeFilters->GetRootItem()) - { - ASSERT(parent.IsOk()); // should be - base node should always exist. - - //Ensure that the parent stays visible - visControl.setWxTreeFilterViewPersistence( - ((wxTreeUint*)parentData)->value); - visControl.updateWxTreeCtrl(treeFilters); - - - //OK, so those old Id s are no longer valid, - //as we just rebuilt the tree. We need new ones - //Parent is now selected - parent=treeFilters->GetSelection(); - parentData=treeFilters->GetItemData(parent); - - - //Update the filter property grid with the parent's data - visControl.updateFilterPropGrid(gridFilterPropGroup, - ((wxTreeUint *)parentData)->value); - } - else - { - if(parent.IsOk()) - visControl.updateWxTreeCtrl(treeFilters); - } - - //Force a scene update, independent of if autoUpdate is enabled. - doSceneUpdate(); - - break; - } - default: - event.Skip(); - } - - - refreshButton->Enable(visControl.numFilters()); - - editUndoMenuItem->Enable(visControl.getUndoSize()); - editRedoMenuItem->Enable(visControl.getRedoSize()); -} - -void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event) -{ - - if(programmaticEvent || currentlyUpdatingScene) - { - event.Veto(); - return; - } - - programmaticEvent=true; - //Should only be in the second col - ASSERT(event.GetCol()==1); - - std::string value; - value = stlStr(gridFilterPropGroup->GetCellValue( - event.GetRow(),1)); - - //Get the filter ID value (long song and dance that it is) - wxTreeItemId tId = treeFilters->GetSelection(); - - if(!tId.IsOk()) - { - programmaticEvent=false; - return; - } - - ASSERT(tId!=treeFilters->GetRootItem()); - - size_t filterId; - wxTreeItemData *tData=treeFilters->GetItemData(tId); - filterId = ((wxTreeUint *)tData)->value; - - bool needUpdate; - int row=event.GetRow(); - if(!visControl.setFilterProperty(filterId, - gridFilterPropGroup->getKeyFromRow(row),value,needUpdate)) - { - event.Veto(); - programmaticEvent=false; - return; - } - - - if(needUpdate && checkAutoUpdate->GetValue()) - doSceneUpdate(); - else - clearWxTreeImages(treeFilters); - - visControl.updateFilterPropGrid(gridFilterPropGroup,filterId); - - editUndoMenuItem->Enable(visControl.getUndoSize()); - editRedoMenuItem->Enable(visControl.getRedoSize()); - Layout(); - programmaticEvent=false; -} - -void MainWindowFrame::OnGridCameraPropertyChange(wxGridEvent &event) -{ - - if(programmaticEvent) - { - event.Veto(); - return; - } - - programmaticEvent=true; - //Should only be in the second col - ASSERT(event.GetCol()==1); - - std::string value; - value = stlStr(gridCameraProperties->GetCellValue( - event.GetRow(),1)); - - //Get the camera ID value (long song and dance that it is) - wxListUint *l; - int n = comboCamera->FindString(comboCamera->GetValue()); - if(n == wxNOT_FOUND) - { - programmaticEvent=false; - return; - } - l =(wxListUint*) comboCamera->GetClientObject(n); - - ASSERT(l); - - size_t cameraId; - cameraId = l->value; - - int row=event.GetRow(); - if(visControl.setCamProperties(cameraId,gridCameraProperties->getKeyFromRow(row),value)) - visControl.updateCamPropertyGrid(gridCameraProperties,cameraId); - else - event.Veto(); - - panelTop->Refresh(true); - programmaticEvent=false; - - -} - -void MainWindowFrame::OnCameraGridCellEditorHide(wxGridEvent &e) -{ - //Unlock the camera combo, now that we have finished editing - comboCamera->Enable(true); -} - -void MainWindowFrame::OnComboCameraText(wxCommandEvent &event) -{ - std::string s; - s=stlStr(comboCamera->GetValue()); - if(!s.size()) - return; - - int n = comboCamera->FindString(comboCamera->GetValue()); - - if ( n== wxNOT_FOUND ) - statusMessage(TRANS("Press enter to store new camera"),MESSAGE_HINT); - else - statusMessage(TRANS("Press enter to restore camera"),MESSAGE_HINT); -} - -void MainWindowFrame::OnComboCameraEnter(wxCommandEvent &event) -{ - std::string camName; - camName=stlStr(comboCamera->GetValue()); - - //Disallow cameras with no name - if (!camName.size()) - return; - - //Search for the camera's position in the combo box - int n = comboCamera->FindString(comboCamera->GetValue()); - - //If we have found the camera... - if ( n!= wxNOT_FOUND ) - { - //Select the combo box item - comboCamera->Select(n); - //Set this camera as thew new camera - wxListUint *l; - l =(wxListUint*) comboCamera->GetClientObject(comboCamera->GetSelection()); - visControl.setCam(l->value); - - std::string s = std::string(TRANS("Restored camera: ") ) +stlStr(comboCamera->GetValue()); - - statusMessage(s.c_str(),MESSAGE_INFO); - - //refresh the camera property grid - visControl.updateCamPropertyGrid(gridCameraProperties ,l->value); - - //force redraw in 3D pane - panelTop->Refresh(false); - return ; - } - - //Create a new camera for the scene. - unsigned int u=visControl.addCam(camName); - - //Do not delete as this will be deleted by wx. - comboCamera->Append(comboCamera->GetValue(),(wxClientData *)new wxListUint(u)); - - std::string s = std::string(TRANS("Stored camera: " )) +stlStr(comboCamera->GetValue()); - statusMessage(s.c_str(),MESSAGE_INFO); - - visControl.setCam(u); - visControl.updateCamPropertyGrid(gridCameraProperties,u); - panelTop->Refresh(false); -} - -void MainWindowFrame::OnComboCamera(wxCommandEvent &event) -{ - //Set the active camera - wxListUint *l; - l =(wxListUint*) comboCamera->GetClientObject(comboCamera->GetSelection()); - visControl.setCam(l->value); - - - - visControl.updateCamPropertyGrid(gridCameraProperties,l->value); - - std::string s = std::string(TRANS("Restored camera: ") ) +stlStr(comboCamera->GetValue()); - statusMessage(s.c_str(),MESSAGE_INFO); - - panelTop->Refresh(false); - return ; -} - -void MainWindowFrame::OnComboCameraSetFocus(wxFocusEvent &event) -{ - - if(!haveSetComboCamText) - { - //Even if we have - int pos; - pos = comboCamera->FindString(comboCamera->GetValue()); - - //clear the text if it is the introduction string, or something - // we don't have in the camera - if(pos == wxNOT_FOUND) - comboCamera->SetValue(wxT("")); - - haveSetComboCamText=true; - event.Skip(); - return; - } - - event.Skip(); -} - -void MainWindowFrame::OnComboStashSetFocus(wxFocusEvent &event) -{ - if(!haveSetComboStashText) - { - comboStash->SetValue(wxT("")); - haveSetComboStashText=true; - event.Skip(); - return; - } - event.Skip(); -} - -void MainWindowFrame::OnComboFilterEnter(wxCommandEvent &event) -{ - if(currentlyUpdatingScene) - return; - - OnComboFilter(event); -} - -void MainWindowFrame::OnComboFilter(wxCommandEvent &event) -{ - if(currentlyUpdatingScene) - return; - - wxTreeItemId id; - - id=treeFilters->GetSelection(); - - //Check that there actually was a selection (a bit backwards, but thats the way of it) - if(!id.IsOk() || id == treeFilters->GetRootItem()) - { - if(treeFilters->GetCount()) - statusMessage(TRANS("Select an item from the filter tree before choosing a new filter")); - else - statusMessage(TRANS("Load data source (file->open) before choosing a new filter")); - return; - } - - //Perform the appropriate action for the particular filter, - //or use the default action for every other filter - bool haveErr=false; - - - //Convert the string into a filter ID based upon our mapping - wxString s; - s=comboFilters->GetString(event.GetSelection()); - size_t filterType; - filterType=filterMap[stlStr(s)]; - - ASSERT(stlStr(s) == TRANS(comboFilters_choices[filterType])); - switch(comboFiltersTypeMapping[filterType]) - { - case FILTER_TYPE_RANGEFILE: - { - ///Prompt user for file - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Select RNG File..."),wxT(""),wxT(""), - wxTRANS("Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST); - - - if( (wxF->ShowModal() == wxID_CANCEL)) - { - haveErr=true; - break; - } - - //Load rangefile & construct filter - Filter*f=configFile.getDefaultFilter(FILTER_TYPE_RANGEFILE); - std::string dataFile = stlStr(wxF->GetPath()); - RangeFileFilter *r = (RangeFileFilter*)f; - r->setRangeFilename(dataFile); - - - - if(!r->updateRng()) - { - std::string errString; - errString = TRANS("Failed reading range file."); - errString += "\n"; - errString+=r->getRange().getErrString(); - - wxMessageDialog *wxD =new wxMessageDialog(this, - wxStr(errString),wxTRANS("Error loading file"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - delete f; - haveErr=true; - break; - } - - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - - ASSERT(tData); - visControl.addFilter(f,false,((wxTreeUint *)tData)->value); - - //Rebuild tree control - visControl.updateWxTreeCtrl(treeFilters,f); - break; - } - default: - { - Filter *t; - - ASSERT(filterType < FILTER_TYPE_ENUM_END); - //Generate the appropriate filter - t=configFile.getDefaultFilter(comboFiltersTypeMapping[filterType]); - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - - ASSERT(tData); - //Add the filter to viscontrol - visControl.addFilter(t,false,((wxTreeUint *)tData)->value); - - //Rebuild tree control - visControl.updateWxTreeCtrl(treeFilters,t); - } - - } - - if(haveErr) - { - //Clear the combo box - comboFilters->SetValue(wxT("")); - return; - } - - //Rebuild tree control - refreshButton->Enable(visControl.numFilters()); - - if(checkAutoUpdate->GetValue()) - doSceneUpdate(); - - comboFilters->SetValue(wxT("")); - - editUndoMenuItem->Enable(visControl.getUndoSize()); - editRedoMenuItem->Enable(visControl.getRedoSize()); -} - -bool MainWindowFrame::doSceneUpdate() -{ - //Update scene - ASSERT(!currentlyUpdatingScene); - - //Suspend the update timer, and start the progress timer - updateTimer->Stop(); - progressTimer->Start(PROGRESS_TIMER_DELAY); - currentlyUpdatingScene=true; - haveAborted=false; - - - statusMessage("",MESSAGE_NONE); - noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons.")); - - //Disable tree filters,refresh button and undo - setLockUI(true); - - panelSpectra->Refresh(); - - if(!requireFirstUpdate) - textConsoleOut->Clear(); - - //Set focus on the main frame itself, so that we can catch escape key presses - SetFocus(); - - unsigned int errCode=visControl.refreshFilterTree(); - - progressTimer->Stop(); - updateTimer->Start(UPDATE_TIMER_DELAY); - - //If there was an error, then - //display it - if(errCode) - { - ProgressData p; - p=visControl.getProgress(); - - statusTimer->Start(STATUS_TIMER_DELAY,wxTIMER_ONE_SHOT); - std::string errString; - if(p.curFilter) - errString = p.curFilter->getErrString(errCode); - else - errString = TRANS("Refresh Aborted."); - - statusMessage(errString.c_str(),MESSAGE_ERROR); - } - - //Call the progress one more time, in order to ensure that user sees "100%" - if(!errCode) - updateProgressStatus(); - - currentlyUpdatingScene=false; - visControl.resetProgress(); - - //Restore the UI elements to their interactive state - setLockUI(false); - - panelTop->Refresh(false); - panelSpectra->Refresh(false); - - updateLastRefreshBox(); - - - //Add (or hide) a little "Star" to inform the user there is some info available - if(textConsoleOut->IsEmpty() || noteDataView->GetSelection()==NOTE_CONSOLE_PAGE_OFFSET) - noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons.")); - else - { -#if defined(__WIN32) || defined(__WIN64) - noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("*Cons.")); -#else - noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("§Cons.")); -#endif - } - - - setFilterTreeAnalysisImages(); - - - //Return a value dependant upon whether we successfully loaded - //the data or not - return errCode == 0; -} - -void MainWindowFrame::setFilterTreeAnalysisImages() -{ - vector lastErrs; - visControl.getAnalysisResults(lastErrs); - - //Show the error button if required - btnFilterTreeErrs->Show(!lastErrs.empty()); - - if(lastErrs.empty()) - { - treeFilters->AssignImageList(NULL); - return; - } - - //Maps filters to their maximal severity level - map severityMapping; - - for(size_t ui=0;ui::iterator it; - it = severityMapping.find(filt); - - - //If doesn't exist, put one in. If it does exist, keep only max. severity msg - if(it == severityMapping.end()) - severityMapping[filt] = lastErrs[ui].severity; - else - it->second = std::max(lastErrs[ui].severity,severityMapping[filt]); - } - } - - //Map filters into icons - map iconSettings; - { - //Maps particular severity values into icons - map severityIconMapping; - severityIconMapping[ANALYSE_SEVERITY_ERROR] = wxART_ERROR; - severityIconMapping[ANALYSE_SEVERITY_WARNING] =wxART_WARNING; - - for(map::const_iterator it=severityMapping.begin();it!=severityMapping.end(); ++it) - iconSettings[visControl.getIdByFilter(it->first)] = severityIconMapping[it->second]; - } - - //apply the filter->icon mapping - setWxTreeImages(treeFilters,iconSettings); - -#if defined(__WIN32) || defined(__WIN64) - //HACK: Under MSW, force button to correct positioning, by forcing a relayout - treeFilters->GetParent()->Layout(); -#endif -} - -void MainWindowFrame::OnStatusBarTimer(wxTimerEvent &event) -{ - for(unsigned int ui=0; ui<3; ui++) - { - MainFrame_statusbar->SetBackgroundColour(wxNullColour); - MainFrame_statusbar->SetStatusText(wxT(""),ui); - } - - - //Stop the status timer, just in case - statusTimer->Stop(); -} - -void MainWindowFrame::OnProgressTimer(wxTimerEvent &event) -{ - updateProgressStatus(); -} - -void MainWindowFrame::OnAutosaveTimer(wxTimerEvent &event) -{ - //Save a state file to the configuration dir - //with the title "autosave.xml" - // - - wxString filePath = wxStr(configFile.getConfigDir()); - - unsigned int pid; - pid = wxGetProcessId(); - - std::string pidStr; - stream_cast(pidStr,pid); - - filePath+=wxFileName::GetPathSeparator()+ wxCStr(AUTOSAVE_PREFIX) + wxStr(pidStr) + - wxCStr(AUTOSAVE_SUFFIX); - //Save to the autosave file - std::string s; - s= stlStr(filePath); - std::map dummyMap; - if(visControl.saveState(s.c_str(),dummyMap)) - statusMessage(TRANS("Autosave complete."),MESSAGE_INFO); - else - { - //The save failed, but may have left an incomplete file lying around - if(wxFileExists(filePath)) - wxRemoveFile(filePath); - } - - -} - -void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event) -{ - timerEvent=true; - - //TODO: HACK AROUND: force tree filter to relayout under wxGTK and Mac - #ifndef __WXMSW__ - //Note: Calling this under windows causes the dropdown box that hovers over the top of this to - //be closed, rendering the dropdown useless. That took ages to work out. - treeFilters->GetParent()->Layout(); - #endif - - if(requireFirstUpdate) - { - //Get vis controller to update tree control to match internal - //structure - visControl.updateWxTreeCtrl(treeFilters); - refreshButton->Enable(visControl.numFilters()); - - doSceneUpdate(); - - //If we are using the default camera, - //move it to make sure that it is visible - if(visControl.numCams() == 1) - visControl.ensureSceneVisible(3); - - panelTop->Refresh(); - requireFirstUpdate=false; - } - - - //see if we need to update the post effects due to user interaction - //with the crop panels - if(panelFxCropOne->hasUpdate() || panelFxCropTwo->hasUpdate()) - { - updatePostEffects(); - panelFxCropOne->clearUpdate(); - panelFxCropOne->clearUpdate(); - } - - //Check viscontrol to see if it needs an update, such as - //when the user interacts with an object when it is not - //in the process of refreshing. - //Don't attempt to update if already updating, or last - //update aborted - bool visUpdates=visControl.hasUpdates(); - bool plotUpdates=panelSpectra->hasUpdates(); - - //I can has updates? - if((visUpdates || plotUpdates) && !visControl.isRefreshing()) - { - //FIXME: This is a massive hack. Use proper feedback to determine - //the correct thing to update, rather than nuking everything - //from orbit - if(plotUpdates) - visControl.clearCacheByType(FILTER_TYPE_RANGEFILE); - - doSceneUpdate(); - } - - //Check the openGL pane to see if the camera property grid needs refreshing - if(panelTop->hasCameraUpdates()) - { - //Use the current combobox value to determine which camera is the - //current camera in the property grid - - - int n = comboCamera->FindString(comboCamera->GetValue()); - - if(n != wxNOT_FOUND) - { - wxListUint *l; - l =(wxListUint*) comboCamera->GetClientObject(n); - - visControl.updateCamPropertyGrid(gridCameraProperties,l->value); - } - - panelTop->clearCameraUpdates(); - } - - if(plotUpdates) - panelSpectra->clearUpdates(); - - if(visUpdates) - { - wxTreeItemId id; - id=treeFilters->GetSelection(); - - if(id.IsOk() && (id != treeFilters->GetRootItem())) - { - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - visControl.updateFilterPropGrid(gridFilterPropGroup, - ((wxTreeUint *)tData)->value); - editUndoMenuItem->Enable(visControl.getUndoSize()); - editRedoMenuItem->Enable(visControl.getRedoSize()); - } - - } - - - - - timerEvent=false; -} - -void MainWindowFrame::statusMessage(const char *message, unsigned int type) -{ - bool sendMessage=true; - switch(type) - { - case MESSAGE_ERROR: - MainFrame_statusbar->SetBackgroundColour(*wxGREEN); - break; - case MESSAGE_INFO: - MainFrame_statusbar->SetBackgroundColour(*wxCYAN); - break; - case MESSAGE_HINT: - break; - //Pseudo-messages - case MESSAGE_NONE: // No actions needed, just supply the message - ASSERT( string(message)== string("")); - break; - case MESSAGE_NONE_BUT_HINT: - ASSERT( string(message)== string("")); - //we need to clear any messages other than "hintMessage" - sendMessage=(lastMessageType==MESSAGE_HINT); - break; - default: - ASSERT(false); - } - - lastMessageType=type; - - if(sendMessage) - MainFrame_statusbar->SetStatusText(wxCStr(message),0); - statusTimer->Start(STATUS_TIMER_DELAY,wxTIMER_ONE_SHOT); -} - -void MainWindowFrame::updateProgressStatus() -{ - - std::string progressString,filterProg; - - - if(!visControl.numFilters()) - return; - - if(haveAborted) - { - progressString=TRANS("Aborted."); - } - else - { - ProgressData p; - p=visControl.getProgress(); - ASSERT(p.totalProgress <= visControl.numFilters()); - - if(p.filterProgress > 100) - p.filterProgress=100; - - //Create a string from the total and percentile progresses - std::string totalProg,totalCount,step,maxStep; - stream_cast(totalProg,p.totalProgress); - stream_cast(filterProg,p.filterProgress); - stream_cast(totalCount,p.totalNumFilters); - - - stream_cast(step,p.step); - stream_cast(maxStep,p.maxStep); - - ASSERT(p.step <=p.maxStep); - - if(p.curFilter) - { - if(!p.maxStep) - progressString = totalProg+TRANS(" of ") + totalCount + - " (" + p.curFilter->typeString() +")"; - else - { - progressString = totalProg+TRANS(" of ") + totalCount + - " (" + p.curFilter->typeString() + ", " - + step + "/" + maxStep + ": " + - p.stepName+")"; - } - } - else - { - //If we have no filter, then we must be done if the totalProgress is - //equal to the total count. - if(totalProg == totalCount) - progressString = TRANS("Updated."); - else - progressString = totalProg + TRANS(" of ") + totalCount; - } - - if( p.filterProgress != 100) - filterProg+=TRANS("\% Done (Esc aborts)"); - else - filterProg+=TRANS("\% Done"); - - } - - MainFrame_statusbar->SetBackgroundColour(wxNullColour); - MainFrame_statusbar->SetStatusText(wxT(""),0); - MainFrame_statusbar->SetStatusText(wxStr(progressString),1); - MainFrame_statusbar->SetStatusText(wxStr(filterProg),2); -} - -void MainWindowFrame::updatePostEffects() -{ - panelTop->currentScene.clearEffects(); - - //Do we need post-processing? -#ifndef APPLE_EFFECTS_WORKAROUND - if(!checkPostProcessing->IsChecked()) - return; -#endif - if( checkFxCrop->IsChecked()) - { - - wxString ws; - string s; - ws=comboFxCropAxisOne->GetValue(); - s =stlStr(ws); - - //String encodes permutation (eg "x-y"). - unsigned int axisPerm[4]; - axisPerm[0] =(unsigned int)(s[0] -'x')*2; - axisPerm[1] = (unsigned int)(s[0] -'x')*2+1; - axisPerm[2] =(unsigned int)(s[2] -'x')*2; - axisPerm[3] = (unsigned int)(s[2] -'x')*2+1; - - //Get the crop data, and generate an effect - BoxCropEffect *b = new BoxCropEffect; - - //Assume, that unless otherwise specified - //the default crop value is zero - float array[6]; - float tmpArray[4]; - for(unsigned int ui=0;ui<6;ui++) - array[ui]=0; - - //Permute the indices for the crop fractions, then assign - panelFxCropOne->getCropValues(tmpArray); - for(unsigned int ui=0;ui<4;ui++) - array[axisPerm[ui]] = tmpArray[ui]; - - - ws=comboFxCropAxisTwo->GetValue(); - s =stlStr(ws); - - axisPerm[0] =(unsigned int)(s[0] -'x')*2; - axisPerm[1] = (unsigned int)(s[0] -'x')*2+1; - axisPerm[2] =(unsigned int)(s[2] -'x')*2; - axisPerm[3] = (unsigned int)(s[2] -'x')*2+1; - panelFxCropTwo->getCropValues(tmpArray); - - for(unsigned int ui=0;ui<4;ui++) - array[axisPerm[ui]] = tmpArray[ui]; - - b->setFractions(array); - - //Should we be using the camera frame? - b->useCamCoords(checkFxCropCameraFrame->IsChecked()); - - //Send the effect to the scene - if(b->willDoSomething()) - { - panelTop->currentScene.addEffect(b); - panelTop->currentScene.setEffects(true); - - - //Update the dx,dy and dz boxes - BoundCube bcTmp; - bcTmp=panelTop->currentScene.getBound(); - - b->getCroppedBounds(bcTmp); - - if(!checkFxCropCameraFrame->IsChecked()) - { - float delta; - delta=bcTmp.getBound(0,1)-bcTmp.getBound(0,0); - stream_cast(s,delta); - textFxCropDx->SetValue(wxStr(s)); - - delta=bcTmp.getBound(1,1)-bcTmp.getBound(1,0); - stream_cast(s,delta); - textFxCropDy->SetValue(wxStr(s)); - - delta=bcTmp.getBound(2,1)-bcTmp.getBound(2,0); - stream_cast(s,delta); - textFxCropDz->SetValue(wxStr(s)); - } - else - { - textFxCropDx->SetValue(wxT("")); - textFxCropDy->SetValue(wxT("")); - textFxCropDz->SetValue(wxT("")); - } - - //well, we dealt with this update. - panelFxCropOne->clearUpdate(); - panelFxCropTwo->clearUpdate(); - } - else - { - textFxCropDx->SetValue(wxT("")); - textFxCropDy->SetValue(wxT("")); - textFxCropDz->SetValue(wxT("")); - delete b; - - //we should let this return true, - //so that an update takes hold - } - - } - - - if(checkFxEnableStereo->IsChecked()) - { - AnaglyphEffect *anaglyph = new AnaglyphEffect; - - unsigned int sel; - sel=comboFxStereoMode->GetSelection(); - anaglyph->setMode(sel); - int v=sliderFxStereoBaseline->GetValue(); - - float shift=((float)v)*BASELINE_SHIFT_FACTOR; - - anaglyph->setBaseShift(shift); - anaglyph->setFlip(checkFxStereoLensFlip->IsChecked()); - panelTop->currentScene.addEffect(anaglyph); - } - - panelTop->Refresh(); -} - -void MainWindowFrame::updateFxUI(const vector &effs) -{ - //Here we pull information out from the effects and then - //update the ui controls accordingly - - Freeze(); - - for(unsigned int ui=0;uigetType()) - { - case EFFECT_BOX_CROP: - { - const BoxCropEffect *e=(const BoxCropEffect*)effs[ui]; - - //Enable the checkbox - checkFxCrop->SetValue(true); - //set the combos back to x-y y-z - comboFxCropAxisOne->SetSelection(0); - comboFxCropAxisTwo->SetSelection(1); - - //Temporarily de-link the panels - panelFxCropOne->link(0,CROP_LINK_NONE); - panelFxCropTwo->link(0,CROP_LINK_NONE); - - //Set the crop values - for(unsigned int ui=0;ui<6;ui++) - { - if(ui<4) - panelFxCropOne->setCropValue(ui, - e->getCropValue(ui)); - else if(ui > 2) - panelFxCropTwo->setCropValue(ui-2, - e->getCropValue(ui)); - } - - //Ensure that the values that went in were valid - panelFxCropOne->makeCropValuesValid(); - panelFxCropTwo->makeCropValuesValid(); - - - //Restore the panel linkage - panelFxCropOne->link(panelFxCropTwo,CROP_LINK_BOTH); - panelFxCropTwo->link(panelFxCropOne,CROP_LINK_BOTH); - - - break; - } - case EFFECT_ANAGLYPH: - { - const AnaglyphEffect *e=(const AnaglyphEffect*)effs[ui]; - //Set the slider from the base-shift value - float shift; - shift=e->getBaseShift(); - sliderFxStereoBaseline->SetValue( - (unsigned int)(shift/BASELINE_SHIFT_FACTOR)); - - - //Set the stereo drop down colour - unsigned int mode; - mode = e->getMode(); - ASSERT(mode < comboFxStereoMode->GetCount()); - - comboFxStereoMode->SetSelection(mode); - //Enable the stereo mode - checkFxEnableStereo->SetValue(true); - break; - } - default: - ASSERT(false); - } - - } - - //Re-enable the effects UI as needed - if(!effs.empty()) - { -#ifndef APPLE_EFFECTS_WORKAROUND - checkPostProcessing->SetValue(true); - noteFxPanelCrop->Enable(); - noteFxPanelStereo->Enable(); -#endif - visControl.setEffects(true); - } - - - Thaw(); -} - -void MainWindowFrame::OnProgressAbort(wxCommandEvent &event) -{ - if(!haveAborted) - visControl.abort(); - haveAborted=true; -} - -void MainWindowFrame::OnViewFullscreen(wxCommandEvent &event) -{ - if(programmaticEvent) - return; - - programmaticEvent=true; - - //Toggle fullscreen, leave the menubar & statusbar visible - -#ifdef __APPLE__ - switch(fullscreenState) - { - case 0: - ShowFullScreen(true,wxFULLSCREEN_NOTOOLBAR); - menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: none")); - break; - case 1: - menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: complete")); - ShowFullScreen(false); - break; - case 2: - menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: none")); - ShowFullScreen(true); - break; - case 3: - menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: with toolbars")); - ShowFullScreen(false); - break; - - default: - ASSERT(false); - - } - fullscreenState++; - fullscreenState%=4; -#elif __LINUX__ - - switch(fullscreenState) - { - case 0: - ShowFullScreen(true,wxFULLSCREEN_NOTOOLBAR); - statusMessage(TRANS("Next Mode: No fullscreen"),MESSAGE_HINT); - break; - case 1: - ShowFullScreen(false); - statusMessage(TRANS("Next Mode: fullscreen w/o toolbar"),MESSAGE_HINT); - break; - case 2: - ShowFullScreen(true); - statusMessage(TRANS("Next Mode: fullscreen with toolbar"),MESSAGE_HINT); - break; - default: - ASSERT(false); - } - fullscreenState++; - fullscreenState%=3; -#else - - switch(fullscreenState) - { - case 0: - ShowFullScreen(true); - break; - case 1: - ShowFullScreen(false); - break; - default: - ASSERT(false); - } - fullscreenState++; - fullscreenState%=2; -#endif - programmaticEvent=false; -} - -void MainWindowFrame::OnButtonRefresh(wxCommandEvent &event) -{ - if(currentlyUpdatingScene) - return; - - //dirty hack to get keyboard state. - wxMouseState wxm = wxGetMouseState(); - if(wxm.ShiftDown()) - { - visControl.purgeFilterCache(); - statusMessage("",MESSAGE_NONE); - } - else - { - if(checkCaching->IsChecked()) - statusMessage(TRANS("Use shift-click to force full refresh"),MESSAGE_HINT); - } - doSceneUpdate(); -} - -void MainWindowFrame::OnRawDataUnsplit(wxSplitterEvent &event) -{ - checkMenuRawDataPane->Check(false); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,false); -} - -void MainWindowFrame::OnFilterPropDoubleClick(wxSplitterEvent &event) -{ - //Disallow unsplitting of filter property panel - event.Veto(); -} - -void MainWindowFrame::OnControlSplitMove(wxSplitterEvent &event) -{ - wxGridEvent gridEvent(ID_GRID_RAW_DATA,wxEVT_GRID_LABEL_LEFT_DCLICK,NULL); - wxPostEvent(gridFilterPropGroup,gridEvent); -} - -void MainWindowFrame::OnTopBottomSplitMove(wxSplitterEvent &event) -{ - Refresh(); -} - -void MainWindowFrame::OnControlUnsplit(wxSplitterEvent &event) -{ - //Make sure that the LHS panel is removed, rather than the default (right) - splitLeftRight->Unsplit(panelLeft); - - checkMenuControlPane->Check(false); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,false); -} - -void MainWindowFrame::OnSpectraUnsplit(wxSplitterEvent &event) -{ - checkMenuSpectraList->Check(false); - configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,false); -} - -//This function modifies the properties before showing the cell content editor. -//This is needed only for certain data types (colours, bools) other data types are edited -//using the default editor and modified using ::OnGridFilterPropertyChange -void MainWindowFrame::OnFilterGridCellEditorShow(wxGridEvent &event) -{ - - if(programmaticEvent || timerEvent) - { - event.Skip(); - return; - } - //Find where the event occurred (cell & property) - const GRID_PROPERTY *item; - - unsigned int key; - key=gridFilterPropGroup->getKeyFromRow(event.GetRow()); - - item=gridFilterPropGroup->getProperty(key); - - //Remove any icons that show filter errors or warning state - clearWxTreeImages(treeFilters); - - bool needUpdate=false; - - ASSERT(treeFilters->GetSelection() != treeFilters->GetRootItem()); - - //If this occurs at run-time, then just abort - if(treeFilters->GetSelection() == treeFilters->GetRootItem()) - return; - - //Get the filter ID value - size_t filterId; - wxTreeItemId tId = treeFilters->GetSelection(); - if(!tId.IsOk()) - return; - - wxTreeItemData *tData=treeFilters->GetItemData(tId); - filterId = ((wxTreeUint *)tData)->value; - - - switch(item->type) - { - case PROPERTY_TYPE_BOOL: - { - std::string s; - //Toggle the property in the grid - if(item->data == "0") - s= "1"; - else - s="0"; - visControl.setFilterProperty(filterId,key,s,needUpdate); - - event.Veto(); - break; - } - case PROPERTY_TYPE_COLOUR: - { - //Show a wxColour choose dialog. - wxColourData d; - - unsigned char r,g,b,a; - parseColString(item->data,r,g,b,a); - - d.SetColour(wxColour(r,g,b,a)); - wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); - - - if( colDg->ShowModal() == wxID_OK) - { - wxColour c; - //Change the colour - c=colDg->GetColourData().GetColour(); - - std::string s; - genColString(c.Red(),c.Green(),c.Blue(),s); - - //Pass the new colour to the viscontrol system, which updates - //the filters - visControl.setFilterProperty(filterId,key,s,needUpdate); - } - - //Set the filter property - //Disallow direct editing of the grid cell - event.Veto(); - - break; - } - default: - //we will handle this after the user has edited the cell contents - //but we must lock controls that can alter the active filter, and thereby changing the - // filter grid in the meantime - refreshButton->Enable(false); - comboFilters->Enable(false); - comboStash->Enable(false); - treeFilters->Enable(false); - break; - } - - if(needUpdate) - { - visControl.updateFilterPropGrid(gridFilterPropGroup, - ((wxTreeUint *)tData)->value); - - editUndoMenuItem->Enable(visControl.getUndoSize()); - editRedoMenuItem->Enable(visControl.getRedoSize()); - if(checkAutoUpdate->GetValue()) - doSceneUpdate(); - else - clearWxTreeImages(treeFilters); - } -} - -void MainWindowFrame::OnFilterGridCellEditorHide(wxGridEvent &event) -{ - //re-enable the controls that were locked during OnFilterGridCellEditorShow - refreshButton->Enable(); - comboFilters->Enable(); - comboStash->Enable(); - treeFilters->Enable(); -} - -void MainWindowFrame::OnCameraGridCellEditorShow(wxGridEvent &event) -{ - if(programmaticEvent||timerEvent) - { - event.Skip(); - return; - } - //Find where the event occurred (cell & property) - const GRID_PROPERTY *item; - - unsigned int key; - key=gridCameraProperties->getKeyFromRow(event.GetRow()); - - item=gridCameraProperties->getProperty(key); - - //Get the camera ID - wxListUint *l; - int n = comboCamera->FindString(comboCamera->GetValue()); - if( n == wxNOT_FOUND) - return; - - l =(wxListUint*) comboCamera->GetClientObject(n); - if(!l) - return; - - size_t camUniqueID=l->value; - - - switch(item->type) - { - case PROPERTY_TYPE_BOOL: - { - std::string s; - //Toggle the property in the grid - if(item->data == "0") - s= "1"; - else - s="0"; - visControl.setCamProperties(camUniqueID,key,s); - - //For some reason this does not redraw neatly. Force a redraw - visControl.updateCamPropertyGrid(gridCameraProperties,camUniqueID); - - event.Veto(); - break; - } - case PROPERTY_TYPE_COLOUR: - { - //Show a wxColour choose dialog. - wxColourData d; - - unsigned char r,g,b,a; - parseColString(item->data,r,g,b,a); - - d.SetColour(wxColour(r,g,b,a)); - wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); - - - if( colDg->ShowModal() == wxID_OK) - { - wxColour c; - //Change the colour - c=colDg->GetColourData().GetColour(); - - std::string s; - genColString(c.Red(),c.Green(),c.Blue(),s); - - //Pass the new colour to the viscontrol system, which updates - //the filters - visControl.setCamProperties(camUniqueID,key,s); - } - - //Set the filter property - //Disallow direct editing of the grid cell - event.Veto(); - - break; - } - default: - //we will handle this after the user has edited the cell contents - //Lock the camera combo, so the user can't alter the camera data while we are using the editor - comboCamera->Enable(false); - break; - } - - panelTop->Refresh(false); - -} - -void MainWindowFrame::OnButtonGridCopy(wxCommandEvent &event) -{ - gridRawData->copyData(); -} - -void MainWindowFrame::OnButtonGridSave(wxCommandEvent &event) -{ - if(!gridRawData->GetRows()||!gridRawData->GetCols()) - { - statusMessage(TRANS("No data to save"),MESSAGE_ERROR); - return; - } - gridRawData->saveData(); -} - -void MainWindowFrame::OnCheckAlpha(wxCommandEvent &event) -{ - panelTop->currentScene.setAlpha(event.IsChecked()); - - panelTop->Refresh(); -} - -void MainWindowFrame::OnCheckLighting(wxCommandEvent &event) -{ - panelTop->currentScene.setLighting(event.IsChecked()); - - panelTop->Refresh(); -} - -void MainWindowFrame::OnCheckCacheEnable(wxCommandEvent &event) -{ - if(event.IsChecked()) - visControl.setCachePercent((unsigned int)spinCachePercent->GetValue()); - else - { - visControl.setCachePercent(0); - visControl.purgeFilterCache(); - - doSceneUpdate(); - } -} - -void MainWindowFrame::OnCheckWeakRandom(wxCommandEvent &event) -{ - visControl.setStrongRandom(!event.IsChecked()); - - doSceneUpdate(); -} - -void MainWindowFrame::OnCacheRamUsageSpin(wxSpinEvent &event) -{ - ASSERT(event.GetPosition() >= 0 &&event.GetPosition()<=100); - - visControl.setCachePercent(event.GetPosition()); - -} -void MainWindowFrame::OnButtonRemoveCam(wxCommandEvent &event) -{ - - std::string camName; - - - camName=stlStr(comboCamera->GetValue()); - - if (!camName.size()) - return; - - int n = comboCamera->FindString(comboCamera->GetValue()); - - if ( n!= wxNOT_FOUND ) - { - wxListUint *l; - l =(wxListUint*) comboCamera->GetClientObject(n); - visControl.removeCam(l->value); - comboCamera->Delete(n); - - programmaticEvent=true; - comboCamera->SetValue(wxT("")); - gridCameraProperties->clear(); - programmaticEvent=false; - } -} - -void MainWindowFrame::OnSpectraListbox(wxCommandEvent &event) -{ - //This function gets called programatically by - //doSceneUpdate. Prevent interaction. - if(visControl.isRefreshing()) - return; - //Get the currently selected item - //Spin through the selected items - for(unsigned int ui=0;uiGetCount(); ui++) - { - wxListUint *l; - unsigned int plotID; - - //Retrieve the uniqueID - l=(wxListUint*)plotList->GetClientObject(ui); - plotID = l->value; - - panelSpectra->setPlotVisible(plotID,plotList->IsSelected(ui)); - - } - - panelSpectra->Refresh(); - //The raw grid contents may change due to the list selection - //change. Update the grid - visControl.updateRawGrid(); -} - -void MainWindowFrame::OnClose(wxCloseEvent &event) -{ - - if(visControl.isRefreshing()) - { - if(!haveAborted) - { - visControl.abort(); - haveAborted=true; - - statusMessage(TRANS("Aborting..."),MESSAGE_INFO); - return; - } - else - { - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("Waiting for refresh to abort. Exiting could lead to the program backgrounding. Exit anyway? "), - wxTRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR); - - if(wxD->ShowModal() != wxID_OK) - { - event.Veto(); - wxD->Destroy(); - return; - } - wxD->Destroy(); - } - } - else - { - //If the program is being forced by the OS to shut down, don't ask the user for abort, - // as we can't abort it anyway. - if(event.CanVeto()) - { - if(visControl.numFilters() || visControl.numCams() > 1) - { - //Prompt for close - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("Are you sure you wish to exit 3Depict?"),\ - wxTRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR); - if(wxD->ShowModal() != wxID_OK) - { - event.Veto(); - wxD->Destroy(); - return; - } - wxD->Destroy(); - - } - } - } - - - - //Remove the autosave file if it exists, as we are shutting down neatly. - - //Get self PID - std::string pidStr; - unsigned int pid; - pid=wxGetProcessId(); - stream_cast(pidStr,pid); - - wxString filePath =wxStr(configFile.getConfigDir()); - filePath+=wxCStr("/") + wxCStr(AUTOSAVE_PREFIX) + wxStr(pidStr)+ wxCStr(AUTOSAVE_SUFFIX); - - if(wxFileExists(filePath)) - wxRemoveFile(filePath); - - //Remember current window size for next time - wxSize winSize; - winSize=GetSize(); - configFile.setInitialAppSize(winSize.GetWidth(),winSize.GetHeight()); - - //Remember the sash positions for next time, as fractional values fo - // the window size - float frac; - frac =(float) splitLeftRight->GetSashPosition()/winSize.GetWidth(); - configFile.setLeftRightSashPos(frac); - frac = (float) splitTopBottom->GetSashPosition()/winSize.GetHeight(); - configFile.setTopBottomSashPos(frac); - frac= (float)filterSplitter->GetSashPosition()/winSize.GetHeight(); - configFile.setFilterSashPos(frac); - frac = (float)splitterSpectra->GetSashPosition()/winSize.GetWidth(); - configFile.setPlotListSashPos(frac); - - winSize=noteDataView->GetSize(); - - //Try to save the configuration - configFile.write(); - - if(verCheckThread) - { - if(!verCheckThread->isComplete()) - { - //Kill it. - verCheckThread->Kill(); - } - delete verCheckThread; - } - - - //Terminate the program - Destroy(); -} - - - -void MainWindowFrame::OnCheckPostProcess(wxCommandEvent &event) -{ -#ifdef APPLE_EFFECTS_WORKAROUND - //FIXME: I have disabled this under apple - ASSERT(false); -#endif - //Disable the entire UI panel - noteFxPanelCrop->Enable(event.IsChecked()); - noteFxPanelStereo->Enable(event.IsChecked()); - visControl.setEffects(event.IsChecked()); - updatePostEffects(); - - panelTop->Refresh(); -} - - -void MainWindowFrame::OnFxCropCheck(wxCommandEvent &event) -{ - //Disable/enable the other UI controls on the crop effects page - //Include the text labels to give them that "greyed-out" look - checkFxCropCameraFrame->Enable(event.IsChecked()); - comboFxCropAxisOne->Enable(event.IsChecked()); - panelFxCropOne->Enable(event.IsChecked()); - comboFxCropAxisTwo->Enable(event.IsChecked()); - panelFxCropTwo->Enable(event.IsChecked()); - textFxCropDx->Enable(event.IsChecked()); - textFxCropDy->Enable(event.IsChecked()); - textFxCropDz->Enable(event.IsChecked()); - labelFxCropDx->Enable(event.IsChecked()); - labelFxCropDy->Enable(event.IsChecked()); - labelFxCropDz->Enable(event.IsChecked()); - - updatePostEffects(); -} - - -void MainWindowFrame::OnFxCropCamFrameCheck(wxCommandEvent &event) -{ - updatePostEffects(); -} - - - -void MainWindowFrame::OnFxCropAxisOne(wxCommandEvent &event) -{ - linkCropWidgets(); - updatePostEffects(); -} - -void MainWindowFrame::OnFxCropAxisTwo(wxCommandEvent &event) -{ - linkCropWidgets(); - updatePostEffects(); -} - -void MainWindowFrame::linkCropWidgets() -{ - //Adjust the link mode as needed - //Lets cheat a little and parse the combo box contents - - unsigned int linkMode; - - string first[2],second[2]; - - wxString s; - string tmp; - - s=comboFxCropAxisOne->GetValue(); - tmp=stlStr(s); - first[0]=tmp[0]; - second[0]=tmp[2]; - - s=comboFxCropAxisTwo->GetValue(); - tmp=stlStr(s); - first[1]=tmp[0]; - second[1]=tmp[2]; - - - linkMode=0; - //First and second axis match? - if(first[0] == first[1] && second[0] == second[1]) - { - linkMode=CROP_LINK_BOTH; - } - else if(first[0] == second[1] && second[0] == first[1]) - linkMode=CROP_LINK_BOTH_FLIP; - else if(first[0] == first[1]) - linkMode=CROP_LINK_LR; - else if(second[0] == second[1]) - linkMode=CROP_LINK_TB; - else if(second[0] == first[1]) - { - panelFxCropOne->link(panelFxCropTwo,CROP_LINK_TB_FLIP); - panelFxCropTwo->link(panelFxCropOne,CROP_LINK_LR_FLIP); - } - else if(second[1]== first[0]) - { - panelFxCropOne->link(panelFxCropTwo,CROP_LINK_LR_FLIP); - panelFxCropTwo->link(panelFxCropOne,CROP_LINK_TB_FLIP); - } - else - { - //Pigeonhole principle says we can't get here. - ASSERT(false); - } - - - if(linkMode) - { - panelFxCropOne->link(panelFxCropTwo,linkMode); - panelFxCropTwo->link(panelFxCropOne,linkMode); - } - -} - - - - -void MainWindowFrame::OnFxStereoEnable(wxCommandEvent &event) -{ - comboFxStereoMode->Enable(event.IsChecked()); - sliderFxStereoBaseline->Enable(event.IsChecked()); - checkFxStereoLensFlip->Enable(event.IsChecked()); - - updatePostEffects(); -} - -void MainWindowFrame::OnFxStereoLensFlip(wxCommandEvent &event) -{ - updatePostEffects(); -} - - -void MainWindowFrame::OnFxStereoCombo(wxCommandEvent &event) -{ - updatePostEffects(); -} - - -void MainWindowFrame::OnFxStereoBaseline(wxScrollEvent &event) -{ - updatePostEffects(); -} - -// wxGlade: add MainWindowFrame event handlers - -void MainWindowFrame::SetCommandLineFiles(wxArrayString &files) -{ - - textConsoleOut->Clear(); - //Load them up as data. - for(unsigned int ui=0;uiSetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons.")); - - //Keep processing - evt.Skip(); -} - -void MainWindowFrame::OnCheckUpdatesThread(wxCommandEvent &evt) -{ - //Check to see if we have a new version or not, and - //what that version number is - - ASSERT(verCheckThread->isComplete()); - - //Check to see if we got the version number OK. - // this might have failed, e.g. if the user has no net connection, - // or the remote RSS is not parseable - if(verCheckThread->isRetrieveOK()) - { - string remoteMax=verCheckThread->getVerStr().c_str(); - - vector maxVers; - maxVers.push_back(remoteMax); - maxVers.push_back(PROGRAM_VERSION); - - string s; - if(getMaxVerStr(maxVers) !=PROGRAM_VERSION) - { - //Use status bar message to notify user about update - s = string(TRANS("Update Notice: New version ")) + remoteMax + TRANS(" found online."); - } - else - { - s=string(TRANS("Online Check: " ))+string(PROGRAM_NAME) + TRANS(" is up-to-date."); - } - statusMessage(s.c_str(),MESSAGE_INFO); - } - - //Wait for, then delete the other thread, as we are done with it - verCheckThread->Wait(); - - delete verCheckThread; - verCheckThread=0; - -} - -void MainWindowFrame::checkReloadAutosave() -{ - wxString configDirPath =wxStr(configFile.getConfigDir()); - configDirPath+=wxCStr("/") ; - - if(!wxDirExists(configDirPath)) - return; - - //obtain a list of autosave xml files - //-- - wxArrayString *dirListing= new wxArrayString; - std::string s; - s=std::string(AUTOSAVE_PREFIX) + - std::string("*") + std::string(AUTOSAVE_SUFFIX); - wxString fileMask = wxStr(s); - - wxDir::GetAllFiles(configDirPath,dirListing,fileMask,wxDIR_FILES); - - if(!dirListing->GetCount()) - { - delete dirListing; - return; - } - //-- - - - unsigned int prefixLen; - prefixLen = stlStr(configDirPath).size() + strlen(AUTOSAVE_PREFIX) + 1; - - //For convenience, Construct a mapping to the PIDs from the string - //-- - map autosaveNamePIDMap; - for(unsigned int ui=0;uiGetCount(); ui++) - { - std::string tmp; - tmp = stlStr(dirListing->Item(ui)); - //File name should match specified glob. - ASSERT(tmp.size() >=(strlen(AUTOSAVE_PREFIX) + strlen(AUTOSAVE_SUFFIX))); - - //Strip the non-glob bit out of the string - tmp = tmp.substr(prefixLen-1,tmp.size()-(strlen(AUTOSAVE_SUFFIX) + prefixLen-1)); - - unsigned int pid; - if(stream_cast(pid,tmp)) - continue; - autosaveNamePIDMap[stlStr(dirListing->Item(ui))] = pid; - } - delete dirListing; - //-- - - - //Filter on process existence and name match. - //--- - for(map::iterator it=autosaveNamePIDMap.begin(); - it!=autosaveNamePIDMap.end();) - { - //Note that map does not have a return value for erase in C++second) && processMatchesName(it->second,PROGRAM_NAME) ) - autosaveNamePIDMap.erase(it++); //Note postfix! - else - ++it; - } - //-- - - - //A little messy, but handles two cases of dialog - // one, where one file is either loaded, or deleted - // two, where one of multiple files are either loaded, all deleted or none deleted - vector removeFiles; - - //Do we want to full erase the files in removeFiles (true) - // or move (false) - bool doErase=false; - if(autosaveNamePIDMap.size() == 1) - { - //If we have exactly one autosave, ask the user about loading it - wxString filePath=wxStr(autosaveNamePIDMap.begin()->first); - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("An auto-save state was found, would you like to restore it?.") - ,wxTRANS("Autosave"),wxCANCEL|wxOK|wxICON_QUESTION|wxYES_DEFAULT ); - - if(wxD->ShowModal()!= wxID_CANCEL) - { - if(!loadFile(filePath)) - { - doErase=true; - statusMessage(TRANS("Unable to load autosave file.."),MESSAGE_ERROR); - } - else - { - doErase=false; - requireFirstUpdate=true; - //Prevent the program from allowing save menu usage - //into autosave file - currentFile.clear(); - fileSave->Enable(false); - } - - - removeFiles.push_back(stlStr(filePath)); - } - } - else if(autosaveNamePIDMap.size() > 1) - { - //OK, so we have more than one autosave, from dead 3depict processes. - //ask the user which one they would like to load - vector > filenamesAndTimes; - - - for(map::iterator it=autosaveNamePIDMap.begin(); - it!=autosaveNamePIDMap.end();++it) - { - time_t timeStamp=wxFileModificationTime(wxStr(it->first)); - filenamesAndTimes.push_back(make_pair(timeStamp,it->first)); - } - - //Sort filenamesAndTimes by decreasing age, so that newest appears at - // top of dialog - ComparePairFirstReverse cmp; - std::sort(filenamesAndTimes.begin(),filenamesAndTimes.end(),cmp); - - vector autoSaveChoices; - time_t now = wxDateTime::Now().GetTicks(); - for(size_t ui=0;uisetItems(autoSaveChoices); - - bool wantLoad = false; - - int dlgResult; - dlgResult=dlg->ShowModal(); - - //Show the dialog to get a choice from the user - //We need to load a file if, and only if, - // autosaves were not purged - if(dlgResult==wxID_OK) - wantLoad = !dlg->removedItems(); - if(dlgResult == wxID_OK) - { - if(wantLoad) - { - requireFirstUpdate=true; - - std::string tmpStr; - tmpStr =filenamesAndTimes[dlg->getSelectedItem()].second; - - if(loadFile(wxStr(tmpStr))) - { - //Prevent the program from allowing save menu usage - //into autosave file - currentFile.clear(); - fileSave->Enable(false); - doErase=true; - } - else - doErase=false; - - //If it either does, or doesn't work, - //there is little point in keeping it - removeFiles.push_back(tmpStr); - - } - else - { - for(unsigned int ui=0;uiGetClientArea(); - - bool haveDisplaySizePref; - unsigned int xPref,yPref; - - haveDisplaySizePref=configFile.getInitialAppSize(xPref,yPref); - - //So Min size trumps all - // - then client area - // - then saved setting - // - then default size - wxSize winSize; - if(haveDisplaySizePref) - winSize.Set(xPref,yPref); - else - { - winSize.Set(DEFAULT_WIN_WIDTH,DEFAULT_WIN_HEIGHT); - } - - //Override using minimal window sizes - winSize.Set(std::max(winSize.GetWidth(),(int)MIN_WIN_WIDTH), - std::max(winSize.GetHeight(),(int)MIN_WIN_HEIGHT)); - //Shrink to display size, as needed - winSize.Set(std::min(winSize.GetWidth(),r.GetWidth()), - std::min(winSize.GetHeight(),r.GetHeight())); - - - delete disp; - - return winSize; - -} - -void MainWindowFrame::set_properties() -{ - // begin wxGlade: MainWindowFrame::set_properties - SetTitle(wxCStr(PROGRAM_NAME)); - comboFilters->SetSelection(-1); - - comboFilters->SetToolTip(wxTRANS("List of available filters")); - treeFilters->SetToolTip(wxTRANS("Tree of data filters")); - checkAutoUpdate->SetToolTip(wxTRANS("Enable/Disable automatic updates of data when filter change takes effect")); - checkAutoUpdate->SetValue(true); - - 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")); - 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); - gridFilterPropGroup->EnableDragRowSize(false); - gridFilterPropGroup->SetColLabelValue(0, wxTRANS("Property")); - gridFilterPropGroup->SetColLabelValue(1, wxTRANS("Value")); - gridCameraProperties->CreateGrid(4, 2); - gridCameraProperties->EnableDragRowSize(false); - gridCameraProperties->SetSelectionMode(wxGrid::wxGridSelectRows); - gridCameraProperties->SetColLabelValue(0, wxTRANS("Property")); - gridCameraProperties->SetColLabelValue(1, wxTRANS("Value")); - gridCameraProperties->SetToolTip(wxTRANS("Camera data information")); - noteCamera->SetScrollRate(10, 10); - -#ifndef APPLE_EFFECTS_WORKAROUND - checkPostProcessing->SetToolTip(wxTRANS("Enable/disable visual effects on final 3D output")); -#endif - checkFxCrop->SetToolTip(wxTRANS("Enable cropping post-process effect")); - comboFxCropAxisOne->SetSelection(0); - comboFxCropAxisTwo->SetSelection(0); - checkFxEnableStereo->SetToolTip(wxTRANS("Colour based 3D effect enable/disable - requires appropriate colour filter 3D glasses.")); - comboFxStereoMode->SetToolTip(wxTRANS("Glasses colour mode")); - comboFxStereoMode->SetSelection(0); - sliderFxStereoBaseline->SetToolTip(wxTRANS("Level of separation between left and right images, which sets 3D depth to visual distortion tradeoff")); - gridRawData->CreateGrid(10, 2); - gridRawData->EnableEditing(false); - gridRawData->EnableDragRowSize(false); - gridRawData->SetColLabelValue(0, wxTRANS("X")); - gridRawData->SetColLabelValue(1, wxTRANS("Y")); - btnRawDataSave->SetToolTip(wxTRANS("Save raw data to file")); - btnRawDataClip->SetToolTip(wxTRANS("Copy raw data to clipboard")); - btnStashManage->SetToolTip(wxTRANS("Manage \"stashed\" data.")); - textConsoleOut->SetToolTip(wxTRANS("Program text output")); - comboCamera->SetToolTip(wxTRANS("Select active camera, or type to create new named camera")); - buttonRemoveCam->SetToolTip(wxTRANS("Remove the selected camera")); - checkFxCropCameraFrame->SetToolTip(wxTRANS("Perform cropping from coordinate frame of camera")); - spinCachePercent->SetToolTip(wxTRANS("Set the maximum amount of RAM to use in order to speed repeat computations")); - btnFilterTreeCollapse->SetToolTip(wxTRANS("Collapse the filter tree")); - btnFilterTreeExpand->SetToolTip(wxTRANS("Expand the filter tree")); - refreshButton->SetToolTip (wxTRANS("Process the filter tree, hold shift to purge cached filter data")); - - // end wxGlade - // - - PlotWrapper *p=new PlotWrapper; //plotting area - - panelSpectra->setPlotWrapper(p); - panelSpectra->setPlotList(plotList); - - //Set the controls that the viscontrol needs to interact with - visControl.setScene(&panelTop->currentScene); //GL scene - visControl.setRawGrid(gridRawData); //Raw data grid - visControl.setPlotWrapper(p); - visControl.setPlotList(plotList); - visControl.setConsole(textConsoleOut); - - - refreshButton->Enable(false); -#if wxCHECK_VERSION(2, 9, 0) - comboCamera->Bind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboCameraSetFocus, this); - comboStash->Bind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboStashSetFocus, this); - noteDataView->Bind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MainWindowFrame::OnNoteDataView, this); -#else - comboCamera->Connect(wxID_ANY, - wxEVT_SET_FOCUS, - wxFocusEventHandler(MainWindowFrame::OnComboCameraSetFocus), NULL, this); - comboStash->Connect(wxID_ANY, - wxEVT_SET_FOCUS, - wxFocusEventHandler(MainWindowFrame::OnComboStashSetFocus), NULL, this); - noteDataView->Connect(wxID_ANY, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, - wxNotebookEventHandler(MainWindowFrame::OnNoteDataView),NULL,this); -#endif - gridCameraProperties->clear(); - int widths[] = {-4,-2,-1}; - MainFrame_statusbar->SetStatusWidths(3,widths); - -} - -void MainWindowFrame::do_layout() -{ - // begin wxGlade: MainWindowFrame::do_layout - wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerTools = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerToolsRamUsage = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* postProcessSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerFxStereo = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerSetereoBaseline = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerStereoCombo = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* cropFxSizer = new wxBoxSizer(wxVERTICAL); - wxFlexGridSizer* sizerFxCropGridLow = new wxFlexGridSizer(3, 2, 2, 2); - wxBoxSizer* cropFxBodyCentreSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* rightPanelSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* textConsoleSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* rawDataGridSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* rawDataSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* plotListSizery = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* topPanelSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerFxCropRHS = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerFxCropLHS = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* camPaneSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* camTopRowSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* filterPaneSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* filterPropGridSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* filterTreeLeftRightSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* filterRightOfTreeSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* filterMainCtrlSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* stashRowSizer = new wxBoxSizer(wxHORIZONTAL); - filterPaneSizer->Add(lblSettings, 0, 0, 0); - stashRowSizer->Add(comboStash, 1, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 3); - stashRowSizer->Add(btnStashManage, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); - filterPaneSizer->Add(stashRowSizer, 0, wxEXPAND, 0); - filterPaneSizer->Add(filteringLabel, 0, 0, 0); - filterMainCtrlSizer->Add(comboFilters, 0, wxLEFT|wxRIGHT|wxEXPAND, 4); - filterMainCtrlSizer->Add(treeFilters, 3, wxLEFT|wxBOTTOM|wxEXPAND, 3); - filterMainCtrlSizer->Add(lastRefreshLabel, 0, wxTOP, 8); - filterMainCtrlSizer->Add(listLastRefresh, 1, wxBOTTOM|wxEXPAND, 5); - filterTreeLeftRightSizer->Add(filterMainCtrlSizer, 3, wxEXPAND, 0); - filterRightOfTreeSizer->Add(checkAutoUpdate, 0, 0, 0); - filterRightOfTreeSizer->Add(10, 10, 0, 0, 0); - filterRightOfTreeSizer->Add(refreshButton, 0, wxALL, 2); - filterRightOfTreeSizer->Add(20, 20, 0, 0, 0); - filterRightOfTreeSizer->Add(btnFilterTreeCollapse, 0, wxLEFT, 6); - filterRightOfTreeSizer->Add(btnFilterTreeExpand, 0, wxLEFT, 6); - filterRightOfTreeSizer->Add(10, 10, 0, 0, 0); - filterRightOfTreeSizer->Add(btnFilterTreeErrs,0,wxLEFT,6); - btnFilterTreeErrs->Show(false); - filterTreeLeftRightSizer->Add(filterRightOfTreeSizer, 2, wxEXPAND, 0); - filterTreePane->SetSizer(filterTreeLeftRightSizer); - filterPropGridSizer->Add(propGridLabel, 0, 0, 0); - filterPropGridSizer->Add(gridFilterPropGroup, 1, wxLEFT|wxEXPAND, 4); - filterPropertyPane->SetSizer(filterPropGridSizer); -// filterSplitter->SplitHorizontally(filterTreePane, filterPropertyPane);//DISABLED This has to be done later to get the window to work. - filterPaneSizer->Add(filterSplitter, 1, wxEXPAND, 0); - noteData->SetSizer(filterPaneSizer); - camPaneSizer->Add(labelCameraName, 0, 0, 0); - camTopRowSizer->Add(comboCamera, 3, 0, 0); - camTopRowSizer->Add(buttonRemoveCam, 0, wxLEFT|wxRIGHT, 2); - camPaneSizer->Add(camTopRowSizer, 0, wxTOP|wxBOTTOM|wxEXPAND, 4); - camPaneSizer->Add(cameraNamePropertySepStaticLine, 0, wxEXPAND, 0); - camPaneSizer->Add(gridCameraProperties, 1, wxEXPAND, 0); - noteCamera->SetSizer(camPaneSizer); -#ifndef APPLE_EFFECTS_WORKAROUND - postProcessSizer->Add(checkPostProcessing, 0, wxALL, 5); +#include +#include +#include +#ifdef __APPLE__ +#include +#include "CoreFoundation/CoreFoundation.h" #endif - cropFxSizer->Add(checkFxCrop, 0, wxALL, 6); - cropFxSizer->Add(checkFxCropCameraFrame, 0, wxLEFT, 15); - sizerFxCropLHS->Add(comboFxCropAxisOne, 0, wxRIGHT|wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5); - sizerFxCropLHS->Add(panelFxCropOne, 1, wxRIGHT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - cropFxBodyCentreSizer->Add(sizerFxCropLHS, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); - sizerFxCropRHS->Add(comboFxCropAxisTwo, 0, wxLEFT|wxBOTTOM|wxEXPAND, 5); - sizerFxCropRHS->Add(panelFxCropTwo, 1, wxLEFT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - cropFxBodyCentreSizer->Add(sizerFxCropRHS, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); - cropFxSizer->Add(cropFxBodyCentreSizer, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5); - sizerFxCropGridLow->Add(labelFxCropDx, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); - sizerFxCropGridLow->Add(textFxCropDx, 0, 0, 0); - sizerFxCropGridLow->Add(labelFxCropDy, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); - sizerFxCropGridLow->Add(textFxCropDy, 0, 0, 0); - sizerFxCropGridLow->Add(labelFxCropDz, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); - sizerFxCropGridLow->Add(textFxCropDz, 0, 0, 0); - sizerFxCropGridLow->AddGrowableRow(0); - sizerFxCropGridLow->AddGrowableRow(1); - sizerFxCropGridLow->AddGrowableRow(2); - sizerFxCropGridLow->AddGrowableCol(0); - sizerFxCropGridLow->AddGrowableCol(1); - cropFxSizer->Add(sizerFxCropGridLow, 0, wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - noteFxPanelCrop->SetSizer(cropFxSizer); - sizerFxStereo->Add(checkFxEnableStereo, 0, wxLEFT|wxTOP, 6); - sizerFxStereo->Add(20, 20, 0, 0, 0); - sizerStereoCombo->Add(lblFxStereoMode, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); - sizerStereoCombo->Add(comboFxStereoMode, 0, wxLEFT, 5); - sizerStereoCombo->Add(bitmapFxStereoGlasses, 0, 0, 0); - sizerFxStereo->Add(sizerStereoCombo, 0, wxBOTTOM|wxEXPAND, 15); - sizerSetereoBaseline->Add(labelFxStereoBaseline, 0, wxLEFT|wxTOP, 5); - sizerSetereoBaseline->Add(sliderFxStereoBaseline, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5); - sizerFxStereo->Add(sizerSetereoBaseline, 0, wxEXPAND, 0); - sizerFxStereo->Add(checkFxStereoLensFlip, 0, wxLEFT, 5); - noteFxPanelStereo->SetSizer(sizerFxStereo); - noteEffects->AddPage(noteFxPanelCrop, wxTRANS("Crop")); - noteEffects->AddPage(noteFxPanelStereo, wxTRANS("Stereo")); - postProcessSizer->Add(noteEffects, 1, wxEXPAND, 0); - notePost->SetSizer(postProcessSizer); - sizerTools->Add(checkAlphaBlend, 0, wxLEFT|wxTOP|wxBOTTOM, 5); - sizerTools->Add(checkLighting, 0, wxLEFT|wxTOP|wxBOTTOM, 6); - sizerTools->Add(checkWeakRandom, 0, wxLEFT|wxTOP|wxBOTTOM, 5); - sizerTools->Add(checkCaching, 0, wxLEFT|wxTOP|wxBOTTOM, 5); - sizerToolsRamUsage->Add(labelMaxRamUsage, 0, wxRIGHT|wxALIGN_RIGHT, 5); - sizerToolsRamUsage->Add(spinCachePercent, 0, 0, 5); - sizerTools->Add(sizerToolsRamUsage, 1, wxTOP|wxEXPAND, 5); - noteTools->SetSizer(sizerTools); - notebookControl->AddPage(noteData, wxTRANS("Data")); - notebookControl->AddPage(noteCamera, wxTRANS("Cam")); - notebookControl->AddPage(notePost, wxTRANS("Post")); - notebookControl->AddPage(noteTools, wxTRANS("Tools")); - sizerLeft->Add(notebookControl, 1, wxLEFT|wxBOTTOM|wxEXPAND, 2); - panelLeft->SetSizer(sizerLeft); - topPanelSizer->Add(panelView, 1, wxEXPAND, 0); - panelTop->SetSizer(topPanelSizer); - plotListSizery->Add(plotListLabel, 0, 0, 0); - plotListSizery->Add(plotList, 1, wxEXPAND, 0); - window_2_pane_2->SetSizer(plotListSizery); - splitterSpectra->SplitVertically(panelSpectra, window_2_pane_2); - rawDataGridSizer->Add(gridRawData, 3, wxEXPAND, 0); - rawDataSizer->Add(20, 20, 1, 0, 0); - rawDataSizer->Add(btnRawDataSave, 0, wxLEFT, 2); - rawDataSizer->Add(btnRawDataClip, 0, wxLEFT, 2); - rawDataGridSizer->Add(rawDataSizer, 0, wxTOP|wxEXPAND, 5); - noteRaw->SetSizer(rawDataGridSizer); - textConsoleSizer->Add(textConsoleOut, 1, wxEXPAND, 0); - noteDataViewConsole->SetSizer(textConsoleSizer); - noteDataView->AddPage(splitterSpectra, wxTRANS("Plot")); - noteDataView->AddPage(noteRaw, wxTRANS("Raw")); - noteDataView->AddPage(noteDataViewConsole, wxTRANS("Cons.")); - splitTopBottom->SplitHorizontally(panelTop, noteDataView); - rightPanelSizer->Add(splitTopBottom, 1, wxEXPAND, 0); - panelRight->SetSizer(rightPanelSizer); - splitLeftRight->SplitVertically(panelLeft, panelRight); - topSizer->Add(splitLeftRight, 1, wxEXPAND, 0); - SetSizer(topSizer); - Layout(); - // end wxGlade - // - // GTK fix hack thing. reparent window - - - - panelTop->Reparent(splitTopBottom); - //Set the combo text - haveSetComboCamText=false; - comboCamera->SetValue(wxCStr(TRANS(cameraIntroString))); - haveSetComboStashText=false; - comboStash->SetValue(wxCStr(TRANS(stashIntroString))); +#include "common/translation.h" +#include "gui/mainFrame.h" -} +//Unit testing code +#include "testing.h" -#ifdef DEBUG -void MainWindowFrame::setEventloggerFile() +enum { - fs.open((configFile.getConfigDir()+stlStr(wxFileName::GetPathSeparator())+string("eventlog.txt")).c_str()); - if (fs) - evtlog.setostream(&fs); -} -#endif + ID_MAIN_WINDOW=wxID_ANY+1, +}; class threeDepictApp: public wxApp { private: @@ -5618,6 +59,10 @@ void MacOpenFile(const wxString & fileName); void MacReopenFile(const wxString & fileName); #endif + +#ifdef DEBUG + void setEventloggerFile(const char *file); +#endif }; //Check version is in place because wxT is deprecated for wx 2.9 @@ -5649,6 +94,24 @@ }; +#ifdef __WXMSW__ +//Force a windows console to show for cerr/cout +#ifdef DEBUG +#include "winconsole.h" +winconsole winC; +#endif +#endif + +//DEBUG NaN and INF +#ifdef DEBUG +#ifdef __linux__ +#include +void trapfpe () { +// feenableexcept(FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW); +} +#endif +#endif + IMPLEMENT_APP(threeDepictApp) threeDepictApp::threeDepictApp() @@ -5749,10 +212,7 @@ //Catching key events globally. int threeDepictApp::FilterEvent(wxEvent& event) { -#ifdef DEBUG - evtlog.insert(event); -#endif - //Process global keyboard (non-accellerator) events + //Process global keyboard (non-accelerator) events if ( event.GetEventType()==wxEVT_KEY_DOWN ) { if(MainFrame) @@ -5819,7 +279,7 @@ version=wxCStr(PROGRAM_VERSION); version+=wxT("\n"); - preamble=wxT("Copyright (C) 2011 3Depict team\n"); + preamble=wxT("Copyright (C) 2013 3Depict team\n"); preamble+=wxT("This program comes with ABSOLUTELY NO WARRANTY; for details see LICENCE file.\n"); preamble+=wxT("This is free software, and you are welcome to redistribute it under certain conditions.\n"); preamble+=wxT("Source code is available under the terms of the GNU GPL v3.0 or any later version (http://www.gnu.org/licenses/gpl.txt)\n"); @@ -5939,7 +399,6 @@ #endif - bool threeDepictApp::OnInit() { @@ -5967,12 +426,9 @@ SetTopWindow(MainFrame); -#ifdef DEBUG -#ifdef __linux__ +#if defined(DEBUG) && defined(__linux__) trapfpe(); //Under Linux, enable segfault on invalid floating point operations #endif - MainFrame->setEventloggerFile(); //Enable event logging -#endif #ifdef __APPLE__ //Switch the working directory into the .app bundle's resources diff -Nru 3depict-0.0.12/src/3Depict.h 3depict-0.0.13/src/3Depict.h --- 3depict-0.0.12/src/3Depict.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/3Depict.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,379 +0,0 @@ -/* - * 3Depict.h - main program header - * 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 - * 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 . -*/ - - -// begin wxGlade: ::dependencies -#include -#include -#include -#include -#include -#include -#include -#include -#include -// end wxGlade - -//Local stuff -#include "wxcommon.h" -#include "glPane.h" -#include "mathglPane.h" -#include "cropPanel.h" // cropping tools - -#include "APTClasses.h" -#include "viscontrol.h" -#include "configFile.h" - -#ifndef THREEDEPICT_H -#define THREEDEPICT_H - -class FileDropTarget; - -class MainWindowFrame: public wxFrame { -public: - // begin wxGlade: MainWindowFrame::ids - // end wxGlade - - MainWindowFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE); - virtual ~MainWindowFrame(); - - //Drop the following files onto the given window XY coordinates. - void OnDropFiles(const wxArrayString &files, int x, int y); - - bool isCurrentlyUpdatingScene() const { return currentlyUpdatingScene;}; - - void linkCropWidgets(); - - wxSize getNiceWindowSize() const ; - -#ifdef DEBUG - void setEventloggerFile(); -#endif - -private: - // begin wxGlade: MainWindowFrame::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //!Give a message in the satus bar - void statusMessage(const char *message, unsigned int messageType=MESSAGE_ERROR); - - //!Update the progress information in the status bar - void updateProgressStatus(); - //!Perform an update to the 3D Scene. Returns false if refresh failed - bool doSceneUpdate(); - - //!Update the post-processing effects in the 3D scene. - void updatePostEffects(); - //!Load a file into the panel given the full path to the file - bool loadFile(const wxString &dataFile,bool merge=false); - - //!Load any errors that were detected in the last refresh into the filter tree - void setFilterTreeAnalysisImages(); - - //!Update the effects UI from some effects vector - void updateFxUI(const vector &fx); - - void setLockUI(bool amlocking,unsigned int lockMode); - - //!Scene - user interaction interface "visualisation control" - VisController visControl; - - //!Program on-disk configuration class - ConfigFile configFile; - - //!Blocking bool to prevent functions from responding to programatically generated wx events - bool programmaticEvent,timerEvent; - //!A flag stating if the first update needs a refresh after GL window OK - bool requireFirstUpdate; - //!Have we set the combo cam/stash text in this session? - bool haveSetComboCamText,haveSetComboStashText; - //!Are we in the middle of updating the scene? - bool currentlyUpdatingScene; - //!Have we aborted an update - bool haveAborted; - - //!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; - - //!Current fullscreen status - unsigned int fullscreenState; - - //!Did the main frame's constructor complete OK? - bool initedOK; - - //The type of status message last sent to user - unsigned int lastMessageType; - - //Pointer to version check thread, occasionally initialised at startup to - // check online for new program updates - VersionCheckThread *verCheckThread; - - //Map to convert filter drop down choices to IDs - map filterMap; - - -#ifdef DEBUG - ofstream fs; // file for writing the event log -#endif -protected: - wxTimer *statusTimer; - wxTimer *progressTimer; - wxTimer *updateTimer; //Periodically calls itself to check for updates from user interaction - wxTimer *autoSaveTimer; //Periodically calls itself to create an autosave state file - wxMenuItem *checkMenuControlPane; - wxMenuItem *checkMenuRawDataPane; - wxMenuItem *checkMenuSpectraList; - wxMenuItem *menuViewFullscreen; - wxMenuItem *checkViewLegend; - wxMenuItem *checkViewWorldAxis; - - wxMenuItem *editUndoMenuItem,*editRedoMenuItem; - wxMenuItem *fileSave; - wxMenu *recentFilesMenu; - wxFileHistory *recentHistory; - - - // begin wxGlade: MainWindowFrame::attributes - wxMenuBar* MainFrame_Menu; - wxStaticText* lblSettings; - wxComboBox* comboStash; - wxButton* btnStashManage; - wxStaticText* filteringLabel; - wxComboBox* comboFilters; - wxTreeCtrl* treeFilters; - wxStaticText* lastRefreshLabel; - wxListCtrl* listLastRefresh; - wxCheckBox* checkAutoUpdate; - wxButton* refreshButton; - wxButton* btnFilterTreeExpand; - wxButton* btnFilterTreeCollapse; - wxBitmapButton* btnFilterTreeErrs; - wxPanel* filterTreePane; - wxStaticText* propGridLabel; - wxPropertyGrid* gridFilterPropGroup; - wxPanel* filterPropertyPane; - wxSplitterWindow* filterSplitter; - wxPanel* noteData; - wxStaticText* labelCameraName; - wxComboBox* comboCamera; - wxButton* buttonRemoveCam; - wxStaticLine* cameraNamePropertySepStaticLine; - wxPropertyGrid* gridCameraProperties; - wxScrolledWindow* noteCamera; - wxCheckBox* checkPostProcessing; - wxCheckBox* checkFxCrop; - wxComboBox* comboFxCropAxisOne; - CropPanel* panelFxCropOne; - wxComboBox* comboFxCropAxisTwo; - CropPanel* panelFxCropTwo; - wxCheckBox* checkFxCropCameraFrame; - wxStaticText* labelFxCropDx; - wxTextCtrl* textFxCropDx; - wxStaticText* labelFxCropDy; - wxTextCtrl* textFxCropDy; - wxStaticText* labelFxCropDz; - wxTextCtrl* textFxCropDz; - wxPanel* noteFxPanelCrop; - wxCheckBox* checkFxEnableStereo; - wxCheckBox* checkFxStereoLensFlip; - wxStaticText* lblFxStereoMode; - wxComboBox* comboFxStereoMode; - wxStaticBitmap* bitmapFxStereoGlasses; - wxStaticText* labelFxStereoBaseline; - wxSlider* sliderFxStereoBaseline; - wxPanel* noteFxPanelStereo; - wxNotebook* noteEffects; - wxPanel* notePost; - wxCheckBox* checkAlphaBlend; - wxCheckBox* checkLighting; - wxCheckBox* checkWeakRandom; - wxCheckBox* checkCaching; - wxStaticText* labelMaxRamUsage; - wxSpinCtrl* spinCachePercent; - wxPanel* noteTools; - wxNotebook* notebookControl; - wxPanel* panelLeft; - wxPanel* panelView; - BasicGLPane* panelTop; - MathGLPane* panelSpectra; - wxStaticText* plotListLabel; - wxListBox* plotList; - wxPanel* window_2_pane_2; - wxSplitterWindow* splitterSpectra; - CopyGrid* gridRawData; - wxButton* btnRawDataSave; - wxButton* btnRawDataClip; - wxPanel* noteRaw; - wxTextCtrl* textConsoleOut; - wxPanel* noteDataViewConsole; - wxNotebook* noteDataView; - wxPanel* panelBottom; - wxSplitterWindow* splitTopBottom; - wxPanel* panelRight; - wxSplitterWindow* splitLeftRight; - wxStatusBar* MainFrame_statusbar; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnFileOpen(wxCommandEvent &event); // wxGlade: - virtual void OnFileMerge(wxCommandEvent &event); // wxGlade: - virtual void OnFileSave(wxCommandEvent &event); // wxGlade: - virtual void OnFileSaveAs(wxCommandEvent &event); // wxGlade: - virtual void OnFileExit(wxCommandEvent &event); // wxGlade: - virtual void OnViewControlPane(wxCommandEvent &event); // wxGlade: - virtual void OnViewRawDataPane(wxCommandEvent &event); // wxGlade: - virtual void OnHelpHelp(wxCommandEvent &event); // wxGlade: - virtual void OnHelpContact(wxCommandEvent &event); // wxGlade: - virtual void OnHelpAbout(wxCommandEvent &event); // wxGlade: - virtual void OnComboStashText(wxCommandEvent &event); // wxGlade: - virtual void OnComboStashEnter(wxCommandEvent &event); // wxGlade: - virtual void OnComboStash(wxCommandEvent &event); // wxGlade: - virtual void OnTreeEndDrag(wxTreeEvent &event); // wxGlade: - virtual void OnTreeKeyDown(wxTreeEvent &event); // wxGlade: - virtual void OnTreeSelectionChange(wxTreeEvent &event); // wxGlade: - virtual void OnTreeDeleteItem(wxTreeEvent &event); // wxGlade: - virtual void OnTreeBeginDrag(wxTreeEvent &event); // wxGlade: - virtual void OnBtnExpandTree(wxCommandEvent &event); // wxGlade: - virtual void OnBtnCollapseTree(wxCommandEvent &event); // wxGlade: - virtual void OnBtnFilterTreeErrs(wxCommandEvent &event); // wxGlade: - virtual void OnComboCameraText(wxCommandEvent &event); // wxGlade: - - virtual void OnGridFilterPropertyChange(wxGridEvent &event); // wxGlade: - virtual void OnComboCameraEnter(wxCommandEvent &event); // wxGlade: - virtual void OnComboCamera(wxCommandEvent &event); // wxGlade: - - - virtual void OnEditUndo(wxCommandEvent &event); - virtual void OnEditRedo(wxCommandEvent &event); - virtual void OnEditPreferences(wxCommandEvent &event); - - - - virtual void OnButtonRemoveCam(wxCommandEvent &event); // wxGlade: - virtual void OnCheckPostProcess(wxCommandEvent &event); // wxGlade: - virtual void OnFxCropCheck(wxCommandEvent &event); // wxGlade: - virtual void OnFxCropCamFrameCheck(wxCommandEvent &event); // wxGlade: - virtual void OnFxCropAxisOne(wxCommandEvent &event); // wxGlade: - virtual void OnFxCropAxisTwo(wxCommandEvent &event); // wxGlade: - virtual void OnFxStereoEnable(wxCommandEvent &event); // wxGlade: - virtual void OnFxStereoCombo(wxCommandEvent &event); // wxGlade: - virtual void OnFxStereoBaseline(wxScrollEvent &event); // wxGlade: - virtual void OnFxStereoLensFlip(wxCommandEvent &event); // wxGlade: - virtual void OnButtonStashDialog(wxCommandEvent &event); // wxGlade: - virtual void OnCheckAlpha(wxCommandEvent &event); // wxGlade: - virtual void OnCheckLighting(wxCommandEvent &event); // wxGlade: - virtual void OnCheckCacheEnable(wxCommandEvent &event); // wxGlade: - virtual void OnCheckWeakRandom(wxCommandEvent &event); // wxGlade: - virtual void OnCacheRamUsageSpin(wxSpinEvent &event); // wxGlade: - virtual void OnSpectraListbox(wxCommandEvent &event); // wxGlade: - - virtual void OnComboFilterEnter(wxCommandEvent &event); // - virtual void OnComboFilter(wxCommandEvent &event); // - - virtual void OnStatusBarTimer(wxTimerEvent &event); // - virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // - virtual void OnFilterGridCellEditorHide(wxGridEvent &event); // - virtual void OnCameraGridCellEditorShow(wxGridEvent &event); // - virtual void OnCameraGridCellEditorHide(wxGridEvent &event); // - virtual void OnProgressTimer(wxTimerEvent &event); - virtual void OnProgressAbort(wxCommandEvent &event); - virtual void OnViewFullscreen(wxCommandEvent &event); - virtual void OnButtonRefresh(wxCommandEvent &event); - virtual void OnButtonGridCopy(wxCommandEvent &event); - virtual void OnButtonGridSave(wxCommandEvent &event); - virtual void OnRawDataUnsplit(wxSplitterEvent &event); - virtual void OnFilterPropDoubleClick(wxSplitterEvent &event); - virtual void OnControlUnsplit(wxSplitterEvent &event); - virtual void OnControlSplitMove(wxSplitterEvent &event); - virtual void OnTopBottomSplitMove(wxSplitterEvent &event); - virtual void OnSpectraUnsplit(wxSplitterEvent &event); - virtual void OnViewSpectraList(wxCommandEvent &event); - virtual void OnViewPlotLegend(wxCommandEvent &event); - virtual void OnViewWorldAxis(wxCommandEvent &event); - virtual void OnViewBackground(wxCommandEvent &event); - virtual void OnClose(wxCloseEvent &evt); - virtual void OnComboCameraSetFocus(wxFocusEvent &evt); - virtual void OnComboStashSetFocus(wxFocusEvent &evt); - virtual void OnNoteDataView(wxNotebookEvent &evt); - virtual void OnGridCameraPropertyChange(wxGridEvent &event); // wxGlade: - - virtual void OnFileExportPlot(wxCommandEvent &event); // wxGlade: - virtual void OnFileExportImage(wxCommandEvent &event); // wxGlade: - virtual void OnFileExportIons(wxCommandEvent &event); // wxGlade: - virtual void OnFileExportRange(wxCommandEvent &event); // wxGlade: - virtual void OnFileExportVideo(wxCommandEvent &event); - virtual void OnFileExportFilterVideo(wxCommandEvent &event); - virtual void OnFileExportPackage(wxCommandEvent &event); - virtual void OnRecentFile(wxCommandEvent &event); // wxGlade: - - virtual void OnTreeBeginLabelEdit(wxTreeEvent &evt); - virtual void OnTreeEndLabelEdit(wxTreeEvent &evt); - virtual void OnUpdateTimer(wxTimerEvent &evt); - virtual void OnAutosaveTimer(wxTimerEvent &evt); - - virtual void OnCheckUpdatesThread(wxCommandEvent &evt); - - virtual void SetCommandLineFiles(wxArrayString &files); - virtual void updateLastRefreshBox(); - - - //Check to see if we need to reload an autosave file (and reload it, as needed) - void checkReloadAutosave(); - - bool initOK() const {return initedOK;} - - //This is isolated from the layout code, due to "bug" 4815 in wx. The splitter window - //does not know how to choose a good size until the window is shown - void fixSplitterWindow() { - filterSplitter->SplitHorizontally(filterTreePane,filterPropertyPane); - splitTopBottom->SplitHorizontally(panelTop, noteDataView); - splitTopBottom->SetSashPosition(GetSize().GetHeight()/10*7); - }; - -}; // wxGlade: end class - - -class FileDropTarget : public wxFileDropTarget -{ -private: - MainWindowFrame *frame; -public: - FileDropTarget(MainWindowFrame *f) { - frame = f; - } - - virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& files) - { - frame->OnDropFiles(files, x, y); - - return true; - }; - -}; - -#endif diff -Nru 3depict-0.0.12/src/3Depict.xpm 3depict-0.0.13/src/3Depict.xpm --- 3depict-0.0.12/src/3Depict.xpm 2012-11-11 14:34:01.000000000 +0000 +++ 3depict-0.0.13/src/3Depict.xpm 1970-01-01 00:00:00.000000000 +0000 @@ -1,267 +0,0 @@ -/* XPM */ -static const char *_Depict[] = { -/* columns rows colors chars-per-pixel */ -"32 32 229 2", -" c #5D251D", -". c #602C26", -"X c #6B2D25", -"o c #752D24", -"O c #7E2F25", -"+ c #65322C", -"@ c #73342C", -"# c #653934", -"$ c #613E39", -"% c #773A32", -"& c #35410F", -"* c #056933", -"= c #10723D", -"- c #615926", -"; c #61423E", -": c #60602B", -"> c #29385D", -", c #1B1B7F", -"< c #2E1E62", -"1 c #012370", -"2 c #163A75", -"3 c #2B2B75", -"4 c #23237A", -"5 c #353570", -"6 c #3A3A72", -"7 c #5D234B", -"8 c #64264C", -"9 c #622751", -"0 c #431B66", -"q c #482677", -"w c #57367C", -"e c #67376B", -"r c #014D4D", -"t c #094B54", -"y c #004D5E", -"u c #21447A", -"i c #306D69", -"p c #64524D", -"a c #87342A", -"s c #893429", -"d c #91362B", -"f c #97382E", -"g c #9A392D", -"h c #843D35", -"j c #883B32", -"k c #913E34", -"l c #993B30", -"z c #A23C2F", -"x c #A23C30", -"c c #8D4239", -"v c #9D453B", -"b c #9C493F", -"n c #AD4034", -"m c #B04134", -"M c #853140", -"N c #843749", -"B c #993944", -"V c #864D47", -"C c #9B574F", -"Z c #90475A", -"A c #935F59", -"S c #A5574D", -"D c #AC584F", -"F c #B8594D", -"G c #A95C53", -"H c #B65952", -"J c #856741", -"K c #B9665C", -"L c #9E736D", -"P c #B56E66", -"I c #BC6A62", -"U c #BD766E", -"Y c #A67F7A", -"T c #B17A74", -"R c #BB7A73", -"E c #C05E51", -"W c #C16D63", -"Q c #C37D75", -"! c #038103", -"~ c #008B00", -"^ c #088108", -"/ c #0B8D0C", -"( c #019301", -") c #009E00", -"_ c #0B9E0B", -"` c #00871F", -"' c #108710", -"] c #138913", -"[ c #188C18", -"{ c #159215", -"} c #1E9515", -"| c #25951D", -" . c #02A402", -".. c #01AA01", -"X. c #01B101", -"o. c #00BA00", -"O. c #00B60A", -"+. c #0AB40A", -"@. c #00AB14", -"#. c #00A61B", -"$. c #19A619", -"%. c #00B417", -"&. c #14B314", -"*. c #1FB31F", -"=. c #1CBA1C", -"-. c #21A11C", -";. c #1CA62B", -":. c #27AC27", -">. c #23B223", -",. c #26BC26", -"<. c #23A630", -"1. c #3AAD3A", -"2. c #00C100", -"3. c #00C900", -"4. c #00CC0D", -"5. c #00D100", -"6. c #00D900", -"7. c #00E200", -"8. c #00EB00", -"9. c #00F200", -"0. c #2AC12A", -"q. c #29CA29", -"w. c #33CC33", -"e. c #3BA74C", -"r. c #4BB54B", -"t. c #5BBE64", -"y. c #44C544", -"u. c #50C850", -"i. c #50D851", -"p. c #62CF62", -"a. c #62D161", -"s. c #6BDB6B", -"d. c #7BCD7B", -"f. c #74D474", -"g. c #7EDD7E", -"h. c #04058D", -"j. c #000F8F", -"k. c #150C89", -"l. c #001184", -"z. c #001E82", -"x. c #151586", -"c. c #010195", -"v. c #000B90", -"b. c #05059F", -"n. c #0B0B9D", -"m. c #0D1790", -"M. c #141491", -"N. c #21158C", -"B. c #271F97", -"V. c #211C9F", -"C. c #263D8E", -"Z. c #0202A4", -"A. c #0A0AA6", -"S. c #0303AC", -"D. c #0D0BAB", -"F. c #1313AE", -"G. c #1D1DAF", -"H. c #0101B2", -"J. c #0E0EB0", -"K. c #0000BB", -"L. c #1617B1", -"P. c #1E1DB4", -"I. c #1C1BBC", -"U. c #2121AE", -"Y. c #2D2DB7", -"T. c #3131B5", -"R. c #3E3EBC", -"E. c #573B84", -"W. c #4943AE", -"Q. c #4040B9", -"!. c #0000C2", -"~. c #0000CB", -"^. c #0000D2", -"/. c #0000DA", -"(. c #2627C5", -"). c #2E2CC3", -"_. c #3131C0", -"`. c #3C3CCD", -"'. c #0000E3", -"]. c #0000EB", -"[. c #0000F2", -"{. c #5151C3", -"}. c #5E5EC4", -"|. c #4949D5", -" X c #5D5DD1", -".X c #6C6EC6", -"XX c #7676CE", -"oX c #7C7CCF", -"OX c #6263D7", -"+X c #AB8985", -"@X c #AE8D89", -"#X c #C58D86", -"$X c #C3908A", -"%X c #C39791", -"&X c #C79D97", -"*X c #C79D98", -"=X c #C89E99", -"-X c #CBABA7", -";X c #CAAEAA", -":X c #CDB8B6", -">X c #CEBEBD", -",X c #80D780", -"X>X>X>X:X%XC @ jXjXjXjX", -"jXjXjXjXjXjXjXjX] [ ' jXjXjXjX. c R -X;X;X;X;X;X;X;X%XS @ jXjXjX", -"jXjXjXjXjX{ r.1X4X6X3Xd.1./ & h S $X&X&X&X&X&X&X&X&X&XP b X jXjX", -"jXjXjX^ :.g.aXsXsXsXsXsX8Xa.| - S #X#X#X#X#X$X#X#X#X#XP v j jX", -"jXjX^ >.s.6X6X6X7X7X7X7X7X5Xi.-.- U Q Q Q Q Q Q Q Q Q G k k X jX", -"jXjX$.w.g.5X2X2X2X2X2X2X2X2Xs.q.} J I I W W W W I W K k a a o jX", -"jX/ =.0.f. E.E.w e Z H E F v a s s O . ", -"jX_ &.&.u.p.p.p.p.p.p.p.a.t.i C..XyXdXfXpX0XW.q N l d d d d s + ", -"! . . .*.y.y.y.r.y.y.y.e.u R.rXgXgXgXgXgXgXpXOXB.7 g g f f d + ", -"~ .......&.,.,.,.,.,.<.2 ).eXiXuXuXuXuXiXiXiXtX|.V.8 x z z d # ", -"~ ..X.X.X.X.X.+.+.+.+.t P.`.qXwXwXwXwXwXwXwXwXwX X(.N.M m x a ; ", -"( o.o.o.o.o.o.o.o.o.` m.I._.XXoXoXoXoXoXoXoXoXoX{.I.L.0 m m @ jX", -"( o.2.2.2.2.2.2.2.o.r A.J.P.W.}.}.}.}.}.}.}.}.}.Y.J.J.k.B l $ jX", -"! o.3.3.3.3.3.3.3.O.1 Z.S.S.U.R.R.Q.Q.Q.Q.Q.Q.T.A.S.Z.c.9 @ jXjX", -"jX..5.5.5.5.5.5.5.@.l.S.S.Z.S.F.U.U.U.U.U.U.P.A.S.S.S.Z.< p jXjX", -"jX~ 3.6.6.6.6.6.6.#.v.H.H.H.H.H.H.H.S.D.S.S.H.H.H.H.S.S.x.jXjXjX", -"jXjX) 6.7.7.7.6.8.%.j.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.H., jXjXjX", -"jXjXjX .6.8.8.8.8.4.z.!.!.!.!.!.!.!.!.!.!.K.!.!.!.!.!.S.4 jXjXjX", -"jXjXjXjX) 2.7.8.9.8.y !.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.n.6 jXjXjX", -"jXjXjXjXjXjX( +.o.2.* H.^.^.^.^.^.^.^.^.^.^.^.^.^.^.~.x.jXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXh.~./././././././././././././.S.5 jXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXZ./.'.'.'.'.'.'.'.'.'.'.'.K.4 jXjXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXjXZ./.].].].].].].].].].K.4 jXjXjXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXjXjXc.K./.].[.[.[.'.~.n.3 jXjXjXjXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXv.A.S.J.A.M.4 jXjXjXjXjXjXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX", -"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX" -}; diff -Nru 3depict-0.0.12/src/APTClasses.cpp 3depict-0.0.13/src/APTClasses.cpp --- 3depict-0.0.12/src/APTClasses.cpp 2012-11-11 19:54:04.000000000 +0000 +++ 3depict-0.0.13/src/APTClasses.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,3069 +0,0 @@ -/* - * APTClasses.h - Generic APT components code - * 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 - * 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 . - */ - -#include "APTClasses.h" - -#include "translation.h" - -#include -#include -#include -#include -#include -#include -#include - -using std::pair; -using std::string; -using std::vector; -using std::ifstream; -using std::make_pair; -using std::map; - -//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"} -}; - -const char *RANGE_EXTS[] = { "rng", - "rrng", - "env", - ""}; -const char *POS_ERR_STRINGS[] = { "", - NTRANS("Memory allocation failure on POS load"), - NTRANS("Error opening pos file"), - NTRANS("Pos file empty"), - NTRANS("Pos file size appears to have non-integer number of entries"), - NTRANS("Error reading from pos file (after open)"), - NTRANS("Error - Found NaN in pos file"), - NTRANS("Pos load aborted by interrupt.") -}; - -enum -{ - TEXT_ERR_OPEN=1, - TEXT_ERR_ONLY_HEADER, - TEXT_ERR_REOPEN, - TEXT_ERR_READ_CONTENTS, - TEXT_ERR_FORMAT, - TEXT_ERR_NUM_FIELDS, - TEXT_ERR_ALLOC_FAIL, - TEXT_ERR_ENUM_END //not an error, just end of enum -}; - -const char *ION_TEXT_ERR_STRINGS[] = { "", - NTRANS("Error opening file"), - NTRANS("No numerical data found"), - NTRANS("Error re-opening file, after first scan"), - NTRANS("Unable to read file contents after open"), - NTRANS("Error interpreting field in file"), - NTRANS("Incorrect number of fields in file"), - NTRANS("Unable to allocate memory to store data"), - }; -const char *rangeErrStrings[] = -{ - "", - NTRANS("Error opening file, check name and permissions."), - NTRANS("Error interpreting range file header, expecting ion count and range count, respectively."), - NTRANS("Range file appears to be empty, check file is a proper range file and is not empty."), - NTRANS("Error reading the long name for ion."), - 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("Unexpected failure whilst trying to skip over range lead-in data (bit before range start value)"), - NTRANS("Unable to read range start and end values"), - NTRANS("Unable to read range table entry"), - NTRANS("Error reading file, unexpected format, are you sure it is a proper range file?"), - NTRANS("Too many ranges appeared to have range entries with no usable data (eg, all blank)"), - 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."), -}; -//!Create an pos file from a vector of IonHits -unsigned int IonVectorToPos(const vector &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 &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)); - } -} - -bool decomposeIonNames(const std::string &name, - std::vector > &fragments) -{ - size_t lastMarker=0; - size_t digitMarker=0; - - if(!name.size()) - return true; - - //Atomic naming systems use uppercase ascii - // letters, like "A" in Au, or Ag as delimiters. - // - // numerals are multipliers, and are forbidden - // for the first char... - if(!isascii(name[0]) || - isdigit(name[0]) || islower(name[0])) - return false; - - //true - was last, or now am on ion name - //false - am still on multiplier - int nameMode=true; - for(size_t ui=1;ui &composedNames, - - const vector > &namesToFind, size_t &matchOffset) -{ - //Decomposition of composed names. - std::vector > > fragmentVec; - - //break each composed name into a vector of decomposed fragments - // and the multiplicity - //of that fragment (eg, AuHg2 would become { Au ,1} {Hg,2}) - fragmentVec.reserve(composedNames.size()); - for(std::map::const_iterator it=composedNames.begin(); - it!=composedNames.end();++it) - { - vector > frags; - if(!decomposeIonNames(it->first,frags)) - frags.clear(); - - - fragmentVec.push_back(frags); - - frags.clear(); - } - - - //Try to match all fragments in "namesToFind" (name-frequency pairings) - //in the master list of fragments of - // which consists of the decomposed composed names (fragmentVec entries) - - //If the decomposed fragments wholly constitute the - //master list, then thats good, and we have a match. - //Note that the master list will not necessarily be in - //the same order as the fragment list - //match tally for fragments - - - vector excludedMatch; - excludedMatch.resize(fragmentVec.size(),false); - - for(size_t uj=0;uj curFrag; - curFrag=namesToFind[uj]; - for(size_t ui=0;ui &posIons,const char *posFile, size_t limitCount, - unsigned int &progress, bool (*callback)(bool),bool strongSampling) -{ - - //Function is only defined for 4 columns here. - ASSERT(outputnumcols == 4); - //buffersize must be a power of two and at least outputnumcols*sizeof(float) - const unsigned int NUMROWS=1; - const unsigned int BUFFERSIZE=inputnumcols * sizeof(float) * NUMROWS; - const unsigned int BUFFERSIZE2=outputnumcols * sizeof(float) * NUMROWS; - char *buffer=new char[BUFFERSIZE]; - - - if(!buffer) - return POS_ALLOC_FAIL; - - char *buffer2=new char[BUFFERSIZE2]; - if(!buffer2) - { - delete[] buffer; - return POS_ALLOC_FAIL; - } - - //open pos file - std::ifstream CFile(posFile,std::ios::binary); - - if(!CFile) - { - delete[] buffer; - delete[] buffer2; - return POS_OPEN_FAIL; - } - - CFile.seekg(0,std::ios::end); - size_t fileSize=CFile.tellg(); - - if(!fileSize) - { - delete[] buffer; - delete[] buffer2; - return POS_EMPTY_FAIL; - } - - CFile.seekg(0,std::ios::beg); - - //calculate the number of points stored in the POS file - size_t pointCount=0; - size_t maxIons; - size_t maxCols = inputnumcols * sizeof(float); - //regular case - - if(fileSize % maxCols) - { - delete[] buffer; - delete[] buffer2; - return POS_SIZE_MODULUS_ERR; - } - - maxIons =fileSize/maxCols; - limitCount=std::min(limitCount,maxIons); - - //If we are going to load the whole file, don't use a sampling method to do it. - if(limitCount == maxIons) - { - //Close the file - CFile.close(); - delete[] buffer; - delete[] buffer2; - //Try opening it using the normal functions - return GenericLoadFloatFile(inputnumcols, outputnumcols, index, posIons,posFile,progress, callback); - } - - //Use a sampling method to load the pos file - std::vector ionsToLoad; - try - { - posIons.resize(limitCount); - - RandNumGen rng; - rng.initTimer(); - unsigned int dummy; - randomDigitSelection(ionsToLoad,maxIons,rng, - limitCount,dummy,callback,strongSampling); - } - catch(std::bad_alloc) - { - delete[] buffer; - delete[] buffer2; - return POS_ALLOC_FAIL; - } - - - //sort again - GreaterWithCallback g(callback,PROGRESS_REDUCE); - std::sort(ionsToLoad.begin(),ionsToLoad.end(),g); - - unsigned int curProg = PROGRESS_REDUCE; - - //TODO: probably not very nice to the disk drive. would be better to - //scan ahead for contigous data regions, and load that where possible. - //Or switch between different algorithms based upon ionsToLoad.size()/ - std::ios::pos_type nextIonPos; - for(size_t ui=0;ui &posIons,const char *posFile, - unsigned int &progress, bool (*callback)(bool)) -{ - ASSERT(outputnumcols==4); //Due to ionHit.setHit - //buffersize must be a power of two and at least sizeof(float)*outputnumCols - const unsigned int NUMROWS=512; - const unsigned int BUFFERSIZE=inputnumcols * sizeof(float) * NUMROWS; - const unsigned int BUFFERSIZE2=outputnumcols * sizeof(float) * NUMROWS; - - char *buffer=new char[BUFFERSIZE]; - - if(!buffer) - return POS_ALLOC_FAIL; - - char *buffer2=new char[BUFFERSIZE2]; - if(!buffer2) - { - delete[] buffer; - return POS_ALLOC_FAIL; - } - //open pos file - std::ifstream CFile(posFile,std::ios::binary); - - if(!CFile) - { - delete[] buffer; - delete[] buffer2; - return POS_OPEN_FAIL; - } - - CFile.seekg(0,std::ios::end); - size_t fileSize=CFile.tellg(); - - if(!fileSize) - { - delete[] buffer; - delete[] buffer2; - return POS_EMPTY_FAIL; - } - - CFile.seekg(0,std::ios::beg); - - //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; - size_t curBufferSize2=BUFFERSIZE2; - - if(fileSize % (inputnumcols * sizeof(float))) - { - delete[] buffer; - delete[] buffer2; - return POS_SIZE_MODULUS_ERR; - } - - try - { - posIons.resize(fileSize/(inputnumcols*sizeof(float))); - } - catch(std::bad_alloc) - { - delete[] buffer; - delete[] buffer2; - return POS_ALLOC_FAIL; - } - - - while(fileSize < curBufferSize) { - curBufferSize = curBufferSize >> 1; - curBufferSize2 = curBufferSize2 >> 1; - } - - //Technically this is dependent upon the buffer size. - unsigned int curProg = 10000; - size_t ionP=0; - int maxCols = inputnumcols * sizeof(float); - int maxPosCols = outputnumcols * sizeof(float); - do - { - //Taking curBufferSize chunks at a time, read the input file - while((size_t)CFile.tellg() <= fileSize-curBufferSize) - { - CFile.read(buffer,curBufferSize); - if(!CFile.good()) - { - delete[] buffer; - delete[] buffer2; - return POS_READ_FAIL; - } - - for (unsigned int j = 0; j < NUMROWS; j++) // iterate through rows - { - for (unsigned int i = 0; i < outputnumcols; i++) // iterate through floats - { - memcpy(&(buffer2[j * maxPosCols + i * sizeof(float)]), - &(buffer[j * maxCols + index[i] * sizeof(float)]), sizeof(float)); - } - } - - unsigned int ui; - for(ui=0; ui> 1 ; - curBufferSize2 = curBufferSize2 >> 1 ; - }while(curBufferSize2 >= sizeof(IONHIT)); - - ASSERT((unsigned int)CFile.tellg() == fileSize); - delete[] buffer; - delete[] buffer2; - - return 0; -} - - -//TODO: Add progress -unsigned int limitLoadTextFile(unsigned int numColsTotal, unsigned int selectedCols[], - vector &posIons,const char *textFile, const char *delim, const size_t limitCount, - unsigned int &progress, bool (*callback)(bool),bool strongRandom) -{ - - ASSERT(numColsTotal); - ASSERT(textFile); - - vector newLinePositions; - std::vector subStrs; - - //Do a brute force scan through the dataset - //to locate newlines. - char *buffer; - const int BUFFER_SIZE=16384; //This is totally a guess. I don't know what is best. - - - //sort the selected columns into increasing order - vector sortedCols; - for(unsigned int ui=0;ui=subStrs.size()) - { - enoughSubStrs=false; - break; - } - } - - if(!enoughSubStrs) - continue; - - //Unable to stream - bool unStreamable; - unStreamable=false; - for(unsigned int ui=0; ui=maxPos) - return TEXT_ERR_ONLY_HEADER; - - - CFile.close(); - - //Re-open the file in binary mode to find the newlines - CFile.open(textFile,std::ios::binary); - - if(!CFile) - return TEXT_ERR_REOPEN; - - - //Jump to beyond the header - CFile.seekg(curPos); - - - //keep a beginning of file marker - newLinePositions.push_back(curPos); - bool seenNumeric=false; - buffer = new char[BUFFER_SIZE]; - while(!CFile.eof() && curPos < maxPos) - { - if(!CFile.good()) - { - delete[] buffer; - return TEXT_ERR_READ_CONTENTS; - } - //read up to BUFFER_SIZE bytes from the file - //but only if they are available - bytesToRead = std::min(maxPos-curPos,(size_t)BUFFER_SIZE); - - CFile.read(buffer,bytesToRead); - - //check that this buffer contains numeric info - for(unsigned int ui=0;ui= '0' && buffer[ui] <='9') - seenNumeric=true; - } - - curPos+=bytesToRead; - - } - - //Don't keep any newline that hits the end of the file, but do keep a zero position - if(newLinePositions.size()) - newLinePositions.pop_back(); - CFile.close(); - - - //OK, so now we know where those pesky endlines are. This gives us jump positions - //to new lines in the file. Each component must have some form of numeric data - //preceding it. That numeric data may not be fully parseable, but we assume it is until we know better. - // - //If it is *not* parseable. just throw an error when we find that out. - - //If we are going to load the whole file, don't use a sampling method to do it. - if(limitCount >=newLinePositions.size()) - { - delete[] buffer; - - vector > data; - vector header; - - //Just use the non-sampling method to load. - if(loadTextData(textFile,data,header,delim)) - return TEXT_ERR_FORMAT; - - if(data.size() !=4) - return TEXT_ERR_NUM_FIELDS; - - posIons.resize(data[0].size()); - for(size_t ui=0;ui dataToLoad; - try - { - posIons.resize(limitCount); - - RandNumGen rng; - rng.initTimer(); - unsigned int dummy; - randomDigitSelection(dataToLoad,newLinePositions.size(),rng, - limitCount,dummy,callback,strongRandom); - } - catch(std::bad_alloc) - { - delete[] buffer; - return TEXT_ERR_ALLOC_FAIL; - } - - - //Sort the data such that we are going to - //always jump forwards in the file; better disk asccess and whatnot. - GreaterWithCallback g(callback,PROGRESS_REDUCE); - std::sort(dataToLoad.begin(),dataToLoad.end(),g); - - //OK, so we have a list of newlines - //that we can use as entry points for random seek. - //We also have some random entry points (sorted). - // Now re-open the file in text mode and try to load the - // data sepecified at the offsets - - - //Open file in text mode - CFile.open(textFile); - - if(!CFile) - { - delete[] buffer; - return TEXT_ERR_REOPEN; - } - - - //OK, now jump to each of the random positions, - //as dictated by the endline position - //and attempt a parsing there. - - subStrs.clear(); - for(size_t ui=0;ui 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)) - { - 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 namePair; - - //Read ion short and full names as well as colour info - for(unsigned int i=0; i - 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; - } - - - vector colHeaders; - splitStrsRef(inBuffer,' ',colHeaders); - - //remove whitespace from each entry - for(size_t ui=0;ui 1) - { - - if(colHeaders.size() -1 !=numIons) - { - // Emit warning - delete[] inBuffer; - return RANGE_ERR_FORMAT_TABLESEPARATOR; - } - - //Strip any trailing newlines off the last of the colheaders, - // to avoid dos->unix conversion problems - std::string str = colHeaders[colHeaders.size() -1]; - - if(str[str.size() -1 ] == '\n') - colHeaders[colHeaders.size()-1]=str.substr(0,str.size()-1); - - //Each column header should match the original ion name - for(size_t ui=1;ui frequencyEntries; - frequencyEntries.clear(); - frequencyEntries.resize(numRanges*numIons,0); - //Load in each range file line - tempInt=0; - pair massPair; - for(unsigned int i=0; i '9')) - { - fgetc(fpRange); - if(feof(fpRange)) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT_RANGE_DUMMYCHARS; - } - - peekVal=fpeek(fpRange); - - } - if(!fscanf(fpRange, "%128f %128f",&massPair.first, - &massPair.second)) - { - 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 - - for(unsigned int j=0; j composeMap; - - for(size_t uj=0;uj freqEntries; - size_t freq; - - freqEntries.clear(); - freq=0; - for(size_t uj=0;ujfirst); - } - 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 > entries; - - for(map::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 strVec; - - //Read file until we get beyond the range length - while(!beyondRanges && !feof(fpRange) ) - { - if(!fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange) - || strlen(inBuffer) >=MAX_LINE_SIZE-1) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - //Trick to "strip" the buffer - nullifyMarker(inBuffer,'#'); - - string s; - s=inBuffer; - - s=stripWhite(s); - - if(!s.size()) - continue; - - //Try different delimiters to split string - splitStrsRef(s.c_str(),"\t ",strVec); - - stripZeroEntries(strVec); - - if(strVec.empty()) - continue; - - if(!haveNumRanges) - { - //num ranges should have two entries, num ions and ranges - if(strVec.size() != 2) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - if(stream_cast(numIons,strVec[0])) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - if(stream_cast(numRanges,strVec[1])) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - haveNumRanges=true; - } - else - { - //Do we still have to process the name block? - if(!haveNameBlock) - { - //Just exiting name block, - if(strVec.size() == 5) - haveNameBlock=true; - else if(strVec.size() == 4) - { - //Entry in name block - if(!strVec[0].size()) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - //Check that name consists only of - //readable ascii chars, or period - for(unsigned int ui=0; ui1.0 || colourStruct.red < 0.0f || - colourStruct.green >1.0 || colourStruct.green < 0.0f || - colourStruct.blue >1.0 || colourStruct.blue < 0.0f ) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - - } - - - colours.push_back(colourStruct); - } - else - { - //Well thats not right, - //we should be looking at the first entry in the - //range block.... - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - } - - if(haveNameBlock) - { - //We are finished - if(strVec.size() == 5) - { - unsigned int thisIonID; - thisIonID=(unsigned int)-1; - for(unsigned int ui=0;ui basicIonNames; - - while (!feof(fpRange)) - { - if(!fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange) - || strlen(inBuffer) >=MAX_LINE_SIZE-1) - break; - //Trick to "strip" the buffer, assuming # is a comment - nullifyMarker(inBuffer,'#'); - - string s; - s=inBuffer; - - s=stripWhite(s); - if (!s.size()) - continue; - - if (s == "[Ions]") - { - curBlock=BLOCK_IONS; - continue; - } - else if (s == "[Ranges]") - { - curBlock=BLOCK_RANGES; - continue; - } - - switch (curBlock) - { - case BLOCK_NONE: - break; - case BLOCK_IONS: - { - - //The ion section in RRNG seems almost completely redundant. - //This does not actually contain information about the ions - //in the file (this is in the ranges section). - //Rather it tells you what the constituents are from which - //complex ions may be formed. Apply Palm to Face. - - vector split; - splitStrsRef(s.c_str(),'=',split); - - if (split.size() != 2) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - std::string stmp; - stmp=lowercase(split[0]); - - haveSeenIonBlock=true; - - - if (stmp == "number") - { - //Should not have set the - //number of ions yet. - if (numBasicIons !=0) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - //Set the number of ions - if(stream_cast(numBasicIons, split[1])) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - if (numBasicIons == 0) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - } - else if (split[0].size() >3) - { - stmp = lowercase(split[0].substr(0,3)); - if (stmp == "ion") - { - //OK, its an ion. - basicIonNames.push_back(split[1]); - - if (basicIonNames.size() > numBasicIons) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - } - else - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - } - break; - } - case BLOCK_RANGES: - { - //Although it looks like the blocks are independent. - //it is more complicated to juggle a parser with them - //out of dependency order, as a second pass would - //need to be done. - if (!haveSeenIonBlock) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - vector split; - - if (s.size() > 6) - { - splitStrsRef(s.c_str(),'=',split); - - if (split.size() != 2) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - if (lowercase(split[0].substr(0,5)) == "numbe") - { - - //Should not have set the num ranges yet - if (numRanges) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - if (stream_cast(numRanges,split[1])) - { - - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - if (!numRanges) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - } - else if ( lowercase(split[0].substr(0,5)) == "range") - { - //Try to decode a range line, as best we can. - //These appear to come in a variety of flavours, - //which makes this section quite long. - - //OK, so the format here is a bit wierd - //we first have to strip the = bit - //then we have to step across fields, - //I assume the fields are in order (or missing) - //* denotes 0 or more, + denotes 1 or more, brackets denote grouping - // Vol: [0-9]* ([A-z]+: [0-9]+)* (Name:[0-9]*([A-z]+[0-9]*)+ Color:[0-F][0-F][0-F][0-F][0-F][0-F] - // Examples: - // Range1=31.8372 32.2963 Vol:0.01521 Zn:1 Color:999999 - // or - // Range1=31.8372 32.2963 Zn:1 Color:999999 - // or - // Range1=95.3100 95.5800 Vol:0.04542 Zn:1 Sb:1 Color:00FFFF - // or - // Range1=95.3100 95.5800 Vol:0.04542 Name:1Zn1Sb1 Color:00FFFF - // or - // Range1=95.3100 95.5800 Vol:0.04542 Zn:1 Sb:1 Name:1Zn1Sb1 Color:00FFFF - // or - // Range1= 95.3100 95.5800 Color:00FFFF Vol:0.04542 Zn:1 Sb:1 Name:1Zn1Sb1 - - //Starting positions (string index) - //of range start and end - //Range1=31.8372 32.2963 Vol:0.01521 Zn:1 Color:999999 - // ^rngmid ^rngend - size_t rngMidIdx,rngEndIdx; - string rngStart,rngEnd; - split[1]=stripWhite(split[1]); - rngMidIdx = split[1].find_first_of(' '); - - if (rngMidIdx == std::string::npos) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - rngEndIdx=split[1].find_first_of(' ',rngMidIdx+1); - if (rngEndIdx == std::string::npos) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - rngStart = split[1].substr(0,rngMidIdx); - rngEnd = split[1].substr(rngMidIdx+1,rngEndIdx-(rngMidIdx+1)); - - - //Strip the range - string strTmp; - strTmp = split[1].substr(rngEndIdx+1);//,split[1].size()-(rngEndIdx+1)); - - //Split the remaining field into key:value pairs - split.clear(); - splitStrsRef(strTmp.c_str(),' ',split); - - stripZeroEntries(split); - RGBf col; - bool haveColour,haveNameField; - haveColour=false; - haveNameField=false; - string strIonNameTmp,strNameFieldValue; - - for (unsigned int ui=0; ui 0 - unsigned int uintVal; - if (stream_cast(uintVal,value) || !uintVal) - { - delete[] inBuffer; - return RANGE_ERR_FORMAT; - } - - //If it is 1, then use straight name. Otherwise try to give it a - //chemical formula look by mixing in the multiplicity after the key - if (uintVal==1) - strIonNameTmp+=key; - else - strIonNameTmp+=key+value; - } - } - - if (!haveColour ) - { - //Okay, so a colour wasn't provided. - // to make our users lives a bit less - // boring, lets just use some semi-random ones - col.red=rand()/(float)std::numeric_limits::max(); - col.green=rand()/(float)std::numeric_limits::max(); - col.blue=rand()/(float)std::numeric_limits::max(); - - } - - //Get the range values - float rngStartV,rngEndV; - if(strIonNameTmp.size() || haveNameField) - { - if (stream_cast(rngStartV,rngStart)) - { - delete[] inBuffer; - - return RANGE_ERR_FORMAT; - } - - if (stream_cast(rngEndV,rngEnd)) - { - delete[] inBuffer; - - return RANGE_ERR_FORMAT; - } - } - - //So the ion field appears to be optional (that is, - //ivas emits RRNGs that do not contain an ion listed in the - //ion field). It is unclear what the purpose of these lines is, - //so we shall ignore it, in preference to aborting - if(strIonNameTmp.size()) - { - //Check to see if we have this ion. - //If we dont, we create a new one. - //if we do, we check that the colours match - //and if not reject the file parsing. - unsigned int pos=(unsigned int)(-1); - for (unsigned int ui=0; ui '9') - { - chargeStrStop =ui; - break; - } - - } - - //Strip off the charge value, to get the ion name - strNameFieldValue =strNameFieldValue.substr(chargeStrStop,strNameFieldValue.size()-chargeStrStop); - - //Check to see if we have this ion. - //If we dont, we create a new one. - //if we do, we check that the colours match - //and if not reject the file parsing. - unsigned int pos=(unsigned int)(-1); - for (unsigned int ui=0; ui &exts) -{ - //subtract one for the guard terminator, which - // we do not want to return - exts.resize(ARRAYSIZE(RANGE_EXTS)-1); - - for(unsigned int ui=0;ui ranges[uj].first && - ranges[ui].first < ranges[uj].second ) - return false; - if(ranges[ui].second > ranges[uj].first && - ranges[ui].second < ranges[uj].second ) - return false; - - //check for not spanning a range - if(ranges[ui].first < ranges[uj].first && - ranges[ui].second > ranges[uj].second) - return false; - - //Check for range duplication - if(ranges[ui].first == ranges[uj].first && - ranges[ui].second == ranges[uj].second) - return false; - - } - } - - return true; -} - -bool RangeFile::isRanged(float mass) const -{ - unsigned int numRanges = ranges.size(); - - for(unsigned int ui=0; ui= ranges[ui].first && - mass <= ranges[ui].second ) - return true; - } - - return false; -} - -bool RangeFile::isRanged(const IonHit &ion) const -{ - return isRanged(ion.getMassToCharge()); -} - -bool RangeFile::range(vector &ions, string ionShortName) -{ - vector rangedVec; - - //find the Ion ID of what we want - unsigned int targetIonID=(unsigned int)-1; - for(unsigned int ui=0; ui subRanges; - for(unsigned int ui=0; ui= ranges[subRanges[uj]].first && - ions[ui].getMassToCharge() <= ranges[subRanges[uj]].second ) - { - rangedVec.push_back(ions[ui]); - break; - } - } - } - - //Do the switcheroonie - //such that the un-ranged ions are destroyed - //and the ranged ions are kept - ions.swap(rangedVec); - return true; -} - -void RangeFile::range(vector &ions) -{ - vector rangedVec; - - unsigned int numIons=ions.size(); - rangedVec.reserve(numIons); - - for(unsigned int ui=0; ui &ions, unsigned int rangeID) -{ - vector rangedVec; - - unsigned int numIons=ions.size(); - rangedVec.reserve(numIons); - - for(unsigned int ui=0; ui= ranges[rangeID].first && - ions[ui].getMassToCharge() <= ranges[rangeID].second ) - { - rangedVec.push_back(ions[ui]); - break; - } - } - - //Do the switcheroonie - //such that the un-ranged ions are destroyed - //and the ranged ions are kept - ions.swap(rangedVec); -} - - -void RangeFile::printErr(std::ostream &strm) const -{ - ASSERT(errState < RANGE_ERR_ENUM_END); - strm < RangeFile::getRange(unsigned int ui) const -{ - return ranges[ui]; -} - -RGBf RangeFile::getColour(unsigned int ui) const -{ - ASSERT(ui < colours.size()); - return colours[ui]; -} - -unsigned int RangeFile::getIonID(float mass) const -{ - unsigned int numRanges = ranges.size(); - - for(unsigned int ui=0; ui= ranges[ui].first && - mass <= ranges[ui].second ) - return ionIDs[ui]; - } - - return (unsigned int)-1; -} - -unsigned int RangeFile::getRangeID(float mass) const -{ - unsigned int numRanges = ranges.size(); - - for(unsigned int ui=0; ui= ranges[ui].first && - mass <= ranges[ui].second ) - return ui; - } - - return (unsigned int)-1; -} - -unsigned int RangeFile::getIonID(unsigned int range) const -{ - ASSERT(range < ranges.size()); - - return ionIDs[range]; -} - -unsigned int RangeFile::getIonID(const char *name) const -{ - for(unsigned int ui=0; ui &ionHits, unsigned int rng) -{ - //This is a bit slack, could be faster, but should work. - return range(ionHits,ionNames[rng].first); -} - -bool RangeFile::isRanged(string shortName, bool caseSensitive) -{ - if(caseSensitive) - { - for(unsigned int ui=ionNames.size(); ui--; ) - { - if(ionNames[ui].first == shortName) - return true; - } - } - else - { - for(unsigned int ui=ionNames.size(); ui--; ) - { - //perform a series of case independent - //string comparisons - string str; - str = ionNames[ui].first; - - if(str.size() !=shortName.size()) - continue; - - bool next; - next=false; - for(unsigned int ui=str.size(); ui--; ) - { - if(tolower(str[ui]) != - tolower(shortName[ui])) - { - next=true; - break; - } - } - - if(!next) - return true; - } - } - - 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 ionIDs.size()) - return 0; - - string str= getName(ionID); - - for(unsigned int ui=0; ui= ranges[rangeId].second) - return false; - } - - //Check that moving this range will not cause any overlaps with - //other ranges - for(unsigned int ui=0; ui ranges[ui].first)) - return false; - - if((ranges[rangeId].first < ranges[ui].second && - newMass > ranges[ui].second)) - return false; - } - else - { - //moving low range - //check for overlap on first - if((ranges[rangeId].second > ranges[ui].first && - newMass < ranges[ui].first)) - return false; - - if((ranges[rangeId].second > ranges[ui].second && - newMass < ranges[ui].second)) - return false; - } - - } - - if(limit) - ranges[rangeId].second = newMass; - else - ranges[rangeId].first= newMass; - - return true; -} - -bool RangeFile::moveBothRanges(unsigned int rangeId, float newLow, float newHigh) -{ - - //Check that moving this range will not cause any overlaps with - //other ranges - for(unsigned int ui=0; ui ranges[ui].first)) - return false; - - if((ranges[rangeId].first < ranges[ui].second && - newHigh > ranges[ui].second)) - return false; - //moving low range - //check for overlap on first - if((ranges[rangeId].second > ranges[ui].first && - newLow < ranges[ui].first)) - return false; - - if((ranges[rangeId].second > ranges[ui].second && - newLow < ranges[ui].second)) - return false; - } - - ranges[rangeId].second = newHigh; - ranges[rangeId].first= newLow; - - return true; -} - - - -unsigned int RangeFile::addRange(float start, float end, unsigned int parentIonID) -{ - ASSERT(start < end); - //Ensure that they do NOT overlap - for(unsigned int ui=0;ui ranges[ui].first && - start<=ranges[ui].second) - return -1; - - if(end > ranges[ui].first && - end<=ranges[ui].second) - return -1; - - //check for start/end spanning range entirely - if(start < ranges[ui].first && end > ranges[ui].second) - return -1; - } - - //Got this far? Good - valid range. Insert it and move on - ionIDs.push_back(parentIonID); - ranges.push_back(std::make_pair(start,end)); - - ASSERT(isSelfConsistent()); - return ranges.size(); -} - -unsigned int RangeFile::addIon(std::string &shortN, std::string &longN, RGBf &newCol) -{ - for(unsigned int ui=9; ui &points,Point3D ¢roid) -{ - //TODO: Paralellise me - centroid=Point3D(0,0,0); - for(unsigned int ui=0;ui &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::max(); - bounds[ui][1]=-std::numeric_limits::max(); - } - - for(unsigned int ui=0; ui 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 cubes; - - unsigned int nT=omp_get_max_threads(); - cubes.resize(nT); - for(unsigned int ui=0;ui. - */ - -#ifndef APTCLASSES_H -#define APTCLASSES_H - -#include "endianTest.h" -#include "mathfuncs.h" -#include "commonConstants.h" -#include "basics.h" - -#include -#include -#include -#include -#include -#include -#include -#include //memcpy -#include -#include //std::bad_alloc - -//!Allowable export ion formats -enum -{ - IONFORMAT_POS=1 -}; - -using std::vector; - -class IonHit; -class Point3D; -class RangeFile; - - -const unsigned int PROGRESS_REDUCE=5000; - -extern const char *POS_ERR_STRINGS[]; - -extern const char *ION_TEXT_ERR_STRINGS[]; - -//!Errors that can be encountered when openning pos files -enum posErrors -{ - POS_ALLOC_FAIL=1, - POS_OPEN_FAIL, - POS_EMPTY_FAIL, - POS_SIZE_MODULUS_ERR, - POS_READ_FAIL, - POS_NAN_LOAD_ERROR, - POS_ABORT_FAIL, - POS_ERR_FINAL // Not actually an error, but tells us where the end of the num is. -}; - - -//!make a pos file from a set of a set of IonHits -unsigned int IonVectorToPos(const vector &points, const std::string &name); - -//!make/append to a pos file from a set of a set of IonHits -void appendPos(const vector &points, const char *name); - -//!Set the bounds from an array of ion hits -BoundCube getIonDataLimits(const vector &p);// - -//!Get the sum of all Point3Ds in an ion vector -void getPointSum(const std::vector &points,Point3D ¢roid); - -//Range file strucutres -//========= - -enum{ - RANGE_ERR_OPEN =1, - RANGE_ERR_FORMAT_HEADER, - RANGE_ERR_EMPTY, - RANGE_ERR_FORMAT_LONGNAME, - RANGE_ERR_FORMAT_SHORTNAME, - RANGE_ERR_FORMAT_COLOUR, - RANGE_ERR_FORMAT_TABLESEPARATOR, - RANGE_ERR_FORMAT_RANGE_DUMMYCHARS, - RANGE_ERR_FORMAT_MASS_PAIR, - RANGE_ERR_FORMAT_TABLE_ENTRY, - RANGE_ERR_FORMAT, - RANGE_ERR_DATA_TOO_MANY_USELESS_RANGES, - RANGE_ERR_DATA_FLIPPED, - RANGE_ERR_DATA_INCONSISTENT, - RANGE_ERR_DATA_NOMAPPED_IONNAME, - RANGE_ERR_ENUM_END -}; - - - -enum{ RANGE_FORMAT_ORNL=1, - RANGE_FORMAT_ENV, - RANGE_FORMAT_RRNG, - RANGE_FORMAT_END_OF_ENUM //not a format, just end of enumueration. -}; -//========= - - - - -//Pos file structure -//=========== -//========= - - - -//!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); -}; - - -//!Data storage and retrieval class for various range files -class RangeFile -{ - private: - //These vectors will contain the number of ions - - //The first element is the shortname for the Ion - //the second is the full name - std::vector > ionNames; - //This holds the colours for the ions - std::vector colours; - - //This will contains the number of ranges - // - //This holds the min and max masses for the range - std::vector > ranges; - //The ion ID number for each range - //FIXME: Convert to proper uniqueID system - std::vector ionIDs; - - unsigned int errState; - //Warning messages, used when loading rangefiles - std::vector warnMessages; - - - //!Erase the contents of the rangefile - void clear(); - - //!Performs limited checks for self consistency. - bool isSelfConsistent() const; - - //!Load an ORNL formatted "RNG" rangefile - // caller must supply and release file pointer - unsigned int openRNG(FILE *fp); - //!Load an RRNG file - // caller must supply and release file pointer - unsigned int openRRNG(FILE *fp); - //!Load an ENV file - // caller must supply and release file pointer - unsigned int openENV(FILE *fp); - - public: - RangeFile(); - //!Open a specified range file - unsigned int open(const char *rangeFile, unsigned int format=RANGE_FORMAT_ORNL); - //!Open a specified range file - 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. - static bool extensionIsRange(const char *ext); - //!Grab a vector that contains all the extensions that are valid for range files - static void getAllExts(std::vector &exts); - - //!Print the translated error associated with the current range file state - void printErr(std::ostream &strm) const; - //!Retreive the translated error associated with the current range file state - std::string getErrString() const; - //!Get the number of unique ranges - unsigned int getNumRanges() const; - //!Get the number of ranges for a given ion ID - unsigned int getNumRanges(unsigned int ionID) const; - //!Get the number of unique ions - unsigned int getNumIons() const; - //!Retrieve the start and end of a given range as a pair(start,end) - std::pair getRange(unsigned int ) const; - //!Retrieve a given colour from the ion ID - RGBf getColour(unsigned int) const; - //!Set the colour using the ion ID - void setColour(unsigned int, const RGBf &r); - - - //!Retrieve the colour from a given ion ID - - //!Get the ion's ID from a specified mass - /*! Returns the ions ID if there exists a range that - * contains this mass. Otherwise (unsigned int)-1 is returned - */ - unsigned int getIonID(float mass) const; - //!Get the ion ID from a given range ID - /*!No validation checks are performed outside debug mode. Ion - range *must* exist*/ - unsigned int getIonID(unsigned int range) const; - //!Get the ion ID from its short name - unsigned int getIonID(const char *name) const; - - //!Set the ion ID for a given range - void setIonID(unsigned int range, unsigned int newIonId); - - //!returns true if a specified mass is ranged - bool isRanged(float mass) const; - //! Returns true if an ion is ranged - bool isRanged(const IonHit &) const; - //!Clips out ions that are not inside the range - void range(std::vector &ionHits); - //!Clips out ions that dont match the specified ion name - /*! Returns false if the ion name given doesn't match - * any in the rangefile (case sensitive) - */ - bool range(std::vector &ionHits, - std::string shortIonName); - - //!Clips out ions that dont lie in the specified range number - /*! Returns false if the range does not exist - * any in the rangefile (case sensitive) - */ - bool rangeByID(std::vector &ionHits, - unsigned int range); - void rangeByRangeID(std::vector &ionHits, - unsigned int rangeID); - //!Get the short name or long name of a speicifed ionID - /*! Pass shortname=false to retireve the long name - * ionID passed in must exist. No checking outside debug mode - */ - std::string getName(unsigned int ionID,bool shortName=true) const; - - std::string getName(const IonHit &ion, bool shortName) const; - - //!set the short name for a given ion - void setIonShortName(unsigned int ionID, const std::string &newName); - - //!Set the long name for a given ion - void setIonLongName(unsigned int ionID, const std::string &newName); - - //!Check to see if an atom is ranged - /*! Returns true if rangefile holds at least one range with shortname - * corresponding input value. Case sensitivite search is default - */ - bool isRanged(std::string shortName, bool caseSensitive=true); - - //!Write the rangefile to the specified output stream (default ORNL format) - unsigned int write(std::ostream &o,size_t format=RANGE_FORMAT_ORNL) const; - //!WRite the rangefile to a file (ORNL format) - unsigned int write(const char *datafile, size_t format=RANGE_FORMAT_ORNL) const; - - //!Return the atomic number of the element from either the long or short version of the atomic name - /* - * Short name takes precedence - * - * Example : if range is "H" or "Hydrogen" function returns 1 - * Returns 0 on error (bad atomic name) - */ - unsigned int atomicNumberFromRange(unsigned int range) const; - - - //!Get atomic number from ion ID - unsigned int atomicNumberFromIonID(unsigned int ionID) const; - - //!Get a range ID from mass to charge - unsigned int getRangeID(float mass) const; - - //!Swap a range file with this one - void swap(RangeFile &rng); - - //!Move a range's mass to a new location - bool moveRange(unsigned int range, bool limit, float newMass); - //!Move both of a range's masses to a new location - bool moveBothRanges(unsigned int range, float newLow, float newHigh); - - //!Add a range to the rangefile. Returns ID number of added range - // if adding successfull, (unsigned int)-1 otherwise - unsigned int addRange(float start, float end, unsigned int ionID); - - //Add the ion to the database returns ion ID if successful, -1 otherwise - unsigned int addIon(std::string &shortName, std::string &longName, RGBf &ionCol); - -}; - -//Number of elements stored in the table -const unsigned int NUM_ELEMENTS=119; - -//!Load a pos file directly into a single ion list -/*! Pos files are fixed record size files, with data stored as 4byte - * big endian floating point. (IEEE 574?). Data is stored as - * x,y,z,mass/charge. - * */ -//!Load a pos file into a T of IonHits -unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int outputnumcols, - unsigned int index[], vector &posIons,const char *posFile, - unsigned int &progress, bool (*callback)(bool)); - - -unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, unsigned int index[], - vector &posIons,const char *posFile, size_t limitCount, - unsigned int &progress, bool (*callback)(bool),bool strongRandom); - - - -unsigned int limitLoadTextFile(unsigned int numColsTotal, unsigned int selectedCols[], - vector &posIons,const char *posFile, const char *deliminator, const size_t limitCount, - unsigned int &progress, bool (*callback)(bool),bool strongRandom); - - -#endif diff -Nru 3depict-0.0.12/src/K3DTree-mk2.cpp 3depict-0.0.13/src/K3DTree-mk2.cpp --- 3depict-0.0.12/src/K3DTree-mk2.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/K3DTree-mk2.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,709 +0,0 @@ -/* - * K3DTree-mk2.cpp : 3D Point KD tree - precise implementation - * 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 - * 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 . - */ - -#include "K3DTree-mk2.h" -#include "mathfuncs.h" - - -#include -#include -#include -#include -#include - -using std::stack; -using std::vector; -using std::pair; - -void K3DTreeMk2::resetPts(std::vector &p, bool clear) -{ - //Compute bounding box for indexedPoints - treeBounds.setBounds(p); - indexedPoints.resize(p.size()); - -#pragma omp parallel for - for(size_t ui=0;ui &p, bool clear) -{ - indexedPoints.resize(p.size()); - nodes.resize(p.size()); - - if(p.empty()) - return; - - - //Compute bounding box for indexedPoints - treeBounds=getIonDataLimits(p); - -#pragma omp parallel for - for(size_t ui=0;ui > limits; - stack buildStatus; - stack splitStack; - - //Data runs from 0 to size-1 INCLUSIVE - limits.push(make_pair(0,indexedPoints.size()-1)); - buildStatus.push(BUILT_NONE); - splitStack.push((size_t)-1); - - - AxisCompareMk2 axisCmp; - - size_t numSeen=0; // for progress reporting - size_t splitIndex=0; - - - - size_t *childPtr; - -#ifdef DEBUG - for(size_t ui=0;uilimits.top().first) - { - //There is; we have to branch again - limits.push(make_pair( - limits.top().first,splitIndex-1)); - - buildStatus.push(BUILT_NONE); - //Set the child pointer, as we don't know - //the correct value until the next sort. - childPtr=&nodes[splitIndex].childLeft; - } - else - { - //There is not. Set the left branch to null - nodes[splitIndex].childLeft=(size_t)-1; - } - splitStack.push(splitIndex); - - break; - } - - case BUILT_LEFT: - { - //Either of these cases results in use - //handling the right branch. - buildStatus.top()++; - splitIndex=splitStack.top(); - //Check to see if there is any right data - if(splitIndex status; - stack nodeStack; - status.push(PRINT_NONE); - nodeStack.push(indexedPoints.size()/2); - - do - { - for(size_t ui=0;ui" <" <" <" <Left() - NODE_THIRD_VISIT // Third visit is when you come back from ->Right() - }; - - size_t nodeStack[maxDepth+1]; - float domainStack[maxDepth+1][2]; - unsigned int visitStack[maxDepth+1]; - - size_t bestPoint; - size_t curNode; - - BoundCube curDomain; - unsigned int visit; - unsigned int stackTop; - unsigned int curAxis; - - float bestDistSqr; - float tmpEdge; - - if(nodes.empty()) - return -1; - - bestPoint=(size_t)-1; - bestDistSqr =std::numeric_limits::max(); - curDomain=domainCube; - visit=NODE_FIRST_VISIT; - curAxis=0; - stackTop=0; - - //Start at medan of array, which is top of tree, - //by definition - curNode=treeRoot; - - //check root node - if(!nodes[curNode].tagged) - { - float tmpDistSqr; - tmpDistSqr = indexedPoints[curNode].first.sqrDist(searchPt); - if(tmpDistSqr < bestDistSqr) - { - bestDistSqr = tmpDistSqr; - bestPoint=curNode; - } - } - - do - { - switch(visit) - { - //Examine left branch - case NODE_FIRST_VISIT: - { - if(searchPt[curAxis] < indexedPoints[curNode].first[curAxis]) - { - if(nodes[curNode].childLeft!=(size_t)-1) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][1]; - curDomain.bounds[curAxis][1] = indexedPoints[curNode].first[curAxis]; - if(!curDomain.intersects(searchPt,bestDistSqr)) - { - curDomain.bounds[curAxis][1] = tmpEdge; - visit++; - continue; - } - //Preserve our current state. - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. - domainStack[stackTop][1] = tmpEdge; - domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; - stackTop++; - - //Update the current information - curNode=nodes[curNode].childLeft; - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - } - } - else - { - if(nodes[curNode].childRight!=(size_t)-1) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][0]; - curDomain.bounds[curAxis][0] = indexedPoints[curNode].first[curAxis]; - - if(!curDomain.intersects(searchPt,bestDistSqr)) - { - curDomain.bounds[curAxis][0] =tmpEdge; - visit++; - continue; - } - - //Preserve our current state. - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. - domainStack[stackTop][0] = tmpEdge; - domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; - stackTop++; - - //Update the information - curNode=nodes[curNode].childRight; - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - } - } - visit++; - //Fall through - } - //Examine right branch - case NODE_SECOND_VISIT: - { - if(searchPt[curAxis]< indexedPoints[curNode].first[curAxis]) - { - if(nodes[curNode].childRight!=(size_t)-1) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][0]; - curDomain.bounds[curAxis][0] = indexedPoints[curNode].first[curAxis]; - - if(!curDomain.intersects(searchPt,bestDistSqr)) - { - curDomain.bounds[curAxis][0] = tmpEdge; - visit++; - continue; - } - - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_THIRD_VISIT; - domainStack[stackTop][0] = tmpEdge; - domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; - stackTop++; - - //Update the information - curNode=nodes[curNode].childRight; - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - - } - } - else - { - if(nodes[curNode].childLeft!=(size_t)-1) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][1]; - curDomain.bounds[curAxis][1] = indexedPoints[curNode].first[curAxis]; - - if(!curDomain.intersects(searchPt,bestDistSqr)) - { - curDomain.bounds[curAxis][1] = tmpEdge; - visit++; - continue; - } - //Preserve our current state. - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_THIRD_VISIT; - domainStack[stackTop][1] = tmpEdge; - domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; - stackTop++; - - //Update the information - curNode=nodes[curNode].childLeft; - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - - } - } - visit++; - //Fall through - } - case NODE_THIRD_VISIT: - { - //Decide if we should promote the current node - //to "best" (ie nearest untagged) node. - //To promote, it musnt be tagged, and it must - //be closer than cur best estimate. - if(!nodes[curNode].tagged) - { - float tmpDistSqr; - tmpDistSqr = indexedPoints[curNode].first.sqrDist(searchPt); - if(tmpDistSqr < bestDistSqr) - { - bestDistSqr = tmpDistSqr; - bestPoint=curNode; - } - } - - //DEBUG - ASSERT(stackTop%3 == curAxis) - // - if(curAxis) - curAxis--; - else - curAxis=2; - - - - ASSERT(stackTop < maxDepth+1); - if(stackTop) - { - stackTop--; - visit=visitStack[stackTop]; - curNode=nodeStack[stackTop]; - curDomain.bounds[curAxis][0]=domainStack[stackTop][0]; - curDomain.bounds[curAxis][1]=domainStack[stackTop][1]; - ASSERT((stackTop)%3 == curAxis); - } - - break; - } - default: - ASSERT(false); - - - } - - - //Keep going until we meet the root nde for the third time (one left, one right, one finish) - }while(!(curNode== treeRoot && visit== NODE_THIRD_VISIT)); - - if(bestPoint != (size_t) -1) - nodes[bestPoint].tagged|=shouldTag; - return bestPoint; - -} - - -void K3DTreeMk2::getTreesInSphere(const Point3D &pt, float sqrDist, const BoundCube &domainCube, - vector > &contigousBlocks ) const -{ - using std::queue; - using std::pair; - using std::make_pair; - - queue nodeQueue; - queue axisQueue; - queue boundQueue; - - queue > limitQueue; - if(treeRoot == (size_t) -1) - return; - - - nodeQueue.push(treeRoot); - boundQueue.push(domainCube); - axisQueue.push(0); - limitQueue.push(make_pair(0,nodes.size()-1)); - do - { - BoundCube tmpCube; - tmpCube=boundQueue.front(); - - ASSERT(nodeQueue.size() == boundQueue.size() && - nodeQueue.size() == axisQueue.size() && - nodeQueue.size() == limitQueue.size()); - - //There are three cases here. - // - KD limits for this subdomain - // wholly contained by sphere - // > contigous subtree is interior. - // - KD Limits for this subdomain partially - // contained by sphere. - // > some subtree may be interior -- refine. - // - Does not intersect, do nothing. - - if(tmpCube.containedInSphere(pt,sqrDist)) - { - //We are? Interesting. We must be a contigous block from our lower - //to upper limits - contigousBlocks.push_back(limitQueue.front()); - } - else if(tmpCube.intersects(pt,sqrDist)) - { - size_t axis,curNode; - //Not wholly contained... but our kids might be! - axis=axisQueue.front(); - curNode=nodeQueue.front(); - - if(nodes[curNode].childLeft !=(size_t)-1) - { - //Construct left hand domain - tmpCube=boundQueue.front(); - //Set upper bound - tmpCube.bounds[axis][1] = indexedPoints[curNode].first[axis]; - - if(tmpCube.intersects(pt,sqrDist)) - { - //We have to examine left child. - nodeQueue.push(nodes[curNode].childLeft); - boundQueue.push(tmpCube); - limitQueue.push(make_pair( - limitQueue.front().first,curNode-1)); - axisQueue.push((axis+1)%3); - } - } - - if(nodes[curNode].childRight !=(size_t)-1) - { - //Construct right hand domain - tmpCube=boundQueue.front(); - //Set lower bound - tmpCube.bounds[axis][0] = indexedPoints[curNode].first[axis]; - - if(tmpCube.intersects(pt,sqrDist)) - { - //We have to examine right child. - nodeQueue.push(nodes[curNode].childRight); - boundQueue.push(tmpCube); - limitQueue.push(make_pair(curNode+1,limitQueue.front().second )); - axisQueue.push((axis+1)%3); - } - } - } - - axisQueue.pop(); - limitQueue.pop(); - boundQueue.pop(); - nodeQueue.pop(); - } - while(!nodeQueue.empty()); - -} - -size_t K3DTreeMk2::tagCount() const -{ - size_t count=0; - for(size_t ui=0;ui &tagsToClear) -{ -#pragma omp parallel for - for(size_t ui=0;ui. - */ - -#ifndef K3DTREEMK2_H -#define K3DTREEMK2_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 -// and avoiding recursive implementations -// - index based construction for smaller in-tree storage - - -#include "basics.h" - -#include "APTClasses.h" //For IonHit - -#include - -//!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 - * that axis only - */ -class AxisCompareMk2 -{ - private: - unsigned int axis; - public: - void setAxis(unsigned int Axis){axis=Axis;}; - inline bool operator()(const std::pair &p1,const std::pair &p2) const - {return p1.first[axis] - -//!Node Class for storing point -class K3DNodeMk2 -{ - public: - //Index of left child in parent tree array - size_t childLeft; - //Index of right child in parent tree array - size_t childRight; - - //Has this point been marked by an external algorithm? - bool tagged; -}; - -//!3D specific KD tree -class K3DTreeMk2 -{ - private: - //!The maximum depth of the tree - size_t maxDepth; - - //!Tree array. First element is spatial data. - //Second is original array index upon build - std::vector > indexedPoints; - - //!Tree node array (stores parent->child relations) - std::vector nodes; - - //!total size of array - size_t arraySize; - - //!Which entry is the root of the tree? - size_t treeRoot; - - BoundCube treeBounds; - - //Callback for progress reporting - bool (*callback)(bool); - - unsigned int *progress; //Progress counter - - public: - //KD Tree constructor - K3DTreeMk2(){}; - - //!Cleans up tree, deallocates nodes - ~K3DTreeMk2(){}; - - //Reset the points - void resetPts(std::vector &pts, bool clear=true); - void resetPts(std::vector &pts, bool clear=true); - - /*! Builds a balanced KD tree from a list of points - * previously set by "resetPts". returns false if callback returns - * false; - */ - bool build(); - - void getBoundCube(BoundCube &b) {ASSERT(treeBounds.isValid());b.setBounds(treeBounds);} - - //!Textual output of tree. tabs are used to separate different levels of the tree - /*!The output from this function can be quite large for even modest trees. - * Recommended for debugging only*/ - void dump(std::ostream &,size_t depth=0, size_t offset=-1) const; - - - //Find the nearest "untagged" point's internal index. - //Mark the found point as "tagged" in the tree. Returns -1 on failure (no untagged points) - size_t findNearestUntagged(const Point3D &queryPt, - const BoundCube &b, bool tag=true); - - - //!Get the contigous node IDs for a subset of points in the tree that are contained - // within a sphere positioned about pt, with a sqr radius of sqrDist. - // - This does *NOT* get *all* points - only some. - // - It should be faster than using findNearestUntagged repeatedly - // for large enough sqrDist. - // - It does not check tags. - void getTreesInSphere(const Point3D &pt, float sqrDist, const BoundCube &domainCube, - std::vector > &contigousBlocks ) const; - - //Obtain a point from its internal index - const Point3D *getPt(size_t index) const { ASSERT(index < indexedPoints.size());return &(indexedPoints[index].first);}; - - //reset the specified "tags" in the tree - void clearTags(std::vector &tagsToClear); - - size_t getOrigIndex(size_t treeIndex) const {ASSERT(treeIndex . - */ -#include "K3DTree.h" - -using std::vector; - -#include - -//Axis compare -//========== -AxisCompare::AxisCompare() : axis(0) -{ -} - -void AxisCompare::setAxis(unsigned int sortAxis) -{ - axis=sortAxis; -} - -//========== - -//K3D node -//========== - -void K3DNode::setLoc(const Point3D &locNew) -{ - loc=locNew; -} - -Point3D K3DNode::getLoc() const -{ - return loc; -} - -void K3DNode::deleteChildren() -{ - - if(childLeft) - { - childLeft->deleteChildren(); - delete childLeft; - childLeft=0; - } - - if(childRight) - { - childRight->deleteChildren(); - delete childRight; - childRight=0; - } - - -} - -void K3DNode::dump(std::ostream &strm, unsigned int depth) const -{ - for(unsigned int ui=0;uidump(strm,depth+1); - - if(childRight) - childRight->dump(strm,depth+1); -} - -//=========== - -//K3D Tree -//============= -K3DTree::K3DTree() : treeSize(0),maxDepth(0),root(0), callback(0),progress(0) -{ -} - - -K3DTree::~K3DTree() -{ - kill(); -} - - -/*void K3DTree::verify() -{ - std::stack nodeStack; - std::stack visitStack; - - K3DNode *curNode; - curNode=root; - unsigned int visit=0; - unsigned int totalVisits; - totalVisits=1; - unsigned int measuredDepth=0; - - std::stack bounds; - - BoundCube curBounds; - - //Set to limits o floating point - curBounds.setInverseLimits(); - bounds.push(curBounds); - - unsigned int curAxis=0; - do - { - //Check to see what the max. depth of the tree really is - if(visitStack.size() > measuredDepth) - measuredDepth=visitStack.size(); - - switch(visit) - { - //Examine left branch - case 0: - { - //verifyChildren(curNode) - if(curNode->left()) - { - curBounds.bounds[curAxis][1] = curNode->getLocVal(curAxis); - totalVisits++; - curAxis++; - - visitStack.push(1); - nodeStack.push(curNode); - - visit=0; - curNode=curNode->left(); - ASSERT(curBounds.containsPt(curNode->getLoc())); - continue; - } - visit++; - break; - } - //Examine right branch - case 1: - { - if(curNode->right()) - { - curBounds.bounds[curAxis][0] = curNode->getLocVal(curAxis); - totalVisits++; - curAxis++; - - visitStack.push(2); - nodeStack.push(curNode); - - visit=0; - curNode=curNode->right(); - ASSERT(curBounds.containsPt(curNode->getLoc())); - continue; - } - visit++; - break; - } - //Go up - case 2: - { - curNode=nodeStack.top(); - nodeStack.pop(); - visit=visitStack.top(); - visitStack.pop(); - curAxis--; - break; - } - } - - //Keep going until we meet the root nde for the third time (one left, one right, one finish) - }while(!(curNode==root && visit== 2)); - - std::cerr << "===COMPARE===" << std::endl; - std::cerr << " -<<>>-" << std::endl; - std::cerr << "Nodes walked : " << totalVisits << std::endl; - std::cerr << "Measered Depth: " << measuredDepth << std::endl; - - std::cerr << " -<<>>-" << std::endl; - std::cerr << "Tree reports # nodes: " << treeSize << std::endl; - std::cerr << "Tree reports Max Depth: " << maxDepth << std::endl; -}*/ - -void K3DTree::kill() -{ - if(root) - { - root->deleteChildren(); - delete root; - root=0; - treeSize=0; - } -} - -//Build the KD tree -void K3DTree::build(vector pts) -{ - //che. to see if the pts vector is empty - if(!pts.size()) - { - maxDepth=0; - return; - } - - if(root) - kill(); - - treeSize=pts.size(); - maxDepth=1; - root=buildRecurse(pts.begin(), pts.end(),0); - -} - -//Build the KD tree, shuffling original -void K3DTree::buildByRef(vector &pts) -{ - //che. to see if the pts vector is empty - if(!pts.size()) - { - maxDepth=0; - return; - } - - if(root) - kill(); - - treeSize=pts.size(); - maxDepth=1; - *progress=0; - curNodeCount=0; - root=buildRecurse(pts.begin(), pts.end(),0); -} - -K3DNode *K3DTree::buildRecurse(vector::iterator pts_start, vector::iterator pts_end, unsigned int depth) -{ - - K3DNode *node= new K3DNode; - unsigned int curAxis=depth%3; - unsigned int ptsSize=pts_end - pts_start - 1;//pts.size()-1 - node->setAxis(curAxis); - - //if we are deeper, then record that - if(depth > maxDepth) - maxDepth=depth; - - unsigned int median =(ptsSize)/2; - - //set up initial node - AxisCompare axisCmp; - axisCmp.setAxis(curAxis); - - //Find the median value in the current axis - sort(pts_start,pts_end,axisCmp); - - //allocate node (this stores a copy of the point) and set. - node->setLoc(*(pts_start + median)); - - if(median) - { - - //Only do process if callback is OK - if((*callback)(false)) - { - node->setLeft(buildRecurse(pts_start,pts_start + median,depth+1)); - *progress= (unsigned int)((float)curNodeCount/(float)treeSize*100.0f); - } - else - node->setLeft(0); - } - else - node->setLeft(0); - - if(median!=ptsSize) - { - //Only do process if callback is OK - if((*callback)(false)) - { - node->setRight(buildRecurse(pts_start + median + 1, pts_end,depth+1)); - *progress= (unsigned int)((float)curNodeCount/(float)treeSize*100.0f); - } - else - node->setRight(0); - - } - else - node->setRight(0); - - curNodeCount++; - return node; - -} - -void K3DTree::dump( std::ostream &strm) const -{ - if(root) - root->dump(strm,0); -} - - -const Point3D *K3DTree::findNearest(const Point3D &searchPt, const BoundCube &domainCube, - const float deadDistSqr) const -{ - enum { NODE_FIRST_VISIT, //First visit is when you descend the tree - NODE_SECOND_VISIT, //Second visit is when you come back from ->Left() - NODE_THIRD_VISIT // Third visit is when you come back from ->Right() - }; - - - //The stacks are for the nodes above the current Node. - const K3DNode *nodeStack[maxDepth+1]; - float domainStack[maxDepth+1][2]; - unsigned int visitStack[maxDepth+1]; - - const Point3D *bestPoint; - const K3DNode *curNode; - - BoundCube curDomain; - unsigned int visit; - unsigned int stackTop; - unsigned int curAxis; - - float bestDistSqr; - float tmpEdge; - - //Set the root as the best estimate - - bestPoint =0; - bestDistSqr =std::numeric_limits::max(); - curDomain=domainCube; - visit=NODE_FIRST_VISIT; - curAxis=0; - - stackTop=0; - - curNode=root; - - do - { - - switch(visit) - { - //Examine left branch - case NODE_FIRST_VISIT: - { - if(searchPt[curAxis] < curNode->getLocVal(curAxis)) - { - if(curNode->left()) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][1]; - curDomain.bounds[curAxis][1] = curNode->getLocVal(curAxis); - if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) - { - curDomain.bounds[curAxis][1] = tmpEdge; - visit++; - continue; - } - - //Preserve our current state. - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. - domainStack[stackTop][1] = tmpEdge; - domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; - stackTop++; - - //Update the current information - curNode=curNode->left(); - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - } - } - else - { - if(curNode->right()) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][0]; - curDomain.bounds[curAxis][0] = curNode->getLocVal(curAxis); - - if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) - { - curDomain.bounds[curAxis][0] =tmpEdge; - visit++; - continue; - } - //Preserve our current state. - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. - domainStack[stackTop][0] = tmpEdge; - domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; - stackTop++; - - //Update the information - curNode=curNode->right(); - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - } - - } - visit++; - //Fall through - } - //Examine right branch - case NODE_SECOND_VISIT: - { - if(searchPt[curAxis]< curNode->getLocVal(curAxis)) - { - if(curNode->right()) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][0]; - curDomain.bounds[curAxis][0] = curNode->getLocVal(curAxis); - - if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) - { - curDomain.bounds[curAxis][0] = tmpEdge; - visit++; - continue; - } - - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_THIRD_VISIT; //Oh, It will be. It will be. - domainStack[stackTop][0] = tmpEdge; - domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; - stackTop++; - - //Update the information - curNode=curNode->right(); - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - - } - } - else - { - if(curNode->left()) - { - //Check bounding box when shrunk overlaps best - //estimate sphere - tmpEdge= curDomain.bounds[curAxis][1]; - curDomain.bounds[curAxis][1] = curNode->getLocVal(curAxis); - - if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) - { - curDomain.bounds[curAxis][1] = tmpEdge; - visit++; - continue; - } - //Preserve our current state. - nodeStack[stackTop]=curNode; - visitStack[stackTop] = NODE_THIRD_VISIT; //Oh, It will be. It will be. - domainStack[stackTop][1] = tmpEdge; - domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; - stackTop++; - - //Update the information - curNode=curNode->left(); - visit=NODE_FIRST_VISIT; - curAxis++; - curAxis%=3; - continue; - - } - } - visit++; - //Fall through - } - //Go up - case NODE_THIRD_VISIT: - { - float tmpDistSqr; - tmpDistSqr = curNode->sqrDist(searchPt); - if(tmpDistSqr < bestDistSqr && tmpDistSqr > deadDistSqr) - { - bestDistSqr = tmpDistSqr; - bestPoint=curNode->getLocRef(); - } - - //DEBUG - ASSERT(stackTop%3 == curAxis) - // - if(curAxis) - curAxis--; - else - curAxis=2; - - - - ASSERT(stackTop < maxDepth+1); - if(stackTop) - { - stackTop--; - visit=visitStack[stackTop]; - curNode=nodeStack[stackTop]; - curDomain.bounds[curAxis][0]=domainStack[stackTop][0]; - curDomain.bounds[curAxis][1]=domainStack[stackTop][1]; - ASSERT((stackTop)%3 == curAxis) - } - - break; - } - default: - ASSERT(false); - - - } - - //Keep going until we meet the root nde for the third time (one left, one right, one finish) - }while(!(curNode==root && visit== NODE_THIRD_VISIT)); - - return bestPoint; - -} - - -void K3DTree::findKNearest(const Point3D &searchPt, const BoundCube &domainCube, - unsigned int num, vector &bestPts, - float deadDistSqr) const -{ - //find the N nearest points - float sqrDist; - bestPts.clear(); - bestPts.reserve(num); - - const Point3D *p; - for(unsigned int ui=0; uisqrDist(searchPt); - deadDistSqr = sqrDist+std::numeric_limits::epsilon(); - - } - -} -//============= diff -Nru 3depict-0.0.12/src/K3DTree.h 3depict-0.0.13/src/K3DTree.h --- 3depict-0.0.12/src/K3DTree.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/K3DTree.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,176 +0,0 @@ -/* - * K3DTree.h - limited precision KD tree implementation - * 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 - * 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 . - */ -#ifndef K3DTREE_H -#define K3DTREE_H - - -#include -#include -#include -#include - -#include "mathfuncs.h" -#include "basics.h" //For BoundCube - -class K3DNode; -class AxisCompare; -class K3DTree; - - -//!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 - * that axis only - */ -class AxisCompare -{ - private: - unsigned int axis; - public: - AxisCompare(); - void setAxis(unsigned int Axis); - inline bool operator()(const Point3D &p1,const Point3D &p2) const - {return p1[axis]::iterator pts_start, - std::vector::iterator pts_end, unsigned int depth ); - - bool (*callback)(bool); - - unsigned int *progress; //Progress counter - size_t curNodeCount; //Counter for build operations - public: - - //KD Tree constructor - K3DTree(); - - //!Cleans up tree, deallocates nodes - ~K3DTree(); - - //Set the callback routine for progress reporting - void setCallbackMethod(bool (*cb)(bool)) {callback = cb;} - - void setProgressPointer(unsigned int *p) { progress=p;}; - - - /*! Builds a balanced KD tree from a list of points - * This call is being passed by copy in order to prevent - * re-ordering of the points. It may be worth having two calls - * a pass by ref version where the points get scrambled and this one - * which preserves input point ordering (due to the copy) - */ - void build(std::vector pts); - - /*! Builds a balanced KD tree from a list of points - * This uses a pass by ref where the points get scrambled (sorted). - * Resultant tree should be identical to that generated by build() - */ - void buildByRef(std::vector &pts); - - - //Tree walker that counts the number of nodes - //void verify(); - - //! Clean the tree - void kill(); - - //!Find the nearest point to a given P that lies outsid some dead zone - /*!deadDistSqr can be used ot disallow exact matching on NN searching - * simply pass epsilon =std::numeric_limits::epsilon() - * (#include ) - * Boundcube is the bounding box around the entire dataset - */ - const Point3D *findNearest(const Point3D &, const BoundCube &, - - float deadDistSqr) const; - - //!Find the nearest N points - /*!Finds the nearest N points, that lie outside a - * dead distance of deadDistSqr. k is the number to find - */ - void findKNearest(const Point3D & sourcePoint, const BoundCube& treeDomain, - unsigned int numNNs, std::vector &results, - float deadDistSqr=0.0f) const; - - //!Textual output of tree. tabs are used to separate different levels of the tree - /*!The output from this function can be quite large for even modest trees. - * Recommended for debugging only*/ - void dump(std::ostream &) const; - - //!Print the number of nodes stored in the tree - inline unsigned int nodeCount() const{return treeSize;}; -}; - - - -#endif diff -Nru 3depict-0.0.12/src/Makefile.am 3depict-0.0.13/src/Makefile.am --- 3depict-0.0.12/src/Makefile.am 2012-11-12 22:36:58.000000000 +0000 +++ 3depict-0.0.13/src/Makefile.am 2013-03-23 11:43:07.000000000 +0000 @@ -21,66 +21,88 @@ bin_PROGRAMS= 3Depict -FILTER_FILES = filters/allFilter.cpp filters/dataLoad.cpp filters/ionDownsample.cpp \ - filters/rangeFile.cpp filters/voxelise.cpp filters/spectrumPlot.cpp \ - filters/transform.cpp filters/externalProgram.cpp filters/ionClip.cpp \ - filters/ionColour.cpp filters/boundingBox.cpp \ - filters/compositionProfile.cpp filters/spatialAnalysis.cpp \ - filters/clusterAnalysis.cpp filters/ionInfo.cpp \ - filters/annotation.cpp - -FILTER_HEADER_FILES = filters/allFilter.h filters/dataLoad.h filters/ionDownsample.h \ - filters/rangeFile.h filters/voxelise.h filters/spectrumPlot.h \ - filters/transform.h filters/externalProgram.h filters/ionClip.h \ - filters/ionColour.h filters/boundingBox.h \ - filters/compositionProfile.h filters/spatialAnalysis.h \ - filters/clusterAnalysis.h filters/ionInfo.h \ - filters/annotation.h - -DIALOG_SOURCE_FILES = dialogs/ExportPos.cpp dialogs/ExportRngDialog.cpp dialogs/prefDialog.cpp \ - dialogs/resolutionDialog.cpp dialogs/StashDialog.cpp \ - dialogs/autosaveDialog.cpp dialogs/filterErrorDialog.cpp \ - dialogs/animateFilterDialog.cpp \ - dialogs/animateSubDialogs/colourKeyFrameDialog.cpp \ - dialogs/animateSubDialogs/stringKeyFrameDialog.cpp \ - dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp - - -DIALOG_HEADER_FILES = dialogs/ExportPos.h dialogs/ExportRngDialog.h dialogs/prefDialog.h \ - dialogs/StashDialog.h dialogs/resolutionDialog.h \ - dialogs/autosaveDialog.h dialogs/filterErrorDialog.h \ - dialogs/animateFilterDialog.h \ - dialogs/animateSubDialogs/realKeyFrameDialog.h \ - dialogs/animateSubDialogs/colourKeyFrameDialog.h \ - dialogs/animateSubDialogs/stringKeyFrameDialog.h \ - dialogs/animateSubDialogs/choiceKeyFrameDialog.h - -#These source files should have heirachical couplings only; no cross-coupling -BASE_SOURCE_FILES= animator.cpp eventlogger.cpp filtertreeAnalyse.cpp filtertree.cpp mathglPane.cpp \ - plot.cpp configFile.cpp filter.cpp \ - APTClasses.cpp select.cpp \ - drawables.cpp effect.cpp textures.cpp rdf.cpp \ - cameras.cpp isoSurface.cpp K3DTree.cpp K3DTree-mk2.cpp\ - xmlHelper.cpp cropPanel.cpp colourmap.cpp \ - pngread.c mathfuncs.cpp wxcomponents.cpp wxcommon.cpp - -BASE_HEADER_FILES= animator.h eventlogger.h filtertreeAnalyse.h filtertree.h mathglPane.h plot.h \ - configFile.h filter.h APTClasses.h select.h \ - drawables.h effect.h textures.h rdf.h translation.h winconsole.h \ - cameras.h isoSurface.h K3DTree.h K3DTree-mk2.h\ - xmlHelper.h cropPanel.h colourmap.h \ - pngread.h mathfuncs.h wxcomponents.h wxcommon.h voxels.h \ - endianTest.h assertion.h commonConstants.h art.h tree.hh 3Depict.xpm - - -#These files are inter-dependant to some extent (mostly viscontrol) -CROSS_DEP_SOURCE_FILES=testing.cpp 3Depict.cpp basics.cpp glPane.cpp \ - scene.cpp viscontrol.cpp -CROSS_DEP_HEADER_FILES=testing.h 3Depict.h basics.h glPane.h \ - scene.h viscontrol.h - -SOURCE_FILES= $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(DIALOG_SOURCE_FILES) $(DIALOG_HEADER_FILES) $(FILTER_FILES) $(FILTER_HEADER_FILES) \ - $(CROSS_DEP_SOURCE_FILES) $(CROSS_DEP_HEADER_FILES) +#------- 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 + +#----------- + +#------- "Backend" calculation files (non-ui) ---------- +FILTER_FILES = backend/filters/allFilter.cpp backend/filters/filterCommon.cpp \ + backend/filters/dataLoad.cpp backend/filters/ionDownsample.cpp \ + backend/filters/rangeFile.cpp backend/filters/voxelise.cpp \ + backend/filters/spectrumPlot.cpp backend/filters/transform.cpp \ + backend/filters/externalProgram.cpp backend/filters/ionClip.cpp \ + backend/filters/ionColour.cpp backend/filters/boundingBox.cpp \ + backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \ + backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \ + backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp + +FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \ + backend/filters/dataLoad.h backend/filters/ionDownsample.h \ + backend/filters/rangeFile.h backend/filters/voxelise.h backend/filters/spectrumPlot.h \ + backend/filters/transform.h backend/filters/externalProgram.h backend/filters/ionClip.h \ + backend/filters/ionColour.h backend/filters/boundingBox.h \ + backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \ + backend/filters/clusterAnalysis.h backend/filters/ionInfo.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/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_HEADER_FILES = 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/plot.h backend/configFile.h \ + backend/tree.hh + +#------------ + +#------------ OpenGL interface files +OPENGL_HEADER_FILES = gl/scene.h gl/drawables.h gl/effect.h gl/textures.h gl/select.h gl/cameras.h gl/isoSurface.h +OPENGL_SOURCE_FILES = gl/scene.cpp gl/drawables.cpp gl/effect.cpp gl/textures.cpp gl/select.cpp gl/cameras.cpp gl/isoSurface.cpp + + +#------------ + + + +#------------ Frontend (linked to UI in some way) files --- +DIALOG_SOURCE_FILES = gui/dialogs/ExportPos.cpp gui/dialogs/ExportRngDialog.cpp gui/dialogs/prefDialog.cpp \ + gui/dialogs/resolutionDialog.cpp gui/dialogs/StashDialog.cpp \ + gui/dialogs/autosaveDialog.cpp gui/dialogs/filterErrorDialog.cpp \ + gui/dialogs/animateFilterDialog.cpp \ + gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp \ + gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp \ + gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp + + +DIALOG_HEADER_FILES = gui/dialogs/ExportPos.h gui/dialogs/ExportRngDialog.h gui/dialogs/prefDialog.h \ + gui/dialogs/StashDialog.h gui/dialogs/resolutionDialog.h \ + gui/dialogs/autosaveDialog.h gui/dialogs/filterErrorDialog.h \ + gui/dialogs/animateFilterDialog.h \ + gui/dialogs/animateSubDialogs/realKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h + +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 +#----------- + + + +SOURCE_FILES= $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(GUI_SOURCE_FILES) $(GUI_HEADER_FILES) \ + $(FILTER_FILES) $(FILTER_HEADER_FILES) \ + ${BACKEND_SOURCE_FILES} ${BACKEND_HEADER_FILES} $(OPENGL_SOURCE_FILES) $(OPENGL_HEADER_FILES) \ + $(COMMON_SOURCE_FILES) $(COMMON_HEADER_FILES) #Do we have or need windows-XP "resource" files for look and feel? @@ -91,22 +113,6 @@ endif #Tarball options -EXTRA_DIST = textures/ tex-source/ glade-skeleton/ myAppIcon.ico +EXTRA_DIST = gui/glade-skeleton myAppIcon.ico -if USE_PRECOMPILED_HEADERS - -#Precompiled headers -BUILT_SOURCES= mathglPane.h.gch plot.h.gch configFile.h.gch filter.h.gch \ - APTClasses.h.gch resDialog.h.gch select.h.gch \ - drawables.h.gch effect.h.gch textures.h.gch rdf.h.gch \ - cameras.h.gch isoSurface.h.gch K3DTree.h.gch K3DTree-mk2.h.gch\ - basics.h.gch xmlHelper.h.gch cropPanel.h.gch colourmap.h.gch \ - pngread.h.gch mathfuncs.h.gch wxcomponents.h.gch wxcommon.h.gch voxels.h.gch \ - endianTest.h.gch assertion.h.gch commonConstants.h.gch art.h.gch tree.hh.gch -%.hh.gch: %.hh - $(CXXCOMPILE) $(3Depict_CXXFLAGS)-c $< - -%.h.gch: %.h - $(CXXCOMPILE) $(3Depict_CXXFLAGS) -c $< -endif diff -Nru 3depict-0.0.12/src/Makefile.in 3depict-0.0.13/src/Makefile.in --- 3depict-0.0.12/src/Makefile.in 2012-11-12 22:37:03.000000000 +0000 +++ 3depict-0.0.13/src/Makefile.in 2013-04-06 11:05:53.000000000 +0000 @@ -66,67 +66,74 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) -am__3Depict_SOURCES_DIST = animator.cpp eventlogger.cpp \ - filtertreeAnalyse.cpp filtertree.cpp mathglPane.cpp plot.cpp \ - configFile.cpp filter.cpp APTClasses.cpp select.cpp \ - drawables.cpp effect.cpp textures.cpp rdf.cpp cameras.cpp \ - isoSurface.cpp K3DTree.cpp K3DTree-mk2.cpp xmlHelper.cpp \ - cropPanel.cpp colourmap.cpp pngread.c mathfuncs.cpp \ - wxcomponents.cpp wxcommon.cpp animator.h eventlogger.h \ - filtertreeAnalyse.h filtertree.h mathglPane.h plot.h \ - configFile.h filter.h APTClasses.h select.h drawables.h \ - effect.h textures.h rdf.h translation.h winconsole.h cameras.h \ - isoSurface.h K3DTree.h K3DTree-mk2.h xmlHelper.h cropPanel.h \ - colourmap.h pngread.h mathfuncs.h wxcomponents.h wxcommon.h \ - voxels.h endianTest.h assertion.h commonConstants.h art.h \ - tree.hh 3Depict.xpm dialogs/ExportPos.cpp \ - dialogs/ExportRngDialog.cpp dialogs/prefDialog.cpp \ - dialogs/resolutionDialog.cpp dialogs/StashDialog.cpp \ - dialogs/autosaveDialog.cpp dialogs/filterErrorDialog.cpp \ - dialogs/animateFilterDialog.cpp \ - dialogs/animateSubDialogs/colourKeyFrameDialog.cpp \ - dialogs/animateSubDialogs/stringKeyFrameDialog.cpp \ - dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp \ - dialogs/ExportPos.h dialogs/ExportRngDialog.h \ - dialogs/prefDialog.h dialogs/StashDialog.h \ - dialogs/resolutionDialog.h dialogs/autosaveDialog.h \ - dialogs/filterErrorDialog.h dialogs/animateFilterDialog.h \ - dialogs/animateSubDialogs/realKeyFrameDialog.h \ - dialogs/animateSubDialogs/colourKeyFrameDialog.h \ - dialogs/animateSubDialogs/stringKeyFrameDialog.h \ - dialogs/animateSubDialogs/choiceKeyFrameDialog.h \ - filters/allFilter.cpp filters/dataLoad.cpp \ - filters/ionDownsample.cpp filters/rangeFile.cpp \ - filters/voxelise.cpp filters/spectrumPlot.cpp \ - filters/transform.cpp filters/externalProgram.cpp \ - filters/ionClip.cpp filters/ionColour.cpp \ - filters/boundingBox.cpp filters/compositionProfile.cpp \ - filters/spatialAnalysis.cpp filters/clusterAnalysis.cpp \ - filters/ionInfo.cpp filters/annotation.cpp filters/allFilter.h \ - filters/dataLoad.h filters/ionDownsample.h filters/rangeFile.h \ - filters/voxelise.h filters/spectrumPlot.h filters/transform.h \ - filters/externalProgram.h filters/ionClip.h \ - filters/ionColour.h filters/boundingBox.h \ - filters/compositionProfile.h filters/spatialAnalysis.h \ - filters/clusterAnalysis.h filters/ionInfo.h \ - filters/annotation.h testing.cpp 3Depict.cpp basics.cpp \ - glPane.cpp scene.cpp viscontrol.cpp testing.h 3Depict.h \ - basics.h glPane.h scene.h viscontrol.h winconsole.cpp \ - 3Depict.rc -am__objects_1 = 3Depict-animator.$(OBJEXT) \ - 3Depict-eventlogger.$(OBJEXT) \ - 3Depict-filtertreeAnalyse.$(OBJEXT) \ - 3Depict-filtertree.$(OBJEXT) 3Depict-mathglPane.$(OBJEXT) \ - 3Depict-plot.$(OBJEXT) 3Depict-configFile.$(OBJEXT) \ - 3Depict-filter.$(OBJEXT) 3Depict-APTClasses.$(OBJEXT) \ - 3Depict-select.$(OBJEXT) 3Depict-drawables.$(OBJEXT) \ - 3Depict-effect.$(OBJEXT) 3Depict-textures.$(OBJEXT) \ - 3Depict-rdf.$(OBJEXT) 3Depict-cameras.$(OBJEXT) \ - 3Depict-isoSurface.$(OBJEXT) 3Depict-K3DTree.$(OBJEXT) \ - 3Depict-K3DTree-mk2.$(OBJEXT) 3Depict-xmlHelper.$(OBJEXT) \ - 3Depict-cropPanel.$(OBJEXT) 3Depict-colourmap.$(OBJEXT) \ - 3Depict-pngread.$(OBJEXT) 3Depict-mathfuncs.$(OBJEXT) \ - 3Depict-wxcomponents.$(OBJEXT) 3Depict-wxcommon.$(OBJEXT) +am__3Depict_SOURCES_DIST = 3Depict.cpp testing.cpp pngread.c \ + wxcomponents.cpp wxcommon.cpp testing.h winconsole.h pngread.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 \ + gui/dialogs/resolutionDialog.cpp gui/dialogs/StashDialog.cpp \ + gui/dialogs/autosaveDialog.cpp \ + gui/dialogs/filterErrorDialog.cpp \ + gui/dialogs/animateFilterDialog.cpp \ + gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp \ + gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp \ + gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp \ + gui/mainFrame.h gui/mathglPane.h gui/cropPanel.h gui/art.h \ + gui/glPane.h gui/dialogs/ExportPos.h \ + gui/dialogs/ExportRngDialog.h gui/dialogs/prefDialog.h \ + gui/dialogs/StashDialog.h gui/dialogs/resolutionDialog.h \ + gui/dialogs/autosaveDialog.h gui/dialogs/filterErrorDialog.h \ + gui/dialogs/animateFilterDialog.h \ + gui/dialogs/animateSubDialogs/realKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h \ + backend/filters/allFilter.cpp backend/filters/filterCommon.cpp \ + backend/filters/dataLoad.cpp backend/filters/ionDownsample.cpp \ + backend/filters/rangeFile.cpp backend/filters/voxelise.cpp \ + backend/filters/spectrumPlot.cpp backend/filters/transform.cpp \ + backend/filters/externalProgram.cpp \ + backend/filters/ionClip.cpp backend/filters/ionColour.cpp \ + backend/filters/boundingBox.cpp \ + backend/filters/compositionProfile.cpp \ + backend/filters/spatialAnalysis.cpp \ + backend/filters/clusterAnalysis.cpp \ + backend/filters/ionInfo.cpp backend/filters/annotation.cpp \ + backend/filters/geometryHelpers.cpp \ + backend/filters/allFilter.h backend/filters/filterCommon.h \ + backend/filters/dataLoad.h backend/filters/ionDownsample.h \ + backend/filters/rangeFile.h backend/filters/voxelise.h \ + backend/filters/spectrumPlot.h backend/filters/transform.h \ + backend/filters/externalProgram.h backend/filters/ionClip.h \ + backend/filters/ionColour.h backend/filters/boundingBox.h \ + backend/filters/compositionProfile.h \ + backend/filters/spatialAnalysis.h \ + 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/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/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 \ + 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 +am__objects_1 = 3Depict-3Depict.$(OBJEXT) 3Depict-testing.$(OBJEXT) \ + 3Depict-pngread.$(OBJEXT) 3Depict-wxcomponents.$(OBJEXT) \ + 3Depict-wxcommon.$(OBJEXT) am__objects_2 = am__objects_3 = 3Depict-ExportPos.$(OBJEXT) \ 3Depict-ExportRngDialog.$(OBJEXT) 3Depict-prefDialog.$(OBJEXT) \ @@ -137,7 +144,12 @@ 3Depict-colourKeyFrameDialog.$(OBJEXT) \ 3Depict-stringKeyFrameDialog.$(OBJEXT) \ 3Depict-choiceKeyFrameDialog.$(OBJEXT) -am__objects_4 = 3Depict-allFilter.$(OBJEXT) 3Depict-dataLoad.$(OBJEXT) \ +am__objects_4 = 3Depict-mainFrame.$(OBJEXT) \ + 3Depict-mathglPane.$(OBJEXT) 3Depict-cropPanel.$(OBJEXT) \ + 3Depict-glPane.$(OBJEXT) $(am__objects_3) +am__objects_5 = $(am__objects_2) +am__objects_6 = 3Depict-allFilter.$(OBJEXT) \ + 3Depict-filterCommon.$(OBJEXT) 3Depict-dataLoad.$(OBJEXT) \ 3Depict-ionDownsample.$(OBJEXT) 3Depict-rangeFile.$(OBJEXT) \ 3Depict-voxelise.$(OBJEXT) 3Depict-spectrumPlot.$(OBJEXT) \ 3Depict-transform.$(OBJEXT) 3Depict-externalProgram.$(OBJEXT) \ @@ -146,15 +158,28 @@ 3Depict-compositionProfile.$(OBJEXT) \ 3Depict-spatialAnalysis.$(OBJEXT) \ 3Depict-clusterAnalysis.$(OBJEXT) 3Depict-ionInfo.$(OBJEXT) \ - 3Depict-annotation.$(OBJEXT) -am__objects_5 = 3Depict-testing.$(OBJEXT) 3Depict-3Depict.$(OBJEXT) \ - 3Depict-basics.$(OBJEXT) 3Depict-glPane.$(OBJEXT) \ - 3Depict-scene.$(OBJEXT) 3Depict-viscontrol.$(OBJEXT) -am__objects_6 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_2) $(am__objects_4) $(am__objects_2) \ - $(am__objects_5) $(am__objects_2) -@HAVE_WINDRES_FALSE@am_3Depict_OBJECTS = $(am__objects_6) -@HAVE_WINDRES_TRUE@am_3Depict_OBJECTS = $(am__objects_6) \ + 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-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_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@am_3Depict_OBJECTS = $(am__objects_10) +@HAVE_WINDRES_TRUE@am_3Depict_OBJECTS = $(am__objects_10) \ @HAVE_WINDRES_TRUE@ 3Depict-winconsole.$(OBJEXT) \ @HAVE_WINDRES_TRUE@ 3Depict.$(OBJEXT) 3Depict_OBJECTS = $(am_3Depict_OBJECTS) @@ -336,67 +361,82 @@ 3Depict_LDADD = $(LIBS) $(GETTEXT_LIBS) $(WX_LIBS) $(MGL_LIBS) $(FTGL_LIBS) \ $(FT_LIBS) $(XML_LIBS) $(GSL_LIBS) $(GL_LIBS) $(GLU_LIBS) $(QHULL_LIBS) $(PNG_LIBS) -FILTER_FILES = filters/allFilter.cpp filters/dataLoad.cpp filters/ionDownsample.cpp \ - filters/rangeFile.cpp filters/voxelise.cpp filters/spectrumPlot.cpp \ - filters/transform.cpp filters/externalProgram.cpp filters/ionClip.cpp \ - filters/ionColour.cpp filters/boundingBox.cpp \ - filters/compositionProfile.cpp filters/spatialAnalysis.cpp \ - filters/clusterAnalysis.cpp filters/ionInfo.cpp \ - filters/annotation.cpp - -FILTER_HEADER_FILES = filters/allFilter.h filters/dataLoad.h filters/ionDownsample.h \ - filters/rangeFile.h filters/voxelise.h filters/spectrumPlot.h \ - filters/transform.h filters/externalProgram.h filters/ionClip.h \ - filters/ionColour.h filters/boundingBox.h \ - filters/compositionProfile.h filters/spatialAnalysis.h \ - filters/clusterAnalysis.h filters/ionInfo.h \ - filters/annotation.h - -DIALOG_SOURCE_FILES = dialogs/ExportPos.cpp dialogs/ExportRngDialog.cpp dialogs/prefDialog.cpp \ - dialogs/resolutionDialog.cpp dialogs/StashDialog.cpp \ - dialogs/autosaveDialog.cpp dialogs/filterErrorDialog.cpp \ - dialogs/animateFilterDialog.cpp \ - dialogs/animateSubDialogs/colourKeyFrameDialog.cpp \ - dialogs/animateSubDialogs/stringKeyFrameDialog.cpp \ - dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp - -DIALOG_HEADER_FILES = dialogs/ExportPos.h dialogs/ExportRngDialog.h dialogs/prefDialog.h \ - dialogs/StashDialog.h dialogs/resolutionDialog.h \ - dialogs/autosaveDialog.h dialogs/filterErrorDialog.h \ - dialogs/animateFilterDialog.h \ - dialogs/animateSubDialogs/realKeyFrameDialog.h \ - dialogs/animateSubDialogs/colourKeyFrameDialog.h \ - dialogs/animateSubDialogs/stringKeyFrameDialog.h \ - dialogs/animateSubDialogs/choiceKeyFrameDialog.h - - -#These source files should have heirachical couplings only; no cross-coupling -BASE_SOURCE_FILES = animator.cpp eventlogger.cpp filtertreeAnalyse.cpp filtertree.cpp mathglPane.cpp \ - plot.cpp configFile.cpp filter.cpp \ - APTClasses.cpp select.cpp \ - drawables.cpp effect.cpp textures.cpp rdf.cpp \ - cameras.cpp isoSurface.cpp K3DTree.cpp K3DTree-mk2.cpp\ - xmlHelper.cpp cropPanel.cpp colourmap.cpp \ - pngread.c mathfuncs.cpp wxcomponents.cpp wxcommon.cpp - -BASE_HEADER_FILES = animator.h eventlogger.h filtertreeAnalyse.h filtertree.h mathglPane.h plot.h \ - configFile.h filter.h APTClasses.h select.h \ - drawables.h effect.h textures.h rdf.h translation.h winconsole.h \ - cameras.h isoSurface.h K3DTree.h K3DTree-mk2.h\ - xmlHelper.h cropPanel.h colourmap.h \ - pngread.h mathfuncs.h wxcomponents.h wxcommon.h voxels.h \ - endianTest.h assertion.h commonConstants.h art.h tree.hh 3Depict.xpm - - -#These files are inter-dependant to some extent (mostly viscontrol) -CROSS_DEP_SOURCE_FILES = testing.cpp 3Depict.cpp basics.cpp glPane.cpp \ - scene.cpp viscontrol.cpp - -CROSS_DEP_HEADER_FILES = testing.h 3Depict.h basics.h glPane.h \ - scene.h viscontrol.h -SOURCE_FILES = $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(DIALOG_SOURCE_FILES) $(DIALOG_HEADER_FILES) $(FILTER_FILES) $(FILTER_HEADER_FILES) \ - $(CROSS_DEP_SOURCE_FILES) $(CROSS_DEP_HEADER_FILES) +#------- 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 + +#----------- + +#------- "Backend" calculation files (non-ui) ---------- +FILTER_FILES = backend/filters/allFilter.cpp backend/filters/filterCommon.cpp \ + backend/filters/dataLoad.cpp backend/filters/ionDownsample.cpp \ + backend/filters/rangeFile.cpp backend/filters/voxelise.cpp \ + backend/filters/spectrumPlot.cpp backend/filters/transform.cpp \ + backend/filters/externalProgram.cpp backend/filters/ionClip.cpp \ + backend/filters/ionColour.cpp backend/filters/boundingBox.cpp \ + backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \ + backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \ + backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp + +FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \ + backend/filters/dataLoad.h backend/filters/ionDownsample.h \ + backend/filters/rangeFile.h backend/filters/voxelise.h backend/filters/spectrumPlot.h \ + backend/filters/transform.h backend/filters/externalProgram.h backend/filters/ionClip.h \ + backend/filters/ionColour.h backend/filters/boundingBox.h \ + backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \ + backend/filters/clusterAnalysis.h backend/filters/ionInfo.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/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_HEADER_FILES = 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/plot.h backend/configFile.h \ + backend/tree.hh + + +#------------ + +#------------ OpenGL interface files +OPENGL_HEADER_FILES = gl/scene.h gl/drawables.h gl/effect.h gl/textures.h gl/select.h gl/cameras.h gl/isoSurface.h +OPENGL_SOURCE_FILES = gl/scene.cpp gl/drawables.cpp gl/effect.cpp gl/textures.cpp gl/select.cpp gl/cameras.cpp gl/isoSurface.cpp + +#------------ + +#------------ Frontend (linked to UI in some way) files --- +DIALOG_SOURCE_FILES = gui/dialogs/ExportPos.cpp gui/dialogs/ExportRngDialog.cpp gui/dialogs/prefDialog.cpp \ + gui/dialogs/resolutionDialog.cpp gui/dialogs/StashDialog.cpp \ + gui/dialogs/autosaveDialog.cpp gui/dialogs/filterErrorDialog.cpp \ + gui/dialogs/animateFilterDialog.cpp \ + gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp \ + gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp \ + gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp + +DIALOG_HEADER_FILES = gui/dialogs/ExportPos.h gui/dialogs/ExportRngDialog.h gui/dialogs/prefDialog.h \ + gui/dialogs/StashDialog.h gui/dialogs/resolutionDialog.h \ + gui/dialogs/autosaveDialog.h gui/dialogs/filterErrorDialog.h \ + gui/dialogs/animateFilterDialog.h \ + gui/dialogs/animateSubDialogs/realKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h \ + gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h + +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 +#----------- +SOURCE_FILES = $(BASE_SOURCE_FILES) $(BASE_HEADER_FILES) $(GUI_SOURCE_FILES) $(GUI_HEADER_FILES) \ + $(FILTER_FILES) $(FILTER_HEADER_FILES) \ + ${BACKEND_SOURCE_FILES} ${BACKEND_HEADER_FILES} $(OPENGL_SOURCE_FILES) $(OPENGL_HEADER_FILES) \ + $(COMMON_SOURCE_FILES) $(COMMON_HEADER_FILES) @HAVE_WINDRES_FALSE@3Depict_SOURCES = $(SOURCE_FILES) @@ -404,19 +444,8 @@ @HAVE_WINDRES_TRUE@3Depict_SOURCES = $(SOURCE_FILES) winconsole.cpp 3Depict.rc #Tarball options -EXTRA_DIST = textures/ tex-source/ glade-skeleton/ myAppIcon.ico - -#Precompiled headers -@USE_PRECOMPILED_HEADERS_TRUE@BUILT_SOURCES = mathglPane.h.gch plot.h.gch configFile.h.gch filter.h.gch \ -@USE_PRECOMPILED_HEADERS_TRUE@ APTClasses.h.gch resDialog.h.gch select.h.gch \ -@USE_PRECOMPILED_HEADERS_TRUE@ drawables.h.gch effect.h.gch textures.h.gch rdf.h.gch \ -@USE_PRECOMPILED_HEADERS_TRUE@ cameras.h.gch isoSurface.h.gch K3DTree.h.gch K3DTree-mk2.h.gch\ -@USE_PRECOMPILED_HEADERS_TRUE@ basics.h.gch xmlHelper.h.gch cropPanel.h.gch colourmap.h.gch \ -@USE_PRECOMPILED_HEADERS_TRUE@ pngread.h.gch mathfuncs.h.gch wxcomponents.h.gch wxcommon.h.gch voxels.h.gch \ -@USE_PRECOMPILED_HEADERS_TRUE@ endianTest.h.gch assertion.h.gch commonConstants.h.gch art.h.gch tree.hh.gch - -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-am +EXTRA_DIST = gui/glade-skeleton myAppIcon.ico +all: all-am .SUFFIXES: .SUFFIXES: .c .cpp .o .obj .rc @@ -502,6 +531,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-3Depict.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-APTClasses.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-APTRanges.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-ExportPos.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-ExportRngDialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-K3DTree-mk2.Po@am__quote@ @@ -525,18 +555,20 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-dataLoad.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-drawables.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-effect.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-eventlogger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-externalProgram.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-filterCommon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-filterErrorDialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-filtertree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-filtertreeAnalyse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-geometryHelpers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-glPane.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-ionClip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-ionColour.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-ionDownsample.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-ionInfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-isoSurface.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-mainFrame.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-mathfuncs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-mathglPane.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-plot.Po@am__quote@ @@ -549,12 +581,14 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-select.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-spatialAnalysis.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-spectrumPlot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-stringFuncs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-stringKeyFrameDialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-testing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-textures.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-transform.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-viscontrol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-voxelise.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-voxels.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-winconsole.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-wxcommon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/3Depict-wxcomponents.Po@am__quote@ @@ -602,803 +636,873 @@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` -3Depict-animator.o: animator.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animator.o -MD -MP -MF $(DEPDIR)/3Depict-animator.Tpo -c -o 3Depict-animator.o `test -f 'animator.cpp' || echo '$(srcdir)/'`animator.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animator.Tpo $(DEPDIR)/3Depict-animator.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='animator.cpp' object='3Depict-animator.o' libtool=no @AMDEPBACKSLASH@ +3Depict-3Depict.o: 3Depict.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-3Depict.o -MD -MP -MF $(DEPDIR)/3Depict-3Depict.Tpo -c -o 3Depict-3Depict.o `test -f '3Depict.cpp' || echo '$(srcdir)/'`3Depict.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-3Depict.Tpo $(DEPDIR)/3Depict-3Depict.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='3Depict.cpp' object='3Depict-3Depict.o' libtool=no @AMDEPBACKSLASH@ @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-animator.o `test -f 'animator.cpp' || echo '$(srcdir)/'`animator.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-3Depict.o `test -f '3Depict.cpp' || echo '$(srcdir)/'`3Depict.cpp -3Depict-animator.obj: animator.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animator.obj -MD -MP -MF $(DEPDIR)/3Depict-animator.Tpo -c -o 3Depict-animator.obj `if test -f 'animator.cpp'; then $(CYGPATH_W) 'animator.cpp'; else $(CYGPATH_W) '$(srcdir)/animator.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animator.Tpo $(DEPDIR)/3Depict-animator.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='animator.cpp' object='3Depict-animator.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-3Depict.obj: 3Depict.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-3Depict.obj -MD -MP -MF $(DEPDIR)/3Depict-3Depict.Tpo -c -o 3Depict-3Depict.obj `if test -f '3Depict.cpp'; then $(CYGPATH_W) '3Depict.cpp'; else $(CYGPATH_W) '$(srcdir)/3Depict.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-3Depict.Tpo $(DEPDIR)/3Depict-3Depict.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='3Depict.cpp' object='3Depict-3Depict.obj' libtool=no @AMDEPBACKSLASH@ @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-animator.obj `if test -f 'animator.cpp'; then $(CYGPATH_W) 'animator.cpp'; else $(CYGPATH_W) '$(srcdir)/animator.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-3Depict.obj `if test -f '3Depict.cpp'; then $(CYGPATH_W) '3Depict.cpp'; else $(CYGPATH_W) '$(srcdir)/3Depict.cpp'; fi` -3Depict-eventlogger.o: eventlogger.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-eventlogger.o -MD -MP -MF $(DEPDIR)/3Depict-eventlogger.Tpo -c -o 3Depict-eventlogger.o `test -f 'eventlogger.cpp' || echo '$(srcdir)/'`eventlogger.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-eventlogger.Tpo $(DEPDIR)/3Depict-eventlogger.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='eventlogger.cpp' object='3Depict-eventlogger.o' libtool=no @AMDEPBACKSLASH@ +3Depict-testing.o: testing.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-testing.o -MD -MP -MF $(DEPDIR)/3Depict-testing.Tpo -c -o 3Depict-testing.o `test -f 'testing.cpp' || echo '$(srcdir)/'`testing.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-testing.Tpo $(DEPDIR)/3Depict-testing.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testing.cpp' object='3Depict-testing.o' libtool=no @AMDEPBACKSLASH@ @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-eventlogger.o `test -f 'eventlogger.cpp' || echo '$(srcdir)/'`eventlogger.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-testing.o `test -f 'testing.cpp' || echo '$(srcdir)/'`testing.cpp -3Depict-eventlogger.obj: eventlogger.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-eventlogger.obj -MD -MP -MF $(DEPDIR)/3Depict-eventlogger.Tpo -c -o 3Depict-eventlogger.obj `if test -f 'eventlogger.cpp'; then $(CYGPATH_W) 'eventlogger.cpp'; else $(CYGPATH_W) '$(srcdir)/eventlogger.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-eventlogger.Tpo $(DEPDIR)/3Depict-eventlogger.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='eventlogger.cpp' object='3Depict-eventlogger.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-testing.obj: testing.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-testing.obj -MD -MP -MF $(DEPDIR)/3Depict-testing.Tpo -c -o 3Depict-testing.obj `if test -f 'testing.cpp'; then $(CYGPATH_W) 'testing.cpp'; else $(CYGPATH_W) '$(srcdir)/testing.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-testing.Tpo $(DEPDIR)/3Depict-testing.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testing.cpp' object='3Depict-testing.obj' libtool=no @AMDEPBACKSLASH@ @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-eventlogger.obj `if test -f 'eventlogger.cpp'; then $(CYGPATH_W) 'eventlogger.cpp'; else $(CYGPATH_W) '$(srcdir)/eventlogger.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-testing.obj `if test -f 'testing.cpp'; then $(CYGPATH_W) 'testing.cpp'; else $(CYGPATH_W) '$(srcdir)/testing.cpp'; fi` -3Depict-filtertreeAnalyse.o: filtertreeAnalyse.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertreeAnalyse.o -MD -MP -MF $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo -c -o 3Depict-filtertreeAnalyse.o `test -f 'filtertreeAnalyse.cpp' || echo '$(srcdir)/'`filtertreeAnalyse.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo $(DEPDIR)/3Depict-filtertreeAnalyse.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filtertreeAnalyse.cpp' object='3Depict-filtertreeAnalyse.o' libtool=no @AMDEPBACKSLASH@ +3Depict-wxcomponents.o: wxcomponents.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcomponents.o -MD -MP -MF $(DEPDIR)/3Depict-wxcomponents.Tpo -c -o 3Depict-wxcomponents.o `test -f 'wxcomponents.cpp' || echo '$(srcdir)/'`wxcomponents.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcomponents.Tpo $(DEPDIR)/3Depict-wxcomponents.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcomponents.cpp' object='3Depict-wxcomponents.o' libtool=no @AMDEPBACKSLASH@ @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-filtertreeAnalyse.o `test -f 'filtertreeAnalyse.cpp' || echo '$(srcdir)/'`filtertreeAnalyse.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-wxcomponents.o `test -f 'wxcomponents.cpp' || echo '$(srcdir)/'`wxcomponents.cpp -3Depict-filtertreeAnalyse.obj: filtertreeAnalyse.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertreeAnalyse.obj -MD -MP -MF $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo -c -o 3Depict-filtertreeAnalyse.obj `if test -f 'filtertreeAnalyse.cpp'; then $(CYGPATH_W) 'filtertreeAnalyse.cpp'; else $(CYGPATH_W) '$(srcdir)/filtertreeAnalyse.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo $(DEPDIR)/3Depict-filtertreeAnalyse.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filtertreeAnalyse.cpp' object='3Depict-filtertreeAnalyse.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-wxcomponents.obj: wxcomponents.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcomponents.obj -MD -MP -MF $(DEPDIR)/3Depict-wxcomponents.Tpo -c -o 3Depict-wxcomponents.obj `if test -f 'wxcomponents.cpp'; then $(CYGPATH_W) 'wxcomponents.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcomponents.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcomponents.Tpo $(DEPDIR)/3Depict-wxcomponents.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcomponents.cpp' object='3Depict-wxcomponents.obj' libtool=no @AMDEPBACKSLASH@ @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-filtertreeAnalyse.obj `if test -f 'filtertreeAnalyse.cpp'; then $(CYGPATH_W) 'filtertreeAnalyse.cpp'; else $(CYGPATH_W) '$(srcdir)/filtertreeAnalyse.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-wxcomponents.obj `if test -f 'wxcomponents.cpp'; then $(CYGPATH_W) 'wxcomponents.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcomponents.cpp'; fi` -3Depict-filtertree.o: filtertree.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertree.o -MD -MP -MF $(DEPDIR)/3Depict-filtertree.Tpo -c -o 3Depict-filtertree.o `test -f 'filtertree.cpp' || echo '$(srcdir)/'`filtertree.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertree.Tpo $(DEPDIR)/3Depict-filtertree.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filtertree.cpp' object='3Depict-filtertree.o' libtool=no @AMDEPBACKSLASH@ +3Depict-wxcommon.o: wxcommon.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcommon.o -MD -MP -MF $(DEPDIR)/3Depict-wxcommon.Tpo -c -o 3Depict-wxcommon.o `test -f 'wxcommon.cpp' || echo '$(srcdir)/'`wxcommon.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcommon.Tpo $(DEPDIR)/3Depict-wxcommon.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcommon.cpp' object='3Depict-wxcommon.o' libtool=no @AMDEPBACKSLASH@ @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.o `test -f 'filtertree.cpp' || echo '$(srcdir)/'`filtertree.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-wxcommon.o `test -f 'wxcommon.cpp' || echo '$(srcdir)/'`wxcommon.cpp -3Depict-filtertree.obj: filtertree.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertree.obj -MD -MP -MF $(DEPDIR)/3Depict-filtertree.Tpo -c -o 3Depict-filtertree.obj `if test -f 'filtertree.cpp'; then $(CYGPATH_W) 'filtertree.cpp'; else $(CYGPATH_W) '$(srcdir)/filtertree.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertree.Tpo $(DEPDIR)/3Depict-filtertree.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filtertree.cpp' object='3Depict-filtertree.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-wxcommon.obj: wxcommon.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcommon.obj -MD -MP -MF $(DEPDIR)/3Depict-wxcommon.Tpo -c -o 3Depict-wxcommon.obj `if test -f 'wxcommon.cpp'; then $(CYGPATH_W) 'wxcommon.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcommon.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcommon.Tpo $(DEPDIR)/3Depict-wxcommon.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcommon.cpp' object='3Depict-wxcommon.obj' libtool=no @AMDEPBACKSLASH@ +@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-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 +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/mainFrame.cpp' object='3Depict-mainFrame.o' libtool=no @AMDEPBACKSLASH@ +@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-mainFrame.o `test -f 'gui/mainFrame.cpp' || echo '$(srcdir)/'`gui/mainFrame.cpp + +3Depict-mainFrame.obj: gui/mainFrame.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mainFrame.obj -MD -MP -MF $(DEPDIR)/3Depict-mainFrame.Tpo -c -o 3Depict-mainFrame.obj `if test -f 'gui/mainFrame.cpp'; then $(CYGPATH_W) 'gui/mainFrame.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/mainFrame.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mainFrame.Tpo $(DEPDIR)/3Depict-mainFrame.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/mainFrame.cpp' object='3Depict-mainFrame.obj' libtool=no @AMDEPBACKSLASH@ @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 'filtertree.cpp'; then $(CYGPATH_W) 'filtertree.cpp'; else $(CYGPATH_W) '$(srcdir)/filtertree.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-mainFrame.obj `if test -f 'gui/mainFrame.cpp'; then $(CYGPATH_W) 'gui/mainFrame.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/mainFrame.cpp'; fi` -3Depict-mathglPane.o: mathglPane.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathglPane.o -MD -MP -MF $(DEPDIR)/3Depict-mathglPane.Tpo -c -o 3Depict-mathglPane.o `test -f 'mathglPane.cpp' || echo '$(srcdir)/'`mathglPane.cpp +3Depict-mathglPane.o: gui/mathglPane.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathglPane.o -MD -MP -MF $(DEPDIR)/3Depict-mathglPane.Tpo -c -o 3Depict-mathglPane.o `test -f 'gui/mathglPane.cpp' || echo '$(srcdir)/'`gui/mathglPane.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mathglPane.Tpo $(DEPDIR)/3Depict-mathglPane.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mathglPane.cpp' object='3Depict-mathglPane.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/mathglPane.cpp' object='3Depict-mathglPane.o' libtool=no @AMDEPBACKSLASH@ @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-mathglPane.o `test -f 'mathglPane.cpp' || echo '$(srcdir)/'`mathglPane.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-mathglPane.o `test -f 'gui/mathglPane.cpp' || echo '$(srcdir)/'`gui/mathglPane.cpp -3Depict-mathglPane.obj: mathglPane.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathglPane.obj -MD -MP -MF $(DEPDIR)/3Depict-mathglPane.Tpo -c -o 3Depict-mathglPane.obj `if test -f 'mathglPane.cpp'; then $(CYGPATH_W) 'mathglPane.cpp'; else $(CYGPATH_W) '$(srcdir)/mathglPane.cpp'; fi` +3Depict-mathglPane.obj: gui/mathglPane.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathglPane.obj -MD -MP -MF $(DEPDIR)/3Depict-mathglPane.Tpo -c -o 3Depict-mathglPane.obj `if test -f 'gui/mathglPane.cpp'; then $(CYGPATH_W) 'gui/mathglPane.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/mathglPane.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mathglPane.Tpo $(DEPDIR)/3Depict-mathglPane.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mathglPane.cpp' object='3Depict-mathglPane.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/mathglPane.cpp' object='3Depict-mathglPane.obj' libtool=no @AMDEPBACKSLASH@ @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-mathglPane.obj `if test -f 'mathglPane.cpp'; then $(CYGPATH_W) 'mathglPane.cpp'; else $(CYGPATH_W) '$(srcdir)/mathglPane.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-mathglPane.obj `if test -f 'gui/mathglPane.cpp'; then $(CYGPATH_W) 'gui/mathglPane.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/mathglPane.cpp'; fi` -3Depict-plot.o: 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 'plot.cpp' || echo '$(srcdir)/'`plot.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-plot.Tpo $(DEPDIR)/3Depict-plot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='plot.cpp' object='3Depict-plot.o' libtool=no @AMDEPBACKSLASH@ +3Depict-cropPanel.o: gui/cropPanel.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cropPanel.o -MD -MP -MF $(DEPDIR)/3Depict-cropPanel.Tpo -c -o 3Depict-cropPanel.o `test -f 'gui/cropPanel.cpp' || echo '$(srcdir)/'`gui/cropPanel.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cropPanel.Tpo $(DEPDIR)/3Depict-cropPanel.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/cropPanel.cpp' object='3Depict-cropPanel.o' libtool=no @AMDEPBACKSLASH@ @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-plot.o `test -f 'plot.cpp' || echo '$(srcdir)/'`plot.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-cropPanel.o `test -f 'gui/cropPanel.cpp' || echo '$(srcdir)/'`gui/cropPanel.cpp -3Depict-plot.obj: plot.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-plot.obj -MD -MP -MF $(DEPDIR)/3Depict-plot.Tpo -c -o 3Depict-plot.obj `if test -f 'plot.cpp'; then $(CYGPATH_W) 'plot.cpp'; else $(CYGPATH_W) '$(srcdir)/plot.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-plot.Tpo $(DEPDIR)/3Depict-plot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='plot.cpp' object='3Depict-plot.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-cropPanel.obj: gui/cropPanel.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cropPanel.obj -MD -MP -MF $(DEPDIR)/3Depict-cropPanel.Tpo -c -o 3Depict-cropPanel.obj `if test -f 'gui/cropPanel.cpp'; then $(CYGPATH_W) 'gui/cropPanel.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/cropPanel.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cropPanel.Tpo $(DEPDIR)/3Depict-cropPanel.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/cropPanel.cpp' object='3Depict-cropPanel.obj' libtool=no @AMDEPBACKSLASH@ @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-plot.obj `if test -f 'plot.cpp'; then $(CYGPATH_W) 'plot.cpp'; else $(CYGPATH_W) '$(srcdir)/plot.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-cropPanel.obj `if test -f 'gui/cropPanel.cpp'; then $(CYGPATH_W) 'gui/cropPanel.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/cropPanel.cpp'; fi` -3Depict-configFile.o: configFile.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-configFile.o -MD -MP -MF $(DEPDIR)/3Depict-configFile.Tpo -c -o 3Depict-configFile.o `test -f 'configFile.cpp' || echo '$(srcdir)/'`configFile.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-configFile.Tpo $(DEPDIR)/3Depict-configFile.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='configFile.cpp' object='3Depict-configFile.o' libtool=no @AMDEPBACKSLASH@ +3Depict-glPane.o: gui/glPane.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-glPane.o -MD -MP -MF $(DEPDIR)/3Depict-glPane.Tpo -c -o 3Depict-glPane.o `test -f 'gui/glPane.cpp' || echo '$(srcdir)/'`gui/glPane.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-glPane.Tpo $(DEPDIR)/3Depict-glPane.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/glPane.cpp' object='3Depict-glPane.o' libtool=no @AMDEPBACKSLASH@ @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-configFile.o `test -f 'configFile.cpp' || echo '$(srcdir)/'`configFile.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-glPane.o `test -f 'gui/glPane.cpp' || echo '$(srcdir)/'`gui/glPane.cpp -3Depict-configFile.obj: configFile.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-configFile.obj -MD -MP -MF $(DEPDIR)/3Depict-configFile.Tpo -c -o 3Depict-configFile.obj `if test -f 'configFile.cpp'; then $(CYGPATH_W) 'configFile.cpp'; else $(CYGPATH_W) '$(srcdir)/configFile.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-configFile.Tpo $(DEPDIR)/3Depict-configFile.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='configFile.cpp' object='3Depict-configFile.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-glPane.obj: gui/glPane.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-glPane.obj -MD -MP -MF $(DEPDIR)/3Depict-glPane.Tpo -c -o 3Depict-glPane.obj `if test -f 'gui/glPane.cpp'; then $(CYGPATH_W) 'gui/glPane.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/glPane.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-glPane.Tpo $(DEPDIR)/3Depict-glPane.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/glPane.cpp' object='3Depict-glPane.obj' libtool=no @AMDEPBACKSLASH@ @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-configFile.obj `if test -f 'configFile.cpp'; then $(CYGPATH_W) 'configFile.cpp'; else $(CYGPATH_W) '$(srcdir)/configFile.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-glPane.obj `if test -f 'gui/glPane.cpp'; then $(CYGPATH_W) 'gui/glPane.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/glPane.cpp'; fi` -3Depict-filter.o: filter.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filter.o -MD -MP -MF $(DEPDIR)/3Depict-filter.Tpo -c -o 3Depict-filter.o `test -f 'filter.cpp' || echo '$(srcdir)/'`filter.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filter.Tpo $(DEPDIR)/3Depict-filter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filter.cpp' object='3Depict-filter.o' libtool=no @AMDEPBACKSLASH@ +3Depict-ExportPos.o: gui/dialogs/ExportPos.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportPos.o -MD -MP -MF $(DEPDIR)/3Depict-ExportPos.Tpo -c -o 3Depict-ExportPos.o `test -f 'gui/dialogs/ExportPos.cpp' || echo '$(srcdir)/'`gui/dialogs/ExportPos.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportPos.Tpo $(DEPDIR)/3Depict-ExportPos.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/ExportPos.cpp' object='3Depict-ExportPos.o' libtool=no @AMDEPBACKSLASH@ @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-filter.o `test -f 'filter.cpp' || echo '$(srcdir)/'`filter.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ExportPos.o `test -f 'gui/dialogs/ExportPos.cpp' || echo '$(srcdir)/'`gui/dialogs/ExportPos.cpp -3Depict-filter.obj: filter.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filter.obj -MD -MP -MF $(DEPDIR)/3Depict-filter.Tpo -c -o 3Depict-filter.obj `if test -f 'filter.cpp'; then $(CYGPATH_W) 'filter.cpp'; else $(CYGPATH_W) '$(srcdir)/filter.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filter.Tpo $(DEPDIR)/3Depict-filter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filter.cpp' object='3Depict-filter.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-ExportPos.obj: gui/dialogs/ExportPos.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportPos.obj -MD -MP -MF $(DEPDIR)/3Depict-ExportPos.Tpo -c -o 3Depict-ExportPos.obj `if test -f 'gui/dialogs/ExportPos.cpp'; then $(CYGPATH_W) 'gui/dialogs/ExportPos.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/ExportPos.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportPos.Tpo $(DEPDIR)/3Depict-ExportPos.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/ExportPos.cpp' object='3Depict-ExportPos.obj' libtool=no @AMDEPBACKSLASH@ @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-filter.obj `if test -f 'filter.cpp'; then $(CYGPATH_W) 'filter.cpp'; else $(CYGPATH_W) '$(srcdir)/filter.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ExportPos.obj `if test -f 'gui/dialogs/ExportPos.cpp'; then $(CYGPATH_W) 'gui/dialogs/ExportPos.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/ExportPos.cpp'; fi` -3Depict-APTClasses.o: APTClasses.cpp -@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 'APTClasses.cpp' || echo '$(srcdir)/'`APTClasses.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-APTClasses.Tpo $(DEPDIR)/3Depict-APTClasses.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='APTClasses.cpp' object='3Depict-APTClasses.o' libtool=no @AMDEPBACKSLASH@ +3Depict-ExportRngDialog.o: gui/dialogs/ExportRngDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportRngDialog.o -MD -MP -MF $(DEPDIR)/3Depict-ExportRngDialog.Tpo -c -o 3Depict-ExportRngDialog.o `test -f 'gui/dialogs/ExportRngDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/ExportRngDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportRngDialog.Tpo $(DEPDIR)/3Depict-ExportRngDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/ExportRngDialog.cpp' object='3Depict-ExportRngDialog.o' libtool=no @AMDEPBACKSLASH@ @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-APTClasses.o `test -f 'APTClasses.cpp' || echo '$(srcdir)/'`APTClasses.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ExportRngDialog.o `test -f 'gui/dialogs/ExportRngDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/ExportRngDialog.cpp -3Depict-APTClasses.obj: APTClasses.cpp -@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 'APTClasses.cpp'; then $(CYGPATH_W) 'APTClasses.cpp'; else $(CYGPATH_W) '$(srcdir)/APTClasses.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-APTClasses.Tpo $(DEPDIR)/3Depict-APTClasses.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='APTClasses.cpp' object='3Depict-APTClasses.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-ExportRngDialog.obj: gui/dialogs/ExportRngDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportRngDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-ExportRngDialog.Tpo -c -o 3Depict-ExportRngDialog.obj `if test -f 'gui/dialogs/ExportRngDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/ExportRngDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/ExportRngDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportRngDialog.Tpo $(DEPDIR)/3Depict-ExportRngDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/ExportRngDialog.cpp' object='3Depict-ExportRngDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-APTClasses.obj `if test -f 'APTClasses.cpp'; then $(CYGPATH_W) 'APTClasses.cpp'; else $(CYGPATH_W) '$(srcdir)/APTClasses.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ExportRngDialog.obj `if test -f 'gui/dialogs/ExportRngDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/ExportRngDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/ExportRngDialog.cpp'; fi` -3Depict-select.o: select.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-select.o -MD -MP -MF $(DEPDIR)/3Depict-select.Tpo -c -o 3Depict-select.o `test -f 'select.cpp' || echo '$(srcdir)/'`select.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-select.Tpo $(DEPDIR)/3Depict-select.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='select.cpp' object='3Depict-select.o' libtool=no @AMDEPBACKSLASH@ +3Depict-prefDialog.o: gui/dialogs/prefDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-prefDialog.o -MD -MP -MF $(DEPDIR)/3Depict-prefDialog.Tpo -c -o 3Depict-prefDialog.o `test -f 'gui/dialogs/prefDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/prefDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-prefDialog.Tpo $(DEPDIR)/3Depict-prefDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/prefDialog.cpp' object='3Depict-prefDialog.o' libtool=no @AMDEPBACKSLASH@ @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-select.o `test -f 'select.cpp' || echo '$(srcdir)/'`select.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-prefDialog.o `test -f 'gui/dialogs/prefDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/prefDialog.cpp -3Depict-select.obj: select.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-select.obj -MD -MP -MF $(DEPDIR)/3Depict-select.Tpo -c -o 3Depict-select.obj `if test -f 'select.cpp'; then $(CYGPATH_W) 'select.cpp'; else $(CYGPATH_W) '$(srcdir)/select.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-select.Tpo $(DEPDIR)/3Depict-select.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='select.cpp' object='3Depict-select.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-prefDialog.obj: gui/dialogs/prefDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-prefDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-prefDialog.Tpo -c -o 3Depict-prefDialog.obj `if test -f 'gui/dialogs/prefDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/prefDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/prefDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-prefDialog.Tpo $(DEPDIR)/3Depict-prefDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/prefDialog.cpp' object='3Depict-prefDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-select.obj `if test -f 'select.cpp'; then $(CYGPATH_W) 'select.cpp'; else $(CYGPATH_W) '$(srcdir)/select.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-prefDialog.obj `if test -f 'gui/dialogs/prefDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/prefDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/prefDialog.cpp'; fi` -3Depict-drawables.o: drawables.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-drawables.o -MD -MP -MF $(DEPDIR)/3Depict-drawables.Tpo -c -o 3Depict-drawables.o `test -f 'drawables.cpp' || echo '$(srcdir)/'`drawables.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-drawables.Tpo $(DEPDIR)/3Depict-drawables.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='drawables.cpp' object='3Depict-drawables.o' libtool=no @AMDEPBACKSLASH@ +3Depict-resolutionDialog.o: gui/dialogs/resolutionDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-resolutionDialog.o -MD -MP -MF $(DEPDIR)/3Depict-resolutionDialog.Tpo -c -o 3Depict-resolutionDialog.o `test -f 'gui/dialogs/resolutionDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/resolutionDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-resolutionDialog.Tpo $(DEPDIR)/3Depict-resolutionDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/resolutionDialog.cpp' object='3Depict-resolutionDialog.o' libtool=no @AMDEPBACKSLASH@ @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-drawables.o `test -f 'drawables.cpp' || echo '$(srcdir)/'`drawables.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-resolutionDialog.o `test -f 'gui/dialogs/resolutionDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/resolutionDialog.cpp -3Depict-drawables.obj: drawables.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-drawables.obj -MD -MP -MF $(DEPDIR)/3Depict-drawables.Tpo -c -o 3Depict-drawables.obj `if test -f 'drawables.cpp'; then $(CYGPATH_W) 'drawables.cpp'; else $(CYGPATH_W) '$(srcdir)/drawables.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-drawables.Tpo $(DEPDIR)/3Depict-drawables.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='drawables.cpp' object='3Depict-drawables.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-resolutionDialog.obj: gui/dialogs/resolutionDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-resolutionDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-resolutionDialog.Tpo -c -o 3Depict-resolutionDialog.obj `if test -f 'gui/dialogs/resolutionDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/resolutionDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/resolutionDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-resolutionDialog.Tpo $(DEPDIR)/3Depict-resolutionDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/resolutionDialog.cpp' object='3Depict-resolutionDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-drawables.obj `if test -f 'drawables.cpp'; then $(CYGPATH_W) 'drawables.cpp'; else $(CYGPATH_W) '$(srcdir)/drawables.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-resolutionDialog.obj `if test -f 'gui/dialogs/resolutionDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/resolutionDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/resolutionDialog.cpp'; fi` -3Depict-effect.o: effect.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-effect.o -MD -MP -MF $(DEPDIR)/3Depict-effect.Tpo -c -o 3Depict-effect.o `test -f 'effect.cpp' || echo '$(srcdir)/'`effect.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-effect.Tpo $(DEPDIR)/3Depict-effect.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='effect.cpp' object='3Depict-effect.o' libtool=no @AMDEPBACKSLASH@ +3Depict-StashDialog.o: gui/dialogs/StashDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-StashDialog.o -MD -MP -MF $(DEPDIR)/3Depict-StashDialog.Tpo -c -o 3Depict-StashDialog.o `test -f 'gui/dialogs/StashDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/StashDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-StashDialog.Tpo $(DEPDIR)/3Depict-StashDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/StashDialog.cpp' object='3Depict-StashDialog.o' libtool=no @AMDEPBACKSLASH@ @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-effect.o `test -f 'effect.cpp' || echo '$(srcdir)/'`effect.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-StashDialog.o `test -f 'gui/dialogs/StashDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/StashDialog.cpp -3Depict-effect.obj: effect.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-effect.obj -MD -MP -MF $(DEPDIR)/3Depict-effect.Tpo -c -o 3Depict-effect.obj `if test -f 'effect.cpp'; then $(CYGPATH_W) 'effect.cpp'; else $(CYGPATH_W) '$(srcdir)/effect.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-effect.Tpo $(DEPDIR)/3Depict-effect.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='effect.cpp' object='3Depict-effect.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-StashDialog.obj: gui/dialogs/StashDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-StashDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-StashDialog.Tpo -c -o 3Depict-StashDialog.obj `if test -f 'gui/dialogs/StashDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/StashDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/StashDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-StashDialog.Tpo $(DEPDIR)/3Depict-StashDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/StashDialog.cpp' object='3Depict-StashDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-effect.obj `if test -f 'effect.cpp'; then $(CYGPATH_W) 'effect.cpp'; else $(CYGPATH_W) '$(srcdir)/effect.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-StashDialog.obj `if test -f 'gui/dialogs/StashDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/StashDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/StashDialog.cpp'; fi` -3Depict-textures.o: textures.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-textures.o -MD -MP -MF $(DEPDIR)/3Depict-textures.Tpo -c -o 3Depict-textures.o `test -f 'textures.cpp' || echo '$(srcdir)/'`textures.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-textures.Tpo $(DEPDIR)/3Depict-textures.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='textures.cpp' object='3Depict-textures.o' libtool=no @AMDEPBACKSLASH@ +3Depict-autosaveDialog.o: gui/dialogs/autosaveDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-autosaveDialog.o -MD -MP -MF $(DEPDIR)/3Depict-autosaveDialog.Tpo -c -o 3Depict-autosaveDialog.o `test -f 'gui/dialogs/autosaveDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/autosaveDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-autosaveDialog.Tpo $(DEPDIR)/3Depict-autosaveDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/autosaveDialog.cpp' object='3Depict-autosaveDialog.o' libtool=no @AMDEPBACKSLASH@ @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-textures.o `test -f 'textures.cpp' || echo '$(srcdir)/'`textures.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-autosaveDialog.o `test -f 'gui/dialogs/autosaveDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/autosaveDialog.cpp -3Depict-textures.obj: textures.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-textures.obj -MD -MP -MF $(DEPDIR)/3Depict-textures.Tpo -c -o 3Depict-textures.obj `if test -f 'textures.cpp'; then $(CYGPATH_W) 'textures.cpp'; else $(CYGPATH_W) '$(srcdir)/textures.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-textures.Tpo $(DEPDIR)/3Depict-textures.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='textures.cpp' object='3Depict-textures.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-autosaveDialog.obj: gui/dialogs/autosaveDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-autosaveDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-autosaveDialog.Tpo -c -o 3Depict-autosaveDialog.obj `if test -f 'gui/dialogs/autosaveDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/autosaveDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/autosaveDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-autosaveDialog.Tpo $(DEPDIR)/3Depict-autosaveDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/autosaveDialog.cpp' object='3Depict-autosaveDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-textures.obj `if test -f 'textures.cpp'; then $(CYGPATH_W) 'textures.cpp'; else $(CYGPATH_W) '$(srcdir)/textures.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-autosaveDialog.obj `if test -f 'gui/dialogs/autosaveDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/autosaveDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/autosaveDialog.cpp'; fi` -3Depict-rdf.o: rdf.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rdf.o -MD -MP -MF $(DEPDIR)/3Depict-rdf.Tpo -c -o 3Depict-rdf.o `test -f 'rdf.cpp' || echo '$(srcdir)/'`rdf.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rdf.Tpo $(DEPDIR)/3Depict-rdf.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='rdf.cpp' object='3Depict-rdf.o' libtool=no @AMDEPBACKSLASH@ +3Depict-filterErrorDialog.o: gui/dialogs/filterErrorDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filterErrorDialog.o -MD -MP -MF $(DEPDIR)/3Depict-filterErrorDialog.Tpo -c -o 3Depict-filterErrorDialog.o `test -f 'gui/dialogs/filterErrorDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/filterErrorDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filterErrorDialog.Tpo $(DEPDIR)/3Depict-filterErrorDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/filterErrorDialog.cpp' object='3Depict-filterErrorDialog.o' libtool=no @AMDEPBACKSLASH@ @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-rdf.o `test -f 'rdf.cpp' || echo '$(srcdir)/'`rdf.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filterErrorDialog.o `test -f 'gui/dialogs/filterErrorDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/filterErrorDialog.cpp -3Depict-rdf.obj: rdf.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rdf.obj -MD -MP -MF $(DEPDIR)/3Depict-rdf.Tpo -c -o 3Depict-rdf.obj `if test -f 'rdf.cpp'; then $(CYGPATH_W) 'rdf.cpp'; else $(CYGPATH_W) '$(srcdir)/rdf.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rdf.Tpo $(DEPDIR)/3Depict-rdf.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='rdf.cpp' object='3Depict-rdf.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-filterErrorDialog.obj: gui/dialogs/filterErrorDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filterErrorDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-filterErrorDialog.Tpo -c -o 3Depict-filterErrorDialog.obj `if test -f 'gui/dialogs/filterErrorDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/filterErrorDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/filterErrorDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filterErrorDialog.Tpo $(DEPDIR)/3Depict-filterErrorDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/filterErrorDialog.cpp' object='3Depict-filterErrorDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-rdf.obj `if test -f 'rdf.cpp'; then $(CYGPATH_W) 'rdf.cpp'; else $(CYGPATH_W) '$(srcdir)/rdf.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filterErrorDialog.obj `if test -f 'gui/dialogs/filterErrorDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/filterErrorDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/filterErrorDialog.cpp'; fi` -3Depict-cameras.o: cameras.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cameras.o -MD -MP -MF $(DEPDIR)/3Depict-cameras.Tpo -c -o 3Depict-cameras.o `test -f 'cameras.cpp' || echo '$(srcdir)/'`cameras.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cameras.Tpo $(DEPDIR)/3Depict-cameras.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cameras.cpp' object='3Depict-cameras.o' libtool=no @AMDEPBACKSLASH@ +3Depict-animateFilterDialog.o: gui/dialogs/animateFilterDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animateFilterDialog.o -MD -MP -MF $(DEPDIR)/3Depict-animateFilterDialog.Tpo -c -o 3Depict-animateFilterDialog.o `test -f 'gui/dialogs/animateFilterDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateFilterDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animateFilterDialog.Tpo $(DEPDIR)/3Depict-animateFilterDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateFilterDialog.cpp' object='3Depict-animateFilterDialog.o' libtool=no @AMDEPBACKSLASH@ @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-cameras.o `test -f 'cameras.cpp' || echo '$(srcdir)/'`cameras.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-animateFilterDialog.o `test -f 'gui/dialogs/animateFilterDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateFilterDialog.cpp -3Depict-cameras.obj: cameras.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cameras.obj -MD -MP -MF $(DEPDIR)/3Depict-cameras.Tpo -c -o 3Depict-cameras.obj `if test -f 'cameras.cpp'; then $(CYGPATH_W) 'cameras.cpp'; else $(CYGPATH_W) '$(srcdir)/cameras.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cameras.Tpo $(DEPDIR)/3Depict-cameras.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cameras.cpp' object='3Depict-cameras.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-animateFilterDialog.obj: gui/dialogs/animateFilterDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animateFilterDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-animateFilterDialog.Tpo -c -o 3Depict-animateFilterDialog.obj `if test -f 'gui/dialogs/animateFilterDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateFilterDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateFilterDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animateFilterDialog.Tpo $(DEPDIR)/3Depict-animateFilterDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateFilterDialog.cpp' object='3Depict-animateFilterDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-cameras.obj `if test -f 'cameras.cpp'; then $(CYGPATH_W) 'cameras.cpp'; else $(CYGPATH_W) '$(srcdir)/cameras.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-animateFilterDialog.obj `if test -f 'gui/dialogs/animateFilterDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateFilterDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateFilterDialog.cpp'; fi` -3Depict-isoSurface.o: isoSurface.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-isoSurface.o -MD -MP -MF $(DEPDIR)/3Depict-isoSurface.Tpo -c -o 3Depict-isoSurface.o `test -f 'isoSurface.cpp' || echo '$(srcdir)/'`isoSurface.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-isoSurface.Tpo $(DEPDIR)/3Depict-isoSurface.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='isoSurface.cpp' object='3Depict-isoSurface.o' libtool=no @AMDEPBACKSLASH@ +3Depict-colourKeyFrameDialog.o: gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourKeyFrameDialog.o -MD -MP -MF $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo -c -o 3Depict-colourKeyFrameDialog.o `test -f 'gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo $(DEPDIR)/3Depict-colourKeyFrameDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' object='3Depict-colourKeyFrameDialog.o' libtool=no @AMDEPBACKSLASH@ @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-isoSurface.o `test -f 'isoSurface.cpp' || echo '$(srcdir)/'`isoSurface.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-colourKeyFrameDialog.o `test -f 'gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp -3Depict-isoSurface.obj: isoSurface.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-isoSurface.obj -MD -MP -MF $(DEPDIR)/3Depict-isoSurface.Tpo -c -o 3Depict-isoSurface.obj `if test -f 'isoSurface.cpp'; then $(CYGPATH_W) 'isoSurface.cpp'; else $(CYGPATH_W) '$(srcdir)/isoSurface.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-isoSurface.Tpo $(DEPDIR)/3Depict-isoSurface.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='isoSurface.cpp' object='3Depict-isoSurface.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-colourKeyFrameDialog.obj: gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourKeyFrameDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo -c -o 3Depict-colourKeyFrameDialog.obj `if test -f 'gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo $(DEPDIR)/3Depict-colourKeyFrameDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' object='3Depict-colourKeyFrameDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-isoSurface.obj `if test -f 'isoSurface.cpp'; then $(CYGPATH_W) 'isoSurface.cpp'; else $(CYGPATH_W) '$(srcdir)/isoSurface.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-colourKeyFrameDialog.obj `if test -f 'gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; fi` -3Depict-K3DTree.o: K3DTree.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree.o -MD -MP -MF $(DEPDIR)/3Depict-K3DTree.Tpo -c -o 3Depict-K3DTree.o `test -f 'K3DTree.cpp' || echo '$(srcdir)/'`K3DTree.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree.Tpo $(DEPDIR)/3Depict-K3DTree.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='K3DTree.cpp' object='3Depict-K3DTree.o' libtool=no @AMDEPBACKSLASH@ +3Depict-stringKeyFrameDialog.o: gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-stringKeyFrameDialog.o -MD -MP -MF $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo -c -o 3Depict-stringKeyFrameDialog.o `test -f 'gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo $(DEPDIR)/3Depict-stringKeyFrameDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' object='3Depict-stringKeyFrameDialog.o' libtool=no @AMDEPBACKSLASH@ @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-K3DTree.o `test -f 'K3DTree.cpp' || echo '$(srcdir)/'`K3DTree.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-stringKeyFrameDialog.o `test -f 'gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp -3Depict-K3DTree.obj: K3DTree.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree.obj -MD -MP -MF $(DEPDIR)/3Depict-K3DTree.Tpo -c -o 3Depict-K3DTree.obj `if test -f 'K3DTree.cpp'; then $(CYGPATH_W) 'K3DTree.cpp'; else $(CYGPATH_W) '$(srcdir)/K3DTree.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree.Tpo $(DEPDIR)/3Depict-K3DTree.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='K3DTree.cpp' object='3Depict-K3DTree.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-stringKeyFrameDialog.obj: gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-stringKeyFrameDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo -c -o 3Depict-stringKeyFrameDialog.obj `if test -f 'gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo $(DEPDIR)/3Depict-stringKeyFrameDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' object='3Depict-stringKeyFrameDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-K3DTree.obj `if test -f 'K3DTree.cpp'; then $(CYGPATH_W) 'K3DTree.cpp'; else $(CYGPATH_W) '$(srcdir)/K3DTree.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-stringKeyFrameDialog.obj `if test -f 'gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; fi` -3Depict-K3DTree-mk2.o: K3DTree-mk2.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree-mk2.o -MD -MP -MF $(DEPDIR)/3Depict-K3DTree-mk2.Tpo -c -o 3Depict-K3DTree-mk2.o `test -f 'K3DTree-mk2.cpp' || echo '$(srcdir)/'`K3DTree-mk2.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree-mk2.Tpo $(DEPDIR)/3Depict-K3DTree-mk2.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='K3DTree-mk2.cpp' object='3Depict-K3DTree-mk2.o' libtool=no @AMDEPBACKSLASH@ +3Depict-choiceKeyFrameDialog.o: gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-choiceKeyFrameDialog.o -MD -MP -MF $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo -c -o 3Depict-choiceKeyFrameDialog.o `test -f 'gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo $(DEPDIR)/3Depict-choiceKeyFrameDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' object='3Depict-choiceKeyFrameDialog.o' libtool=no @AMDEPBACKSLASH@ @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-K3DTree-mk2.o `test -f 'K3DTree-mk2.cpp' || echo '$(srcdir)/'`K3DTree-mk2.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-choiceKeyFrameDialog.o `test -f 'gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' || echo '$(srcdir)/'`gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp -3Depict-K3DTree-mk2.obj: K3DTree-mk2.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree-mk2.obj -MD -MP -MF $(DEPDIR)/3Depict-K3DTree-mk2.Tpo -c -o 3Depict-K3DTree-mk2.obj `if test -f 'K3DTree-mk2.cpp'; then $(CYGPATH_W) 'K3DTree-mk2.cpp'; else $(CYGPATH_W) '$(srcdir)/K3DTree-mk2.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree-mk2.Tpo $(DEPDIR)/3Depict-K3DTree-mk2.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='K3DTree-mk2.cpp' object='3Depict-K3DTree-mk2.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-choiceKeyFrameDialog.obj: gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-choiceKeyFrameDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo -c -o 3Depict-choiceKeyFrameDialog.obj `if test -f 'gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo $(DEPDIR)/3Depict-choiceKeyFrameDialog.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' object='3Depict-choiceKeyFrameDialog.obj' libtool=no @AMDEPBACKSLASH@ @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-K3DTree-mk2.obj `if test -f 'K3DTree-mk2.cpp'; then $(CYGPATH_W) 'K3DTree-mk2.cpp'; else $(CYGPATH_W) '$(srcdir)/K3DTree-mk2.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-choiceKeyFrameDialog.obj `if test -f 'gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; then $(CYGPATH_W) 'gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; fi` -3Depict-xmlHelper.o: xmlHelper.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-xmlHelper.o -MD -MP -MF $(DEPDIR)/3Depict-xmlHelper.Tpo -c -o 3Depict-xmlHelper.o `test -f 'xmlHelper.cpp' || echo '$(srcdir)/'`xmlHelper.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-xmlHelper.Tpo $(DEPDIR)/3Depict-xmlHelper.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='xmlHelper.cpp' object='3Depict-xmlHelper.o' libtool=no @AMDEPBACKSLASH@ +3Depict-allFilter.o: backend/filters/allFilter.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-allFilter.o -MD -MP -MF $(DEPDIR)/3Depict-allFilter.Tpo -c -o 3Depict-allFilter.o `test -f 'backend/filters/allFilter.cpp' || echo '$(srcdir)/'`backend/filters/allFilter.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-allFilter.Tpo $(DEPDIR)/3Depict-allFilter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/allFilter.cpp' object='3Depict-allFilter.o' libtool=no @AMDEPBACKSLASH@ @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-xmlHelper.o `test -f 'xmlHelper.cpp' || echo '$(srcdir)/'`xmlHelper.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-allFilter.o `test -f 'backend/filters/allFilter.cpp' || echo '$(srcdir)/'`backend/filters/allFilter.cpp -3Depict-xmlHelper.obj: xmlHelper.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-xmlHelper.obj -MD -MP -MF $(DEPDIR)/3Depict-xmlHelper.Tpo -c -o 3Depict-xmlHelper.obj `if test -f 'xmlHelper.cpp'; then $(CYGPATH_W) 'xmlHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/xmlHelper.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-xmlHelper.Tpo $(DEPDIR)/3Depict-xmlHelper.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='xmlHelper.cpp' object='3Depict-xmlHelper.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-allFilter.obj: backend/filters/allFilter.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-allFilter.obj -MD -MP -MF $(DEPDIR)/3Depict-allFilter.Tpo -c -o 3Depict-allFilter.obj `if test -f 'backend/filters/allFilter.cpp'; then $(CYGPATH_W) 'backend/filters/allFilter.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/allFilter.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-allFilter.Tpo $(DEPDIR)/3Depict-allFilter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/allFilter.cpp' object='3Depict-allFilter.obj' libtool=no @AMDEPBACKSLASH@ @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-xmlHelper.obj `if test -f 'xmlHelper.cpp'; then $(CYGPATH_W) 'xmlHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/xmlHelper.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-allFilter.obj `if test -f 'backend/filters/allFilter.cpp'; then $(CYGPATH_W) 'backend/filters/allFilter.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/allFilter.cpp'; fi` -3Depict-cropPanel.o: cropPanel.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cropPanel.o -MD -MP -MF $(DEPDIR)/3Depict-cropPanel.Tpo -c -o 3Depict-cropPanel.o `test -f 'cropPanel.cpp' || echo '$(srcdir)/'`cropPanel.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cropPanel.Tpo $(DEPDIR)/3Depict-cropPanel.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cropPanel.cpp' object='3Depict-cropPanel.o' libtool=no @AMDEPBACKSLASH@ +3Depict-filterCommon.o: backend/filters/filterCommon.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filterCommon.o -MD -MP -MF $(DEPDIR)/3Depict-filterCommon.Tpo -c -o 3Depict-filterCommon.o `test -f 'backend/filters/filterCommon.cpp' || echo '$(srcdir)/'`backend/filters/filterCommon.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filterCommon.Tpo $(DEPDIR)/3Depict-filterCommon.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/filterCommon.cpp' object='3Depict-filterCommon.o' libtool=no @AMDEPBACKSLASH@ @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-cropPanel.o `test -f 'cropPanel.cpp' || echo '$(srcdir)/'`cropPanel.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filterCommon.o `test -f 'backend/filters/filterCommon.cpp' || echo '$(srcdir)/'`backend/filters/filterCommon.cpp -3Depict-cropPanel.obj: cropPanel.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cropPanel.obj -MD -MP -MF $(DEPDIR)/3Depict-cropPanel.Tpo -c -o 3Depict-cropPanel.obj `if test -f 'cropPanel.cpp'; then $(CYGPATH_W) 'cropPanel.cpp'; else $(CYGPATH_W) '$(srcdir)/cropPanel.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cropPanel.Tpo $(DEPDIR)/3Depict-cropPanel.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cropPanel.cpp' object='3Depict-cropPanel.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-filterCommon.obj: backend/filters/filterCommon.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filterCommon.obj -MD -MP -MF $(DEPDIR)/3Depict-filterCommon.Tpo -c -o 3Depict-filterCommon.obj `if test -f 'backend/filters/filterCommon.cpp'; then $(CYGPATH_W) 'backend/filters/filterCommon.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/filterCommon.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filterCommon.Tpo $(DEPDIR)/3Depict-filterCommon.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/filterCommon.cpp' object='3Depict-filterCommon.obj' libtool=no @AMDEPBACKSLASH@ @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-cropPanel.obj `if test -f 'cropPanel.cpp'; then $(CYGPATH_W) 'cropPanel.cpp'; else $(CYGPATH_W) '$(srcdir)/cropPanel.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filterCommon.obj `if test -f 'backend/filters/filterCommon.cpp'; then $(CYGPATH_W) 'backend/filters/filterCommon.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/filterCommon.cpp'; fi` -3Depict-colourmap.o: colourmap.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourmap.o -MD -MP -MF $(DEPDIR)/3Depict-colourmap.Tpo -c -o 3Depict-colourmap.o `test -f 'colourmap.cpp' || echo '$(srcdir)/'`colourmap.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourmap.Tpo $(DEPDIR)/3Depict-colourmap.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='colourmap.cpp' object='3Depict-colourmap.o' libtool=no @AMDEPBACKSLASH@ +3Depict-dataLoad.o: backend/filters/dataLoad.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-dataLoad.o -MD -MP -MF $(DEPDIR)/3Depict-dataLoad.Tpo -c -o 3Depict-dataLoad.o `test -f 'backend/filters/dataLoad.cpp' || echo '$(srcdir)/'`backend/filters/dataLoad.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-dataLoad.Tpo $(DEPDIR)/3Depict-dataLoad.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/dataLoad.cpp' object='3Depict-dataLoad.o' libtool=no @AMDEPBACKSLASH@ @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-colourmap.o `test -f 'colourmap.cpp' || echo '$(srcdir)/'`colourmap.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-dataLoad.o `test -f 'backend/filters/dataLoad.cpp' || echo '$(srcdir)/'`backend/filters/dataLoad.cpp -3Depict-colourmap.obj: colourmap.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourmap.obj -MD -MP -MF $(DEPDIR)/3Depict-colourmap.Tpo -c -o 3Depict-colourmap.obj `if test -f 'colourmap.cpp'; then $(CYGPATH_W) 'colourmap.cpp'; else $(CYGPATH_W) '$(srcdir)/colourmap.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourmap.Tpo $(DEPDIR)/3Depict-colourmap.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='colourmap.cpp' object='3Depict-colourmap.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-dataLoad.obj: backend/filters/dataLoad.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-dataLoad.obj -MD -MP -MF $(DEPDIR)/3Depict-dataLoad.Tpo -c -o 3Depict-dataLoad.obj `if test -f 'backend/filters/dataLoad.cpp'; then $(CYGPATH_W) 'backend/filters/dataLoad.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/dataLoad.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-dataLoad.Tpo $(DEPDIR)/3Depict-dataLoad.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/dataLoad.cpp' object='3Depict-dataLoad.obj' libtool=no @AMDEPBACKSLASH@ @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-colourmap.obj `if test -f 'colourmap.cpp'; then $(CYGPATH_W) 'colourmap.cpp'; else $(CYGPATH_W) '$(srcdir)/colourmap.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-dataLoad.obj `if test -f 'backend/filters/dataLoad.cpp'; then $(CYGPATH_W) 'backend/filters/dataLoad.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/dataLoad.cpp'; fi` -3Depict-mathfuncs.o: mathfuncs.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathfuncs.o -MD -MP -MF $(DEPDIR)/3Depict-mathfuncs.Tpo -c -o 3Depict-mathfuncs.o `test -f 'mathfuncs.cpp' || echo '$(srcdir)/'`mathfuncs.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mathfuncs.Tpo $(DEPDIR)/3Depict-mathfuncs.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mathfuncs.cpp' object='3Depict-mathfuncs.o' libtool=no @AMDEPBACKSLASH@ +3Depict-ionDownsample.o: backend/filters/ionDownsample.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionDownsample.o -MD -MP -MF $(DEPDIR)/3Depict-ionDownsample.Tpo -c -o 3Depict-ionDownsample.o `test -f 'backend/filters/ionDownsample.cpp' || echo '$(srcdir)/'`backend/filters/ionDownsample.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionDownsample.Tpo $(DEPDIR)/3Depict-ionDownsample.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionDownsample.cpp' object='3Depict-ionDownsample.o' libtool=no @AMDEPBACKSLASH@ @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-mathfuncs.o `test -f 'mathfuncs.cpp' || echo '$(srcdir)/'`mathfuncs.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionDownsample.o `test -f 'backend/filters/ionDownsample.cpp' || echo '$(srcdir)/'`backend/filters/ionDownsample.cpp -3Depict-mathfuncs.obj: mathfuncs.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathfuncs.obj -MD -MP -MF $(DEPDIR)/3Depict-mathfuncs.Tpo -c -o 3Depict-mathfuncs.obj `if test -f 'mathfuncs.cpp'; then $(CYGPATH_W) 'mathfuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/mathfuncs.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mathfuncs.Tpo $(DEPDIR)/3Depict-mathfuncs.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mathfuncs.cpp' object='3Depict-mathfuncs.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-ionDownsample.obj: backend/filters/ionDownsample.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionDownsample.obj -MD -MP -MF $(DEPDIR)/3Depict-ionDownsample.Tpo -c -o 3Depict-ionDownsample.obj `if test -f 'backend/filters/ionDownsample.cpp'; then $(CYGPATH_W) 'backend/filters/ionDownsample.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionDownsample.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionDownsample.Tpo $(DEPDIR)/3Depict-ionDownsample.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionDownsample.cpp' object='3Depict-ionDownsample.obj' libtool=no @AMDEPBACKSLASH@ @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-mathfuncs.obj `if test -f 'mathfuncs.cpp'; then $(CYGPATH_W) 'mathfuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/mathfuncs.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionDownsample.obj `if test -f 'backend/filters/ionDownsample.cpp'; then $(CYGPATH_W) 'backend/filters/ionDownsample.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionDownsample.cpp'; fi` -3Depict-wxcomponents.o: wxcomponents.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcomponents.o -MD -MP -MF $(DEPDIR)/3Depict-wxcomponents.Tpo -c -o 3Depict-wxcomponents.o `test -f 'wxcomponents.cpp' || echo '$(srcdir)/'`wxcomponents.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcomponents.Tpo $(DEPDIR)/3Depict-wxcomponents.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcomponents.cpp' object='3Depict-wxcomponents.o' libtool=no @AMDEPBACKSLASH@ +3Depict-rangeFile.o: backend/filters/rangeFile.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rangeFile.o -MD -MP -MF $(DEPDIR)/3Depict-rangeFile.Tpo -c -o 3Depict-rangeFile.o `test -f 'backend/filters/rangeFile.cpp' || echo '$(srcdir)/'`backend/filters/rangeFile.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rangeFile.Tpo $(DEPDIR)/3Depict-rangeFile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/rangeFile.cpp' object='3Depict-rangeFile.o' libtool=no @AMDEPBACKSLASH@ @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-wxcomponents.o `test -f 'wxcomponents.cpp' || echo '$(srcdir)/'`wxcomponents.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-rangeFile.o `test -f 'backend/filters/rangeFile.cpp' || echo '$(srcdir)/'`backend/filters/rangeFile.cpp -3Depict-wxcomponents.obj: wxcomponents.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcomponents.obj -MD -MP -MF $(DEPDIR)/3Depict-wxcomponents.Tpo -c -o 3Depict-wxcomponents.obj `if test -f 'wxcomponents.cpp'; then $(CYGPATH_W) 'wxcomponents.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcomponents.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcomponents.Tpo $(DEPDIR)/3Depict-wxcomponents.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcomponents.cpp' object='3Depict-wxcomponents.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-rangeFile.obj: backend/filters/rangeFile.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rangeFile.obj -MD -MP -MF $(DEPDIR)/3Depict-rangeFile.Tpo -c -o 3Depict-rangeFile.obj `if test -f 'backend/filters/rangeFile.cpp'; then $(CYGPATH_W) 'backend/filters/rangeFile.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/rangeFile.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rangeFile.Tpo $(DEPDIR)/3Depict-rangeFile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/rangeFile.cpp' object='3Depict-rangeFile.obj' libtool=no @AMDEPBACKSLASH@ @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-wxcomponents.obj `if test -f 'wxcomponents.cpp'; then $(CYGPATH_W) 'wxcomponents.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcomponents.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-rangeFile.obj `if test -f 'backend/filters/rangeFile.cpp'; then $(CYGPATH_W) 'backend/filters/rangeFile.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/rangeFile.cpp'; fi` -3Depict-wxcommon.o: wxcommon.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcommon.o -MD -MP -MF $(DEPDIR)/3Depict-wxcommon.Tpo -c -o 3Depict-wxcommon.o `test -f 'wxcommon.cpp' || echo '$(srcdir)/'`wxcommon.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcommon.Tpo $(DEPDIR)/3Depict-wxcommon.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcommon.cpp' object='3Depict-wxcommon.o' libtool=no @AMDEPBACKSLASH@ +3Depict-voxelise.o: backend/filters/voxelise.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-voxelise.o -MD -MP -MF $(DEPDIR)/3Depict-voxelise.Tpo -c -o 3Depict-voxelise.o `test -f 'backend/filters/voxelise.cpp' || echo '$(srcdir)/'`backend/filters/voxelise.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-voxelise.Tpo $(DEPDIR)/3Depict-voxelise.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/voxelise.cpp' object='3Depict-voxelise.o' libtool=no @AMDEPBACKSLASH@ @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.o `test -f 'wxcommon.cpp' || echo '$(srcdir)/'`wxcommon.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-voxelise.o `test -f 'backend/filters/voxelise.cpp' || echo '$(srcdir)/'`backend/filters/voxelise.cpp -3Depict-wxcommon.obj: wxcommon.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-wxcommon.obj -MD -MP -MF $(DEPDIR)/3Depict-wxcommon.Tpo -c -o 3Depict-wxcommon.obj `if test -f 'wxcommon.cpp'; then $(CYGPATH_W) 'wxcommon.cpp'; else $(CYGPATH_W) '$(srcdir)/wxcommon.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-wxcommon.Tpo $(DEPDIR)/3Depict-wxcommon.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='wxcommon.cpp' object='3Depict-wxcommon.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-voxelise.obj: backend/filters/voxelise.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-voxelise.obj -MD -MP -MF $(DEPDIR)/3Depict-voxelise.Tpo -c -o 3Depict-voxelise.obj `if test -f 'backend/filters/voxelise.cpp'; then $(CYGPATH_W) 'backend/filters/voxelise.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/voxelise.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-voxelise.Tpo $(DEPDIR)/3Depict-voxelise.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/voxelise.cpp' object='3Depict-voxelise.obj' libtool=no @AMDEPBACKSLASH@ @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` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-voxelise.obj `if test -f 'backend/filters/voxelise.cpp'; then $(CYGPATH_W) 'backend/filters/voxelise.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/voxelise.cpp'; fi` -3Depict-ExportPos.o: dialogs/ExportPos.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportPos.o -MD -MP -MF $(DEPDIR)/3Depict-ExportPos.Tpo -c -o 3Depict-ExportPos.o `test -f 'dialogs/ExportPos.cpp' || echo '$(srcdir)/'`dialogs/ExportPos.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportPos.Tpo $(DEPDIR)/3Depict-ExportPos.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/ExportPos.cpp' object='3Depict-ExportPos.o' libtool=no @AMDEPBACKSLASH@ +3Depict-spectrumPlot.o: backend/filters/spectrumPlot.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spectrumPlot.o -MD -MP -MF $(DEPDIR)/3Depict-spectrumPlot.Tpo -c -o 3Depict-spectrumPlot.o `test -f 'backend/filters/spectrumPlot.cpp' || echo '$(srcdir)/'`backend/filters/spectrumPlot.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spectrumPlot.Tpo $(DEPDIR)/3Depict-spectrumPlot.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/spectrumPlot.cpp' object='3Depict-spectrumPlot.o' libtool=no @AMDEPBACKSLASH@ @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-ExportPos.o `test -f 'dialogs/ExportPos.cpp' || echo '$(srcdir)/'`dialogs/ExportPos.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-spectrumPlot.o `test -f 'backend/filters/spectrumPlot.cpp' || echo '$(srcdir)/'`backend/filters/spectrumPlot.cpp -3Depict-ExportPos.obj: dialogs/ExportPos.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportPos.obj -MD -MP -MF $(DEPDIR)/3Depict-ExportPos.Tpo -c -o 3Depict-ExportPos.obj `if test -f 'dialogs/ExportPos.cpp'; then $(CYGPATH_W) 'dialogs/ExportPos.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/ExportPos.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportPos.Tpo $(DEPDIR)/3Depict-ExportPos.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/ExportPos.cpp' object='3Depict-ExportPos.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-spectrumPlot.obj: backend/filters/spectrumPlot.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spectrumPlot.obj -MD -MP -MF $(DEPDIR)/3Depict-spectrumPlot.Tpo -c -o 3Depict-spectrumPlot.obj `if test -f 'backend/filters/spectrumPlot.cpp'; then $(CYGPATH_W) 'backend/filters/spectrumPlot.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/spectrumPlot.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spectrumPlot.Tpo $(DEPDIR)/3Depict-spectrumPlot.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/spectrumPlot.cpp' object='3Depict-spectrumPlot.obj' libtool=no @AMDEPBACKSLASH@ @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-ExportPos.obj `if test -f 'dialogs/ExportPos.cpp'; then $(CYGPATH_W) 'dialogs/ExportPos.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/ExportPos.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-spectrumPlot.obj `if test -f 'backend/filters/spectrumPlot.cpp'; then $(CYGPATH_W) 'backend/filters/spectrumPlot.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/spectrumPlot.cpp'; fi` -3Depict-ExportRngDialog.o: dialogs/ExportRngDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportRngDialog.o -MD -MP -MF $(DEPDIR)/3Depict-ExportRngDialog.Tpo -c -o 3Depict-ExportRngDialog.o `test -f 'dialogs/ExportRngDialog.cpp' || echo '$(srcdir)/'`dialogs/ExportRngDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportRngDialog.Tpo $(DEPDIR)/3Depict-ExportRngDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/ExportRngDialog.cpp' object='3Depict-ExportRngDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-transform.o: backend/filters/transform.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-transform.o -MD -MP -MF $(DEPDIR)/3Depict-transform.Tpo -c -o 3Depict-transform.o `test -f 'backend/filters/transform.cpp' || echo '$(srcdir)/'`backend/filters/transform.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-transform.Tpo $(DEPDIR)/3Depict-transform.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/transform.cpp' object='3Depict-transform.o' libtool=no @AMDEPBACKSLASH@ @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-ExportRngDialog.o `test -f 'dialogs/ExportRngDialog.cpp' || echo '$(srcdir)/'`dialogs/ExportRngDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-transform.o `test -f 'backend/filters/transform.cpp' || echo '$(srcdir)/'`backend/filters/transform.cpp -3Depict-ExportRngDialog.obj: dialogs/ExportRngDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ExportRngDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-ExportRngDialog.Tpo -c -o 3Depict-ExportRngDialog.obj `if test -f 'dialogs/ExportRngDialog.cpp'; then $(CYGPATH_W) 'dialogs/ExportRngDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/ExportRngDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ExportRngDialog.Tpo $(DEPDIR)/3Depict-ExportRngDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/ExportRngDialog.cpp' object='3Depict-ExportRngDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-transform.obj: backend/filters/transform.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-transform.obj -MD -MP -MF $(DEPDIR)/3Depict-transform.Tpo -c -o 3Depict-transform.obj `if test -f 'backend/filters/transform.cpp'; then $(CYGPATH_W) 'backend/filters/transform.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/transform.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-transform.Tpo $(DEPDIR)/3Depict-transform.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/transform.cpp' object='3Depict-transform.obj' libtool=no @AMDEPBACKSLASH@ @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-ExportRngDialog.obj `if test -f 'dialogs/ExportRngDialog.cpp'; then $(CYGPATH_W) 'dialogs/ExportRngDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/ExportRngDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-transform.obj `if test -f 'backend/filters/transform.cpp'; then $(CYGPATH_W) 'backend/filters/transform.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/transform.cpp'; fi` -3Depict-prefDialog.o: dialogs/prefDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-prefDialog.o -MD -MP -MF $(DEPDIR)/3Depict-prefDialog.Tpo -c -o 3Depict-prefDialog.o `test -f 'dialogs/prefDialog.cpp' || echo '$(srcdir)/'`dialogs/prefDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-prefDialog.Tpo $(DEPDIR)/3Depict-prefDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/prefDialog.cpp' object='3Depict-prefDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-externalProgram.o: backend/filters/externalProgram.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-externalProgram.o -MD -MP -MF $(DEPDIR)/3Depict-externalProgram.Tpo -c -o 3Depict-externalProgram.o `test -f 'backend/filters/externalProgram.cpp' || echo '$(srcdir)/'`backend/filters/externalProgram.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-externalProgram.Tpo $(DEPDIR)/3Depict-externalProgram.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/externalProgram.cpp' object='3Depict-externalProgram.o' libtool=no @AMDEPBACKSLASH@ @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-prefDialog.o `test -f 'dialogs/prefDialog.cpp' || echo '$(srcdir)/'`dialogs/prefDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-externalProgram.o `test -f 'backend/filters/externalProgram.cpp' || echo '$(srcdir)/'`backend/filters/externalProgram.cpp -3Depict-prefDialog.obj: dialogs/prefDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-prefDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-prefDialog.Tpo -c -o 3Depict-prefDialog.obj `if test -f 'dialogs/prefDialog.cpp'; then $(CYGPATH_W) 'dialogs/prefDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/prefDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-prefDialog.Tpo $(DEPDIR)/3Depict-prefDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/prefDialog.cpp' object='3Depict-prefDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-externalProgram.obj: backend/filters/externalProgram.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-externalProgram.obj -MD -MP -MF $(DEPDIR)/3Depict-externalProgram.Tpo -c -o 3Depict-externalProgram.obj `if test -f 'backend/filters/externalProgram.cpp'; then $(CYGPATH_W) 'backend/filters/externalProgram.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/externalProgram.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-externalProgram.Tpo $(DEPDIR)/3Depict-externalProgram.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/externalProgram.cpp' object='3Depict-externalProgram.obj' libtool=no @AMDEPBACKSLASH@ @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-prefDialog.obj `if test -f 'dialogs/prefDialog.cpp'; then $(CYGPATH_W) 'dialogs/prefDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/prefDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-externalProgram.obj `if test -f 'backend/filters/externalProgram.cpp'; then $(CYGPATH_W) 'backend/filters/externalProgram.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/externalProgram.cpp'; fi` -3Depict-resolutionDialog.o: dialogs/resolutionDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-resolutionDialog.o -MD -MP -MF $(DEPDIR)/3Depict-resolutionDialog.Tpo -c -o 3Depict-resolutionDialog.o `test -f 'dialogs/resolutionDialog.cpp' || echo '$(srcdir)/'`dialogs/resolutionDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-resolutionDialog.Tpo $(DEPDIR)/3Depict-resolutionDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/resolutionDialog.cpp' object='3Depict-resolutionDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-ionClip.o: backend/filters/ionClip.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionClip.o -MD -MP -MF $(DEPDIR)/3Depict-ionClip.Tpo -c -o 3Depict-ionClip.o `test -f 'backend/filters/ionClip.cpp' || echo '$(srcdir)/'`backend/filters/ionClip.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionClip.Tpo $(DEPDIR)/3Depict-ionClip.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionClip.cpp' object='3Depict-ionClip.o' libtool=no @AMDEPBACKSLASH@ @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-resolutionDialog.o `test -f 'dialogs/resolutionDialog.cpp' || echo '$(srcdir)/'`dialogs/resolutionDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionClip.o `test -f 'backend/filters/ionClip.cpp' || echo '$(srcdir)/'`backend/filters/ionClip.cpp -3Depict-resolutionDialog.obj: dialogs/resolutionDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-resolutionDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-resolutionDialog.Tpo -c -o 3Depict-resolutionDialog.obj `if test -f 'dialogs/resolutionDialog.cpp'; then $(CYGPATH_W) 'dialogs/resolutionDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/resolutionDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-resolutionDialog.Tpo $(DEPDIR)/3Depict-resolutionDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/resolutionDialog.cpp' object='3Depict-resolutionDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-ionClip.obj: backend/filters/ionClip.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionClip.obj -MD -MP -MF $(DEPDIR)/3Depict-ionClip.Tpo -c -o 3Depict-ionClip.obj `if test -f 'backend/filters/ionClip.cpp'; then $(CYGPATH_W) 'backend/filters/ionClip.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionClip.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionClip.Tpo $(DEPDIR)/3Depict-ionClip.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionClip.cpp' object='3Depict-ionClip.obj' libtool=no @AMDEPBACKSLASH@ @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-resolutionDialog.obj `if test -f 'dialogs/resolutionDialog.cpp'; then $(CYGPATH_W) 'dialogs/resolutionDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/resolutionDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionClip.obj `if test -f 'backend/filters/ionClip.cpp'; then $(CYGPATH_W) 'backend/filters/ionClip.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionClip.cpp'; fi` -3Depict-StashDialog.o: dialogs/StashDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-StashDialog.o -MD -MP -MF $(DEPDIR)/3Depict-StashDialog.Tpo -c -o 3Depict-StashDialog.o `test -f 'dialogs/StashDialog.cpp' || echo '$(srcdir)/'`dialogs/StashDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-StashDialog.Tpo $(DEPDIR)/3Depict-StashDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/StashDialog.cpp' object='3Depict-StashDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-ionColour.o: backend/filters/ionColour.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionColour.o -MD -MP -MF $(DEPDIR)/3Depict-ionColour.Tpo -c -o 3Depict-ionColour.o `test -f 'backend/filters/ionColour.cpp' || echo '$(srcdir)/'`backend/filters/ionColour.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionColour.Tpo $(DEPDIR)/3Depict-ionColour.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionColour.cpp' object='3Depict-ionColour.o' libtool=no @AMDEPBACKSLASH@ @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-StashDialog.o `test -f 'dialogs/StashDialog.cpp' || echo '$(srcdir)/'`dialogs/StashDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionColour.o `test -f 'backend/filters/ionColour.cpp' || echo '$(srcdir)/'`backend/filters/ionColour.cpp -3Depict-StashDialog.obj: dialogs/StashDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-StashDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-StashDialog.Tpo -c -o 3Depict-StashDialog.obj `if test -f 'dialogs/StashDialog.cpp'; then $(CYGPATH_W) 'dialogs/StashDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/StashDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-StashDialog.Tpo $(DEPDIR)/3Depict-StashDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/StashDialog.cpp' object='3Depict-StashDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-ionColour.obj: backend/filters/ionColour.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionColour.obj -MD -MP -MF $(DEPDIR)/3Depict-ionColour.Tpo -c -o 3Depict-ionColour.obj `if test -f 'backend/filters/ionColour.cpp'; then $(CYGPATH_W) 'backend/filters/ionColour.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionColour.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionColour.Tpo $(DEPDIR)/3Depict-ionColour.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionColour.cpp' object='3Depict-ionColour.obj' libtool=no @AMDEPBACKSLASH@ @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-StashDialog.obj `if test -f 'dialogs/StashDialog.cpp'; then $(CYGPATH_W) 'dialogs/StashDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/StashDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionColour.obj `if test -f 'backend/filters/ionColour.cpp'; then $(CYGPATH_W) 'backend/filters/ionColour.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionColour.cpp'; fi` -3Depict-autosaveDialog.o: dialogs/autosaveDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-autosaveDialog.o -MD -MP -MF $(DEPDIR)/3Depict-autosaveDialog.Tpo -c -o 3Depict-autosaveDialog.o `test -f 'dialogs/autosaveDialog.cpp' || echo '$(srcdir)/'`dialogs/autosaveDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-autosaveDialog.Tpo $(DEPDIR)/3Depict-autosaveDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/autosaveDialog.cpp' object='3Depict-autosaveDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-boundingBox.o: backend/filters/boundingBox.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-boundingBox.o -MD -MP -MF $(DEPDIR)/3Depict-boundingBox.Tpo -c -o 3Depict-boundingBox.o `test -f 'backend/filters/boundingBox.cpp' || echo '$(srcdir)/'`backend/filters/boundingBox.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-boundingBox.Tpo $(DEPDIR)/3Depict-boundingBox.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/boundingBox.cpp' object='3Depict-boundingBox.o' libtool=no @AMDEPBACKSLASH@ @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-autosaveDialog.o `test -f 'dialogs/autosaveDialog.cpp' || echo '$(srcdir)/'`dialogs/autosaveDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-boundingBox.o `test -f 'backend/filters/boundingBox.cpp' || echo '$(srcdir)/'`backend/filters/boundingBox.cpp -3Depict-autosaveDialog.obj: dialogs/autosaveDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-autosaveDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-autosaveDialog.Tpo -c -o 3Depict-autosaveDialog.obj `if test -f 'dialogs/autosaveDialog.cpp'; then $(CYGPATH_W) 'dialogs/autosaveDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/autosaveDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-autosaveDialog.Tpo $(DEPDIR)/3Depict-autosaveDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/autosaveDialog.cpp' object='3Depict-autosaveDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-boundingBox.obj: backend/filters/boundingBox.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-boundingBox.obj -MD -MP -MF $(DEPDIR)/3Depict-boundingBox.Tpo -c -o 3Depict-boundingBox.obj `if test -f 'backend/filters/boundingBox.cpp'; then $(CYGPATH_W) 'backend/filters/boundingBox.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/boundingBox.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-boundingBox.Tpo $(DEPDIR)/3Depict-boundingBox.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/boundingBox.cpp' object='3Depict-boundingBox.obj' libtool=no @AMDEPBACKSLASH@ @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-autosaveDialog.obj `if test -f 'dialogs/autosaveDialog.cpp'; then $(CYGPATH_W) 'dialogs/autosaveDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/autosaveDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-boundingBox.obj `if test -f 'backend/filters/boundingBox.cpp'; then $(CYGPATH_W) 'backend/filters/boundingBox.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/boundingBox.cpp'; fi` -3Depict-filterErrorDialog.o: dialogs/filterErrorDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filterErrorDialog.o -MD -MP -MF $(DEPDIR)/3Depict-filterErrorDialog.Tpo -c -o 3Depict-filterErrorDialog.o `test -f 'dialogs/filterErrorDialog.cpp' || echo '$(srcdir)/'`dialogs/filterErrorDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filterErrorDialog.Tpo $(DEPDIR)/3Depict-filterErrorDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/filterErrorDialog.cpp' object='3Depict-filterErrorDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-compositionProfile.o: backend/filters/compositionProfile.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-compositionProfile.o -MD -MP -MF $(DEPDIR)/3Depict-compositionProfile.Tpo -c -o 3Depict-compositionProfile.o `test -f 'backend/filters/compositionProfile.cpp' || echo '$(srcdir)/'`backend/filters/compositionProfile.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-compositionProfile.Tpo $(DEPDIR)/3Depict-compositionProfile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/compositionProfile.cpp' object='3Depict-compositionProfile.o' libtool=no @AMDEPBACKSLASH@ @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-filterErrorDialog.o `test -f 'dialogs/filterErrorDialog.cpp' || echo '$(srcdir)/'`dialogs/filterErrorDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-compositionProfile.o `test -f 'backend/filters/compositionProfile.cpp' || echo '$(srcdir)/'`backend/filters/compositionProfile.cpp -3Depict-filterErrorDialog.obj: dialogs/filterErrorDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filterErrorDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-filterErrorDialog.Tpo -c -o 3Depict-filterErrorDialog.obj `if test -f 'dialogs/filterErrorDialog.cpp'; then $(CYGPATH_W) 'dialogs/filterErrorDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/filterErrorDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filterErrorDialog.Tpo $(DEPDIR)/3Depict-filterErrorDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/filterErrorDialog.cpp' object='3Depict-filterErrorDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-compositionProfile.obj: backend/filters/compositionProfile.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-compositionProfile.obj -MD -MP -MF $(DEPDIR)/3Depict-compositionProfile.Tpo -c -o 3Depict-compositionProfile.obj `if test -f 'backend/filters/compositionProfile.cpp'; then $(CYGPATH_W) 'backend/filters/compositionProfile.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/compositionProfile.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-compositionProfile.Tpo $(DEPDIR)/3Depict-compositionProfile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/compositionProfile.cpp' object='3Depict-compositionProfile.obj' libtool=no @AMDEPBACKSLASH@ @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-filterErrorDialog.obj `if test -f 'dialogs/filterErrorDialog.cpp'; then $(CYGPATH_W) 'dialogs/filterErrorDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/filterErrorDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-compositionProfile.obj `if test -f 'backend/filters/compositionProfile.cpp'; then $(CYGPATH_W) 'backend/filters/compositionProfile.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/compositionProfile.cpp'; fi` -3Depict-animateFilterDialog.o: dialogs/animateFilterDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animateFilterDialog.o -MD -MP -MF $(DEPDIR)/3Depict-animateFilterDialog.Tpo -c -o 3Depict-animateFilterDialog.o `test -f 'dialogs/animateFilterDialog.cpp' || echo '$(srcdir)/'`dialogs/animateFilterDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animateFilterDialog.Tpo $(DEPDIR)/3Depict-animateFilterDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateFilterDialog.cpp' object='3Depict-animateFilterDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-spatialAnalysis.o: backend/filters/spatialAnalysis.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spatialAnalysis.o -MD -MP -MF $(DEPDIR)/3Depict-spatialAnalysis.Tpo -c -o 3Depict-spatialAnalysis.o `test -f 'backend/filters/spatialAnalysis.cpp' || echo '$(srcdir)/'`backend/filters/spatialAnalysis.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spatialAnalysis.Tpo $(DEPDIR)/3Depict-spatialAnalysis.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/spatialAnalysis.cpp' object='3Depict-spatialAnalysis.o' libtool=no @AMDEPBACKSLASH@ @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-animateFilterDialog.o `test -f 'dialogs/animateFilterDialog.cpp' || echo '$(srcdir)/'`dialogs/animateFilterDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-spatialAnalysis.o `test -f 'backend/filters/spatialAnalysis.cpp' || echo '$(srcdir)/'`backend/filters/spatialAnalysis.cpp -3Depict-animateFilterDialog.obj: dialogs/animateFilterDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animateFilterDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-animateFilterDialog.Tpo -c -o 3Depict-animateFilterDialog.obj `if test -f 'dialogs/animateFilterDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateFilterDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateFilterDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animateFilterDialog.Tpo $(DEPDIR)/3Depict-animateFilterDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateFilterDialog.cpp' object='3Depict-animateFilterDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-spatialAnalysis.obj: backend/filters/spatialAnalysis.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spatialAnalysis.obj -MD -MP -MF $(DEPDIR)/3Depict-spatialAnalysis.Tpo -c -o 3Depict-spatialAnalysis.obj `if test -f 'backend/filters/spatialAnalysis.cpp'; then $(CYGPATH_W) 'backend/filters/spatialAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/spatialAnalysis.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spatialAnalysis.Tpo $(DEPDIR)/3Depict-spatialAnalysis.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/spatialAnalysis.cpp' object='3Depict-spatialAnalysis.obj' libtool=no @AMDEPBACKSLASH@ @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-animateFilterDialog.obj `if test -f 'dialogs/animateFilterDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateFilterDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateFilterDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-spatialAnalysis.obj `if test -f 'backend/filters/spatialAnalysis.cpp'; then $(CYGPATH_W) 'backend/filters/spatialAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/spatialAnalysis.cpp'; fi` -3Depict-colourKeyFrameDialog.o: dialogs/animateSubDialogs/colourKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourKeyFrameDialog.o -MD -MP -MF $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo -c -o 3Depict-colourKeyFrameDialog.o `test -f 'dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' || echo '$(srcdir)/'`dialogs/animateSubDialogs/colourKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo $(DEPDIR)/3Depict-colourKeyFrameDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' object='3Depict-colourKeyFrameDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-clusterAnalysis.o: backend/filters/clusterAnalysis.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-clusterAnalysis.o -MD -MP -MF $(DEPDIR)/3Depict-clusterAnalysis.Tpo -c -o 3Depict-clusterAnalysis.o `test -f 'backend/filters/clusterAnalysis.cpp' || echo '$(srcdir)/'`backend/filters/clusterAnalysis.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-clusterAnalysis.Tpo $(DEPDIR)/3Depict-clusterAnalysis.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/clusterAnalysis.cpp' object='3Depict-clusterAnalysis.o' libtool=no @AMDEPBACKSLASH@ @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-colourKeyFrameDialog.o `test -f 'dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' || echo '$(srcdir)/'`dialogs/animateSubDialogs/colourKeyFrameDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-clusterAnalysis.o `test -f 'backend/filters/clusterAnalysis.cpp' || echo '$(srcdir)/'`backend/filters/clusterAnalysis.cpp -3Depict-colourKeyFrameDialog.obj: dialogs/animateSubDialogs/colourKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourKeyFrameDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo -c -o 3Depict-colourKeyFrameDialog.obj `if test -f 'dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourKeyFrameDialog.Tpo $(DEPDIR)/3Depict-colourKeyFrameDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateSubDialogs/colourKeyFrameDialog.cpp' object='3Depict-colourKeyFrameDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-clusterAnalysis.obj: backend/filters/clusterAnalysis.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-clusterAnalysis.obj -MD -MP -MF $(DEPDIR)/3Depict-clusterAnalysis.Tpo -c -o 3Depict-clusterAnalysis.obj `if test -f 'backend/filters/clusterAnalysis.cpp'; then $(CYGPATH_W) 'backend/filters/clusterAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/clusterAnalysis.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-clusterAnalysis.Tpo $(DEPDIR)/3Depict-clusterAnalysis.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/clusterAnalysis.cpp' object='3Depict-clusterAnalysis.obj' libtool=no @AMDEPBACKSLASH@ @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-colourKeyFrameDialog.obj `if test -f 'dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-clusterAnalysis.obj `if test -f 'backend/filters/clusterAnalysis.cpp'; then $(CYGPATH_W) 'backend/filters/clusterAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/clusterAnalysis.cpp'; fi` -3Depict-stringKeyFrameDialog.o: dialogs/animateSubDialogs/stringKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-stringKeyFrameDialog.o -MD -MP -MF $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo -c -o 3Depict-stringKeyFrameDialog.o `test -f 'dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' || echo '$(srcdir)/'`dialogs/animateSubDialogs/stringKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo $(DEPDIR)/3Depict-stringKeyFrameDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' object='3Depict-stringKeyFrameDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-ionInfo.o: backend/filters/ionInfo.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionInfo.o -MD -MP -MF $(DEPDIR)/3Depict-ionInfo.Tpo -c -o 3Depict-ionInfo.o `test -f 'backend/filters/ionInfo.cpp' || echo '$(srcdir)/'`backend/filters/ionInfo.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionInfo.Tpo $(DEPDIR)/3Depict-ionInfo.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionInfo.cpp' object='3Depict-ionInfo.o' libtool=no @AMDEPBACKSLASH@ @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-stringKeyFrameDialog.o `test -f 'dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' || echo '$(srcdir)/'`dialogs/animateSubDialogs/stringKeyFrameDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionInfo.o `test -f 'backend/filters/ionInfo.cpp' || echo '$(srcdir)/'`backend/filters/ionInfo.cpp -3Depict-stringKeyFrameDialog.obj: dialogs/animateSubDialogs/stringKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-stringKeyFrameDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo -c -o 3Depict-stringKeyFrameDialog.obj `if test -f 'dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-stringKeyFrameDialog.Tpo $(DEPDIR)/3Depict-stringKeyFrameDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateSubDialogs/stringKeyFrameDialog.cpp' object='3Depict-stringKeyFrameDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-ionInfo.obj: backend/filters/ionInfo.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionInfo.obj -MD -MP -MF $(DEPDIR)/3Depict-ionInfo.Tpo -c -o 3Depict-ionInfo.obj `if test -f 'backend/filters/ionInfo.cpp'; then $(CYGPATH_W) 'backend/filters/ionInfo.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionInfo.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionInfo.Tpo $(DEPDIR)/3Depict-ionInfo.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/ionInfo.cpp' object='3Depict-ionInfo.obj' libtool=no @AMDEPBACKSLASH@ @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-stringKeyFrameDialog.obj `if test -f 'dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-ionInfo.obj `if test -f 'backend/filters/ionInfo.cpp'; then $(CYGPATH_W) 'backend/filters/ionInfo.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/ionInfo.cpp'; fi` -3Depict-choiceKeyFrameDialog.o: dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-choiceKeyFrameDialog.o -MD -MP -MF $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo -c -o 3Depict-choiceKeyFrameDialog.o `test -f 'dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' || echo '$(srcdir)/'`dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo $(DEPDIR)/3Depict-choiceKeyFrameDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' object='3Depict-choiceKeyFrameDialog.o' libtool=no @AMDEPBACKSLASH@ +3Depict-annotation.o: backend/filters/annotation.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-annotation.o -MD -MP -MF $(DEPDIR)/3Depict-annotation.Tpo -c -o 3Depict-annotation.o `test -f 'backend/filters/annotation.cpp' || echo '$(srcdir)/'`backend/filters/annotation.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-annotation.Tpo $(DEPDIR)/3Depict-annotation.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/annotation.cpp' object='3Depict-annotation.o' libtool=no @AMDEPBACKSLASH@ @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-choiceKeyFrameDialog.o `test -f 'dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' || echo '$(srcdir)/'`dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-annotation.o `test -f 'backend/filters/annotation.cpp' || echo '$(srcdir)/'`backend/filters/annotation.cpp -3Depict-choiceKeyFrameDialog.obj: dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-choiceKeyFrameDialog.obj -MD -MP -MF $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo -c -o 3Depict-choiceKeyFrameDialog.obj `if test -f 'dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-choiceKeyFrameDialog.Tpo $(DEPDIR)/3Depict-choiceKeyFrameDialog.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp' object='3Depict-choiceKeyFrameDialog.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-annotation.obj: backend/filters/annotation.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-annotation.obj -MD -MP -MF $(DEPDIR)/3Depict-annotation.Tpo -c -o 3Depict-annotation.obj `if test -f 'backend/filters/annotation.cpp'; then $(CYGPATH_W) 'backend/filters/annotation.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/annotation.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-annotation.Tpo $(DEPDIR)/3Depict-annotation.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/annotation.cpp' object='3Depict-annotation.obj' libtool=no @AMDEPBACKSLASH@ @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-choiceKeyFrameDialog.obj `if test -f 'dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; then $(CYGPATH_W) 'dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; else $(CYGPATH_W) '$(srcdir)/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-annotation.obj `if test -f 'backend/filters/annotation.cpp'; then $(CYGPATH_W) 'backend/filters/annotation.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/annotation.cpp'; fi` -3Depict-allFilter.o: filters/allFilter.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-allFilter.o -MD -MP -MF $(DEPDIR)/3Depict-allFilter.Tpo -c -o 3Depict-allFilter.o `test -f 'filters/allFilter.cpp' || echo '$(srcdir)/'`filters/allFilter.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-allFilter.Tpo $(DEPDIR)/3Depict-allFilter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/allFilter.cpp' object='3Depict-allFilter.o' libtool=no @AMDEPBACKSLASH@ +3Depict-geometryHelpers.o: backend/filters/geometryHelpers.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-geometryHelpers.o -MD -MP -MF $(DEPDIR)/3Depict-geometryHelpers.Tpo -c -o 3Depict-geometryHelpers.o `test -f 'backend/filters/geometryHelpers.cpp' || echo '$(srcdir)/'`backend/filters/geometryHelpers.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-geometryHelpers.Tpo $(DEPDIR)/3Depict-geometryHelpers.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/geometryHelpers.cpp' object='3Depict-geometryHelpers.o' libtool=no @AMDEPBACKSLASH@ @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-allFilter.o `test -f 'filters/allFilter.cpp' || echo '$(srcdir)/'`filters/allFilter.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-geometryHelpers.o `test -f 'backend/filters/geometryHelpers.cpp' || echo '$(srcdir)/'`backend/filters/geometryHelpers.cpp -3Depict-allFilter.obj: filters/allFilter.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-allFilter.obj -MD -MP -MF $(DEPDIR)/3Depict-allFilter.Tpo -c -o 3Depict-allFilter.obj `if test -f 'filters/allFilter.cpp'; then $(CYGPATH_W) 'filters/allFilter.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/allFilter.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-allFilter.Tpo $(DEPDIR)/3Depict-allFilter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/allFilter.cpp' object='3Depict-allFilter.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-geometryHelpers.obj: backend/filters/geometryHelpers.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-geometryHelpers.obj -MD -MP -MF $(DEPDIR)/3Depict-geometryHelpers.Tpo -c -o 3Depict-geometryHelpers.obj `if test -f 'backend/filters/geometryHelpers.cpp'; then $(CYGPATH_W) 'backend/filters/geometryHelpers.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/geometryHelpers.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-geometryHelpers.Tpo $(DEPDIR)/3Depict-geometryHelpers.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/geometryHelpers.cpp' object='3Depict-geometryHelpers.obj' libtool=no @AMDEPBACKSLASH@ @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-allFilter.obj `if test -f 'filters/allFilter.cpp'; then $(CYGPATH_W) 'filters/allFilter.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/allFilter.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-geometryHelpers.obj `if test -f 'backend/filters/geometryHelpers.cpp'; then $(CYGPATH_W) 'backend/filters/geometryHelpers.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/geometryHelpers.cpp'; fi` -3Depict-dataLoad.o: filters/dataLoad.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-dataLoad.o -MD -MP -MF $(DEPDIR)/3Depict-dataLoad.Tpo -c -o 3Depict-dataLoad.o `test -f 'filters/dataLoad.cpp' || echo '$(srcdir)/'`filters/dataLoad.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-dataLoad.Tpo $(DEPDIR)/3Depict-dataLoad.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/dataLoad.cpp' object='3Depict-dataLoad.o' libtool=no @AMDEPBACKSLASH@ +3Depict-animator.o: backend/animator.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animator.o -MD -MP -MF $(DEPDIR)/3Depict-animator.Tpo -c -o 3Depict-animator.o `test -f 'backend/animator.cpp' || echo '$(srcdir)/'`backend/animator.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animator.Tpo $(DEPDIR)/3Depict-animator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/animator.cpp' object='3Depict-animator.o' libtool=no @AMDEPBACKSLASH@ @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-dataLoad.o `test -f 'filters/dataLoad.cpp' || echo '$(srcdir)/'`filters/dataLoad.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-animator.o `test -f 'backend/animator.cpp' || echo '$(srcdir)/'`backend/animator.cpp -3Depict-dataLoad.obj: filters/dataLoad.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-dataLoad.obj -MD -MP -MF $(DEPDIR)/3Depict-dataLoad.Tpo -c -o 3Depict-dataLoad.obj `if test -f 'filters/dataLoad.cpp'; then $(CYGPATH_W) 'filters/dataLoad.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/dataLoad.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-dataLoad.Tpo $(DEPDIR)/3Depict-dataLoad.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/dataLoad.cpp' object='3Depict-dataLoad.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-animator.obj: backend/animator.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-animator.obj -MD -MP -MF $(DEPDIR)/3Depict-animator.Tpo -c -o 3Depict-animator.obj `if test -f 'backend/animator.cpp'; then $(CYGPATH_W) 'backend/animator.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/animator.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-animator.Tpo $(DEPDIR)/3Depict-animator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/animator.cpp' object='3Depict-animator.obj' libtool=no @AMDEPBACKSLASH@ @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-dataLoad.obj `if test -f 'filters/dataLoad.cpp'; then $(CYGPATH_W) 'filters/dataLoad.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/dataLoad.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-animator.obj `if test -f 'backend/animator.cpp'; then $(CYGPATH_W) 'backend/animator.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/animator.cpp'; fi` -3Depict-ionDownsample.o: filters/ionDownsample.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionDownsample.o -MD -MP -MF $(DEPDIR)/3Depict-ionDownsample.Tpo -c -o 3Depict-ionDownsample.o `test -f 'filters/ionDownsample.cpp' || echo '$(srcdir)/'`filters/ionDownsample.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionDownsample.Tpo $(DEPDIR)/3Depict-ionDownsample.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionDownsample.cpp' object='3Depict-ionDownsample.o' libtool=no @AMDEPBACKSLASH@ +3Depict-filtertreeAnalyse.o: backend/filtertreeAnalyse.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertreeAnalyse.o -MD -MP -MF $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo -c -o 3Depict-filtertreeAnalyse.o `test -f 'backend/filtertreeAnalyse.cpp' || echo '$(srcdir)/'`backend/filtertreeAnalyse.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo $(DEPDIR)/3Depict-filtertreeAnalyse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filtertreeAnalyse.cpp' object='3Depict-filtertreeAnalyse.o' libtool=no @AMDEPBACKSLASH@ @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-ionDownsample.o `test -f 'filters/ionDownsample.cpp' || echo '$(srcdir)/'`filters/ionDownsample.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filtertreeAnalyse.o `test -f 'backend/filtertreeAnalyse.cpp' || echo '$(srcdir)/'`backend/filtertreeAnalyse.cpp -3Depict-ionDownsample.obj: filters/ionDownsample.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionDownsample.obj -MD -MP -MF $(DEPDIR)/3Depict-ionDownsample.Tpo -c -o 3Depict-ionDownsample.obj `if test -f 'filters/ionDownsample.cpp'; then $(CYGPATH_W) 'filters/ionDownsample.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionDownsample.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionDownsample.Tpo $(DEPDIR)/3Depict-ionDownsample.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionDownsample.cpp' object='3Depict-ionDownsample.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-filtertreeAnalyse.obj: backend/filtertreeAnalyse.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertreeAnalyse.obj -MD -MP -MF $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo -c -o 3Depict-filtertreeAnalyse.obj `if test -f 'backend/filtertreeAnalyse.cpp'; then $(CYGPATH_W) 'backend/filtertreeAnalyse.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filtertreeAnalyse.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertreeAnalyse.Tpo $(DEPDIR)/3Depict-filtertreeAnalyse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filtertreeAnalyse.cpp' object='3Depict-filtertreeAnalyse.obj' libtool=no @AMDEPBACKSLASH@ @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-ionDownsample.obj `if test -f 'filters/ionDownsample.cpp'; then $(CYGPATH_W) 'filters/ionDownsample.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionDownsample.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filtertreeAnalyse.obj `if test -f 'backend/filtertreeAnalyse.cpp'; then $(CYGPATH_W) 'backend/filtertreeAnalyse.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filtertreeAnalyse.cpp'; fi` -3Depict-rangeFile.o: filters/rangeFile.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rangeFile.o -MD -MP -MF $(DEPDIR)/3Depict-rangeFile.Tpo -c -o 3Depict-rangeFile.o `test -f 'filters/rangeFile.cpp' || echo '$(srcdir)/'`filters/rangeFile.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rangeFile.Tpo $(DEPDIR)/3Depict-rangeFile.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/rangeFile.cpp' object='3Depict-rangeFile.o' libtool=no @AMDEPBACKSLASH@ +3Depict-filtertree.o: backend/filtertree.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertree.o -MD -MP -MF $(DEPDIR)/3Depict-filtertree.Tpo -c -o 3Depict-filtertree.o `test -f 'backend/filtertree.cpp' || echo '$(srcdir)/'`backend/filtertree.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertree.Tpo $(DEPDIR)/3Depict-filtertree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filtertree.cpp' object='3Depict-filtertree.o' libtool=no @AMDEPBACKSLASH@ @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-rangeFile.o `test -f 'filters/rangeFile.cpp' || echo '$(srcdir)/'`filters/rangeFile.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filtertree.o `test -f 'backend/filtertree.cpp' || echo '$(srcdir)/'`backend/filtertree.cpp -3Depict-rangeFile.obj: filters/rangeFile.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rangeFile.obj -MD -MP -MF $(DEPDIR)/3Depict-rangeFile.Tpo -c -o 3Depict-rangeFile.obj `if test -f 'filters/rangeFile.cpp'; then $(CYGPATH_W) 'filters/rangeFile.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/rangeFile.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rangeFile.Tpo $(DEPDIR)/3Depict-rangeFile.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/rangeFile.cpp' object='3Depict-rangeFile.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-filtertree.obj: backend/filtertree.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filtertree.obj -MD -MP -MF $(DEPDIR)/3Depict-filtertree.Tpo -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` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filtertree.Tpo $(DEPDIR)/3Depict-filtertree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filtertree.cpp' object='3Depict-filtertree.obj' libtool=no @AMDEPBACKSLASH@ @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-rangeFile.obj `if test -f 'filters/rangeFile.cpp'; then $(CYGPATH_W) 'filters/rangeFile.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/rangeFile.cpp'; fi` +@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-voxelise.o: filters/voxelise.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-voxelise.o -MD -MP -MF $(DEPDIR)/3Depict-voxelise.Tpo -c -o 3Depict-voxelise.o `test -f 'filters/voxelise.cpp' || echo '$(srcdir)/'`filters/voxelise.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-voxelise.Tpo $(DEPDIR)/3Depict-voxelise.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/voxelise.cpp' object='3Depict-voxelise.o' libtool=no @AMDEPBACKSLASH@ +3Depict-APTClasses.o: backend/APT/APTClasses.cpp +@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 +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-APTClasses.Tpo $(DEPDIR)/3Depict-APTClasses.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/APT/APTClasses.cpp' object='3Depict-APTClasses.o' libtool=no @AMDEPBACKSLASH@ @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-voxelise.o `test -f 'filters/voxelise.cpp' || echo '$(srcdir)/'`filters/voxelise.cpp +@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 -3Depict-voxelise.obj: filters/voxelise.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-voxelise.obj -MD -MP -MF $(DEPDIR)/3Depict-voxelise.Tpo -c -o 3Depict-voxelise.obj `if test -f 'filters/voxelise.cpp'; then $(CYGPATH_W) 'filters/voxelise.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/voxelise.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-voxelise.Tpo $(DEPDIR)/3Depict-voxelise.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/voxelise.cpp' object='3Depict-voxelise.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-APTClasses.obj: backend/APT/APTClasses.cpp +@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` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-APTClasses.Tpo $(DEPDIR)/3Depict-APTClasses.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/APT/APTClasses.cpp' object='3Depict-APTClasses.obj' libtool=no @AMDEPBACKSLASH@ @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-voxelise.obj `if test -f 'filters/voxelise.cpp'; then $(CYGPATH_W) 'filters/voxelise.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/voxelise.cpp'; fi` +@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` -3Depict-spectrumPlot.o: filters/spectrumPlot.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spectrumPlot.o -MD -MP -MF $(DEPDIR)/3Depict-spectrumPlot.Tpo -c -o 3Depict-spectrumPlot.o `test -f 'filters/spectrumPlot.cpp' || echo '$(srcdir)/'`filters/spectrumPlot.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spectrumPlot.Tpo $(DEPDIR)/3Depict-spectrumPlot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/spectrumPlot.cpp' object='3Depict-spectrumPlot.o' libtool=no @AMDEPBACKSLASH@ +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 +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-APTRanges.Tpo $(DEPDIR)/3Depict-APTRanges.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/APT/APTRanges.cpp' object='3Depict-APTRanges.o' libtool=no @AMDEPBACKSLASH@ @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-spectrumPlot.o `test -f 'filters/spectrumPlot.cpp' || echo '$(srcdir)/'`filters/spectrumPlot.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-APTRanges.o `test -f 'backend/APT/APTRanges.cpp' || echo '$(srcdir)/'`backend/APT/APTRanges.cpp -3Depict-spectrumPlot.obj: filters/spectrumPlot.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spectrumPlot.obj -MD -MP -MF $(DEPDIR)/3Depict-spectrumPlot.Tpo -c -o 3Depict-spectrumPlot.obj `if test -f 'filters/spectrumPlot.cpp'; then $(CYGPATH_W) 'filters/spectrumPlot.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/spectrumPlot.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spectrumPlot.Tpo $(DEPDIR)/3Depict-spectrumPlot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/spectrumPlot.cpp' object='3Depict-spectrumPlot.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-APTRanges.obj: backend/APT/APTRanges.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-APTRanges.obj -MD -MP -MF $(DEPDIR)/3Depict-APTRanges.Tpo -c -o 3Depict-APTRanges.obj `if test -f 'backend/APT/APTRanges.cpp'; then $(CYGPATH_W) 'backend/APT/APTRanges.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/APTRanges.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-APTRanges.Tpo $(DEPDIR)/3Depict-APTRanges.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/APT/APTRanges.cpp' object='3Depict-APTRanges.obj' libtool=no @AMDEPBACKSLASH@ @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-spectrumPlot.obj `if test -f 'filters/spectrumPlot.cpp'; then $(CYGPATH_W) 'filters/spectrumPlot.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/spectrumPlot.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-APTRanges.obj `if test -f 'backend/APT/APTRanges.cpp'; then $(CYGPATH_W) 'backend/APT/APTRanges.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/APT/APTRanges.cpp'; fi` -3Depict-transform.o: filters/transform.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-transform.o -MD -MP -MF $(DEPDIR)/3Depict-transform.Tpo -c -o 3Depict-transform.o `test -f 'filters/transform.cpp' || echo '$(srcdir)/'`filters/transform.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-transform.Tpo $(DEPDIR)/3Depict-transform.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/transform.cpp' object='3Depict-transform.o' libtool=no @AMDEPBACKSLASH@ +3Depict-K3DTree.o: backend/filters/K3DTree.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree.o -MD -MP -MF $(DEPDIR)/3Depict-K3DTree.Tpo -c -o 3Depict-K3DTree.o `test -f 'backend/filters/K3DTree.cpp' || echo '$(srcdir)/'`backend/filters/K3DTree.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree.Tpo $(DEPDIR)/3Depict-K3DTree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/K3DTree.cpp' object='3Depict-K3DTree.o' libtool=no @AMDEPBACKSLASH@ @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-transform.o `test -f 'filters/transform.cpp' || echo '$(srcdir)/'`filters/transform.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-K3DTree.o `test -f 'backend/filters/K3DTree.cpp' || echo '$(srcdir)/'`backend/filters/K3DTree.cpp -3Depict-transform.obj: filters/transform.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-transform.obj -MD -MP -MF $(DEPDIR)/3Depict-transform.Tpo -c -o 3Depict-transform.obj `if test -f 'filters/transform.cpp'; then $(CYGPATH_W) 'filters/transform.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/transform.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-transform.Tpo $(DEPDIR)/3Depict-transform.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/transform.cpp' object='3Depict-transform.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-K3DTree.obj: backend/filters/K3DTree.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree.obj -MD -MP -MF $(DEPDIR)/3Depict-K3DTree.Tpo -c -o 3Depict-K3DTree.obj `if test -f 'backend/filters/K3DTree.cpp'; then $(CYGPATH_W) 'backend/filters/K3DTree.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/K3DTree.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree.Tpo $(DEPDIR)/3Depict-K3DTree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/K3DTree.cpp' object='3Depict-K3DTree.obj' libtool=no @AMDEPBACKSLASH@ @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-transform.obj `if test -f 'filters/transform.cpp'; then $(CYGPATH_W) 'filters/transform.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/transform.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-K3DTree.obj `if test -f 'backend/filters/K3DTree.cpp'; then $(CYGPATH_W) 'backend/filters/K3DTree.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/K3DTree.cpp'; fi` -3Depict-externalProgram.o: filters/externalProgram.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-externalProgram.o -MD -MP -MF $(DEPDIR)/3Depict-externalProgram.Tpo -c -o 3Depict-externalProgram.o `test -f 'filters/externalProgram.cpp' || echo '$(srcdir)/'`filters/externalProgram.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-externalProgram.Tpo $(DEPDIR)/3Depict-externalProgram.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/externalProgram.cpp' object='3Depict-externalProgram.o' libtool=no @AMDEPBACKSLASH@ +3Depict-K3DTree-mk2.o: backend/filters/K3DTree-mk2.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree-mk2.o -MD -MP -MF $(DEPDIR)/3Depict-K3DTree-mk2.Tpo -c -o 3Depict-K3DTree-mk2.o `test -f 'backend/filters/K3DTree-mk2.cpp' || echo '$(srcdir)/'`backend/filters/K3DTree-mk2.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree-mk2.Tpo $(DEPDIR)/3Depict-K3DTree-mk2.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/K3DTree-mk2.cpp' object='3Depict-K3DTree-mk2.o' libtool=no @AMDEPBACKSLASH@ @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-externalProgram.o `test -f 'filters/externalProgram.cpp' || echo '$(srcdir)/'`filters/externalProgram.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-K3DTree-mk2.o `test -f 'backend/filters/K3DTree-mk2.cpp' || echo '$(srcdir)/'`backend/filters/K3DTree-mk2.cpp -3Depict-externalProgram.obj: filters/externalProgram.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-externalProgram.obj -MD -MP -MF $(DEPDIR)/3Depict-externalProgram.Tpo -c -o 3Depict-externalProgram.obj `if test -f 'filters/externalProgram.cpp'; then $(CYGPATH_W) 'filters/externalProgram.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/externalProgram.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-externalProgram.Tpo $(DEPDIR)/3Depict-externalProgram.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/externalProgram.cpp' object='3Depict-externalProgram.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-K3DTree-mk2.obj: backend/filters/K3DTree-mk2.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-K3DTree-mk2.obj -MD -MP -MF $(DEPDIR)/3Depict-K3DTree-mk2.Tpo -c -o 3Depict-K3DTree-mk2.obj `if test -f 'backend/filters/K3DTree-mk2.cpp'; then $(CYGPATH_W) 'backend/filters/K3DTree-mk2.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/K3DTree-mk2.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-K3DTree-mk2.Tpo $(DEPDIR)/3Depict-K3DTree-mk2.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/K3DTree-mk2.cpp' object='3Depict-K3DTree-mk2.obj' libtool=no @AMDEPBACKSLASH@ @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-externalProgram.obj `if test -f 'filters/externalProgram.cpp'; then $(CYGPATH_W) 'filters/externalProgram.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/externalProgram.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-K3DTree-mk2.obj `if test -f 'backend/filters/K3DTree-mk2.cpp'; then $(CYGPATH_W) 'backend/filters/K3DTree-mk2.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/K3DTree-mk2.cpp'; fi` -3Depict-ionClip.o: filters/ionClip.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionClip.o -MD -MP -MF $(DEPDIR)/3Depict-ionClip.Tpo -c -o 3Depict-ionClip.o `test -f 'filters/ionClip.cpp' || echo '$(srcdir)/'`filters/ionClip.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionClip.Tpo $(DEPDIR)/3Depict-ionClip.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionClip.cpp' object='3Depict-ionClip.o' libtool=no @AMDEPBACKSLASH@ +3Depict-filter.o: backend/filter.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filter.o -MD -MP -MF $(DEPDIR)/3Depict-filter.Tpo -c -o 3Depict-filter.o `test -f 'backend/filter.cpp' || echo '$(srcdir)/'`backend/filter.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filter.Tpo $(DEPDIR)/3Depict-filter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filter.cpp' object='3Depict-filter.o' libtool=no @AMDEPBACKSLASH@ @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-ionClip.o `test -f 'filters/ionClip.cpp' || echo '$(srcdir)/'`filters/ionClip.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filter.o `test -f 'backend/filter.cpp' || echo '$(srcdir)/'`backend/filter.cpp -3Depict-ionClip.obj: filters/ionClip.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionClip.obj -MD -MP -MF $(DEPDIR)/3Depict-ionClip.Tpo -c -o 3Depict-ionClip.obj `if test -f 'filters/ionClip.cpp'; then $(CYGPATH_W) 'filters/ionClip.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionClip.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionClip.Tpo $(DEPDIR)/3Depict-ionClip.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionClip.cpp' object='3Depict-ionClip.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-filter.obj: backend/filter.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-filter.obj -MD -MP -MF $(DEPDIR)/3Depict-filter.Tpo -c -o 3Depict-filter.obj `if test -f 'backend/filter.cpp'; then $(CYGPATH_W) 'backend/filter.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filter.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-filter.Tpo $(DEPDIR)/3Depict-filter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filter.cpp' object='3Depict-filter.obj' libtool=no @AMDEPBACKSLASH@ @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-ionClip.obj `if test -f 'filters/ionClip.cpp'; then $(CYGPATH_W) 'filters/ionClip.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionClip.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-filter.obj `if test -f 'backend/filter.cpp'; then $(CYGPATH_W) 'backend/filter.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filter.cpp'; fi` -3Depict-ionColour.o: filters/ionColour.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionColour.o -MD -MP -MF $(DEPDIR)/3Depict-ionColour.Tpo -c -o 3Depict-ionColour.o `test -f 'filters/ionColour.cpp' || echo '$(srcdir)/'`filters/ionColour.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionColour.Tpo $(DEPDIR)/3Depict-ionColour.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionColour.cpp' object='3Depict-ionColour.o' libtool=no @AMDEPBACKSLASH@ +3Depict-rdf.o: backend/filters/rdf.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rdf.o -MD -MP -MF $(DEPDIR)/3Depict-rdf.Tpo -c -o 3Depict-rdf.o `test -f 'backend/filters/rdf.cpp' || echo '$(srcdir)/'`backend/filters/rdf.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rdf.Tpo $(DEPDIR)/3Depict-rdf.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/rdf.cpp' object='3Depict-rdf.o' libtool=no @AMDEPBACKSLASH@ @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-ionColour.o `test -f 'filters/ionColour.cpp' || echo '$(srcdir)/'`filters/ionColour.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-rdf.o `test -f 'backend/filters/rdf.cpp' || echo '$(srcdir)/'`backend/filters/rdf.cpp -3Depict-ionColour.obj: filters/ionColour.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionColour.obj -MD -MP -MF $(DEPDIR)/3Depict-ionColour.Tpo -c -o 3Depict-ionColour.obj `if test -f 'filters/ionColour.cpp'; then $(CYGPATH_W) 'filters/ionColour.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionColour.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionColour.Tpo $(DEPDIR)/3Depict-ionColour.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionColour.cpp' object='3Depict-ionColour.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-rdf.obj: backend/filters/rdf.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-rdf.obj -MD -MP -MF $(DEPDIR)/3Depict-rdf.Tpo -c -o 3Depict-rdf.obj `if test -f 'backend/filters/rdf.cpp'; then $(CYGPATH_W) 'backend/filters/rdf.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/rdf.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-rdf.Tpo $(DEPDIR)/3Depict-rdf.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/filters/rdf.cpp' object='3Depict-rdf.obj' libtool=no @AMDEPBACKSLASH@ @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-ionColour.obj `if test -f 'filters/ionColour.cpp'; then $(CYGPATH_W) 'filters/ionColour.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionColour.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-rdf.obj `if test -f 'backend/filters/rdf.cpp'; then $(CYGPATH_W) 'backend/filters/rdf.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/filters/rdf.cpp'; fi` -3Depict-boundingBox.o: filters/boundingBox.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-boundingBox.o -MD -MP -MF $(DEPDIR)/3Depict-boundingBox.Tpo -c -o 3Depict-boundingBox.o `test -f 'filters/boundingBox.cpp' || echo '$(srcdir)/'`filters/boundingBox.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-boundingBox.Tpo $(DEPDIR)/3Depict-boundingBox.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/boundingBox.cpp' object='3Depict-boundingBox.o' libtool=no @AMDEPBACKSLASH@ +3Depict-viscontrol.o: backend/viscontrol.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-viscontrol.o -MD -MP -MF $(DEPDIR)/3Depict-viscontrol.Tpo -c -o 3Depict-viscontrol.o `test -f 'backend/viscontrol.cpp' || echo '$(srcdir)/'`backend/viscontrol.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-viscontrol.Tpo $(DEPDIR)/3Depict-viscontrol.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/viscontrol.cpp' object='3Depict-viscontrol.o' libtool=no @AMDEPBACKSLASH@ @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-boundingBox.o `test -f 'filters/boundingBox.cpp' || echo '$(srcdir)/'`filters/boundingBox.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-viscontrol.o `test -f 'backend/viscontrol.cpp' || echo '$(srcdir)/'`backend/viscontrol.cpp -3Depict-boundingBox.obj: filters/boundingBox.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-boundingBox.obj -MD -MP -MF $(DEPDIR)/3Depict-boundingBox.Tpo -c -o 3Depict-boundingBox.obj `if test -f 'filters/boundingBox.cpp'; then $(CYGPATH_W) 'filters/boundingBox.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/boundingBox.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-boundingBox.Tpo $(DEPDIR)/3Depict-boundingBox.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/boundingBox.cpp' object='3Depict-boundingBox.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-viscontrol.obj: backend/viscontrol.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-viscontrol.obj -MD -MP -MF $(DEPDIR)/3Depict-viscontrol.Tpo -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` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-viscontrol.Tpo $(DEPDIR)/3Depict-viscontrol.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/viscontrol.cpp' object='3Depict-viscontrol.obj' libtool=no @AMDEPBACKSLASH@ @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-boundingBox.obj `if test -f 'filters/boundingBox.cpp'; then $(CYGPATH_W) 'filters/boundingBox.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/boundingBox.cpp'; fi` +@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-compositionProfile.o: filters/compositionProfile.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-compositionProfile.o -MD -MP -MF $(DEPDIR)/3Depict-compositionProfile.Tpo -c -o 3Depict-compositionProfile.o `test -f 'filters/compositionProfile.cpp' || echo '$(srcdir)/'`filters/compositionProfile.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-compositionProfile.Tpo $(DEPDIR)/3Depict-compositionProfile.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/compositionProfile.cpp' object='3Depict-compositionProfile.o' libtool=no @AMDEPBACKSLASH@ +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 +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/plot.cpp' object='3Depict-plot.o' libtool=no @AMDEPBACKSLASH@ @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-compositionProfile.o `test -f 'filters/compositionProfile.cpp' || echo '$(srcdir)/'`filters/compositionProfile.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-plot.o `test -f 'backend/plot.cpp' || echo '$(srcdir)/'`backend/plot.cpp -3Depict-compositionProfile.obj: filters/compositionProfile.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-compositionProfile.obj -MD -MP -MF $(DEPDIR)/3Depict-compositionProfile.Tpo -c -o 3Depict-compositionProfile.obj `if test -f 'filters/compositionProfile.cpp'; then $(CYGPATH_W) 'filters/compositionProfile.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/compositionProfile.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-compositionProfile.Tpo $(DEPDIR)/3Depict-compositionProfile.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/compositionProfile.cpp' object='3Depict-compositionProfile.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-plot.obj: backend/plot.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-plot.obj -MD -MP -MF $(DEPDIR)/3Depict-plot.Tpo -c -o 3Depict-plot.obj `if test -f 'backend/plot.cpp'; then $(CYGPATH_W) 'backend/plot.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/plot.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-plot.Tpo $(DEPDIR)/3Depict-plot.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/plot.cpp' object='3Depict-plot.obj' libtool=no @AMDEPBACKSLASH@ @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-compositionProfile.obj `if test -f 'filters/compositionProfile.cpp'; then $(CYGPATH_W) 'filters/compositionProfile.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/compositionProfile.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-plot.obj `if test -f 'backend/plot.cpp'; then $(CYGPATH_W) 'backend/plot.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/plot.cpp'; fi` -3Depict-spatialAnalysis.o: filters/spatialAnalysis.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spatialAnalysis.o -MD -MP -MF $(DEPDIR)/3Depict-spatialAnalysis.Tpo -c -o 3Depict-spatialAnalysis.o `test -f 'filters/spatialAnalysis.cpp' || echo '$(srcdir)/'`filters/spatialAnalysis.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spatialAnalysis.Tpo $(DEPDIR)/3Depict-spatialAnalysis.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/spatialAnalysis.cpp' object='3Depict-spatialAnalysis.o' libtool=no @AMDEPBACKSLASH@ +3Depict-configFile.o: backend/configFile.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-configFile.o -MD -MP -MF $(DEPDIR)/3Depict-configFile.Tpo -c -o 3Depict-configFile.o `test -f 'backend/configFile.cpp' || echo '$(srcdir)/'`backend/configFile.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-configFile.Tpo $(DEPDIR)/3Depict-configFile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/configFile.cpp' object='3Depict-configFile.o' libtool=no @AMDEPBACKSLASH@ @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-spatialAnalysis.o `test -f 'filters/spatialAnalysis.cpp' || echo '$(srcdir)/'`filters/spatialAnalysis.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-configFile.o `test -f 'backend/configFile.cpp' || echo '$(srcdir)/'`backend/configFile.cpp -3Depict-spatialAnalysis.obj: filters/spatialAnalysis.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-spatialAnalysis.obj -MD -MP -MF $(DEPDIR)/3Depict-spatialAnalysis.Tpo -c -o 3Depict-spatialAnalysis.obj `if test -f 'filters/spatialAnalysis.cpp'; then $(CYGPATH_W) 'filters/spatialAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/spatialAnalysis.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-spatialAnalysis.Tpo $(DEPDIR)/3Depict-spatialAnalysis.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/spatialAnalysis.cpp' object='3Depict-spatialAnalysis.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-configFile.obj: backend/configFile.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-configFile.obj -MD -MP -MF $(DEPDIR)/3Depict-configFile.Tpo -c -o 3Depict-configFile.obj `if test -f 'backend/configFile.cpp'; then $(CYGPATH_W) 'backend/configFile.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/configFile.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-configFile.Tpo $(DEPDIR)/3Depict-configFile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='backend/configFile.cpp' object='3Depict-configFile.obj' libtool=no @AMDEPBACKSLASH@ @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-spatialAnalysis.obj `if test -f 'filters/spatialAnalysis.cpp'; then $(CYGPATH_W) 'filters/spatialAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/spatialAnalysis.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-configFile.obj `if test -f 'backend/configFile.cpp'; then $(CYGPATH_W) 'backend/configFile.cpp'; else $(CYGPATH_W) '$(srcdir)/backend/configFile.cpp'; fi` -3Depict-clusterAnalysis.o: filters/clusterAnalysis.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-clusterAnalysis.o -MD -MP -MF $(DEPDIR)/3Depict-clusterAnalysis.Tpo -c -o 3Depict-clusterAnalysis.o `test -f 'filters/clusterAnalysis.cpp' || echo '$(srcdir)/'`filters/clusterAnalysis.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-clusterAnalysis.Tpo $(DEPDIR)/3Depict-clusterAnalysis.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/clusterAnalysis.cpp' object='3Depict-clusterAnalysis.o' libtool=no @AMDEPBACKSLASH@ +3Depict-scene.o: gl/scene.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-scene.o -MD -MP -MF $(DEPDIR)/3Depict-scene.Tpo -c -o 3Depict-scene.o `test -f 'gl/scene.cpp' || echo '$(srcdir)/'`gl/scene.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-scene.Tpo $(DEPDIR)/3Depict-scene.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/scene.cpp' object='3Depict-scene.o' libtool=no @AMDEPBACKSLASH@ @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-clusterAnalysis.o `test -f 'filters/clusterAnalysis.cpp' || echo '$(srcdir)/'`filters/clusterAnalysis.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-scene.o `test -f 'gl/scene.cpp' || echo '$(srcdir)/'`gl/scene.cpp -3Depict-clusterAnalysis.obj: filters/clusterAnalysis.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-clusterAnalysis.obj -MD -MP -MF $(DEPDIR)/3Depict-clusterAnalysis.Tpo -c -o 3Depict-clusterAnalysis.obj `if test -f 'filters/clusterAnalysis.cpp'; then $(CYGPATH_W) 'filters/clusterAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/clusterAnalysis.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-clusterAnalysis.Tpo $(DEPDIR)/3Depict-clusterAnalysis.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/clusterAnalysis.cpp' object='3Depict-clusterAnalysis.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-scene.obj: gl/scene.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-scene.obj -MD -MP -MF $(DEPDIR)/3Depict-scene.Tpo -c -o 3Depict-scene.obj `if test -f 'gl/scene.cpp'; then $(CYGPATH_W) 'gl/scene.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/scene.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-scene.Tpo $(DEPDIR)/3Depict-scene.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/scene.cpp' object='3Depict-scene.obj' libtool=no @AMDEPBACKSLASH@ @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-clusterAnalysis.obj `if test -f 'filters/clusterAnalysis.cpp'; then $(CYGPATH_W) 'filters/clusterAnalysis.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/clusterAnalysis.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-scene.obj `if test -f 'gl/scene.cpp'; then $(CYGPATH_W) 'gl/scene.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/scene.cpp'; fi` -3Depict-ionInfo.o: filters/ionInfo.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionInfo.o -MD -MP -MF $(DEPDIR)/3Depict-ionInfo.Tpo -c -o 3Depict-ionInfo.o `test -f 'filters/ionInfo.cpp' || echo '$(srcdir)/'`filters/ionInfo.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionInfo.Tpo $(DEPDIR)/3Depict-ionInfo.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionInfo.cpp' object='3Depict-ionInfo.o' libtool=no @AMDEPBACKSLASH@ +3Depict-drawables.o: gl/drawables.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-drawables.o -MD -MP -MF $(DEPDIR)/3Depict-drawables.Tpo -c -o 3Depict-drawables.o `test -f 'gl/drawables.cpp' || echo '$(srcdir)/'`gl/drawables.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-drawables.Tpo $(DEPDIR)/3Depict-drawables.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/drawables.cpp' object='3Depict-drawables.o' libtool=no @AMDEPBACKSLASH@ @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-ionInfo.o `test -f 'filters/ionInfo.cpp' || echo '$(srcdir)/'`filters/ionInfo.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-drawables.o `test -f 'gl/drawables.cpp' || echo '$(srcdir)/'`gl/drawables.cpp -3Depict-ionInfo.obj: filters/ionInfo.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-ionInfo.obj -MD -MP -MF $(DEPDIR)/3Depict-ionInfo.Tpo -c -o 3Depict-ionInfo.obj `if test -f 'filters/ionInfo.cpp'; then $(CYGPATH_W) 'filters/ionInfo.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionInfo.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-ionInfo.Tpo $(DEPDIR)/3Depict-ionInfo.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/ionInfo.cpp' object='3Depict-ionInfo.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-drawables.obj: gl/drawables.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-drawables.obj -MD -MP -MF $(DEPDIR)/3Depict-drawables.Tpo -c -o 3Depict-drawables.obj `if test -f 'gl/drawables.cpp'; then $(CYGPATH_W) 'gl/drawables.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/drawables.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-drawables.Tpo $(DEPDIR)/3Depict-drawables.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/drawables.cpp' object='3Depict-drawables.obj' libtool=no @AMDEPBACKSLASH@ @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-ionInfo.obj `if test -f 'filters/ionInfo.cpp'; then $(CYGPATH_W) 'filters/ionInfo.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/ionInfo.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-drawables.obj `if test -f 'gl/drawables.cpp'; then $(CYGPATH_W) 'gl/drawables.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/drawables.cpp'; fi` -3Depict-annotation.o: filters/annotation.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-annotation.o -MD -MP -MF $(DEPDIR)/3Depict-annotation.Tpo -c -o 3Depict-annotation.o `test -f 'filters/annotation.cpp' || echo '$(srcdir)/'`filters/annotation.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-annotation.Tpo $(DEPDIR)/3Depict-annotation.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/annotation.cpp' object='3Depict-annotation.o' libtool=no @AMDEPBACKSLASH@ +3Depict-effect.o: gl/effect.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-effect.o -MD -MP -MF $(DEPDIR)/3Depict-effect.Tpo -c -o 3Depict-effect.o `test -f 'gl/effect.cpp' || echo '$(srcdir)/'`gl/effect.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-effect.Tpo $(DEPDIR)/3Depict-effect.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/effect.cpp' object='3Depict-effect.o' libtool=no @AMDEPBACKSLASH@ @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-annotation.o `test -f 'filters/annotation.cpp' || echo '$(srcdir)/'`filters/annotation.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-effect.o `test -f 'gl/effect.cpp' || echo '$(srcdir)/'`gl/effect.cpp -3Depict-annotation.obj: filters/annotation.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-annotation.obj -MD -MP -MF $(DEPDIR)/3Depict-annotation.Tpo -c -o 3Depict-annotation.obj `if test -f 'filters/annotation.cpp'; then $(CYGPATH_W) 'filters/annotation.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/annotation.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-annotation.Tpo $(DEPDIR)/3Depict-annotation.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filters/annotation.cpp' object='3Depict-annotation.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-effect.obj: gl/effect.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-effect.obj -MD -MP -MF $(DEPDIR)/3Depict-effect.Tpo -c -o 3Depict-effect.obj `if test -f 'gl/effect.cpp'; then $(CYGPATH_W) 'gl/effect.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/effect.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-effect.Tpo $(DEPDIR)/3Depict-effect.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/effect.cpp' object='3Depict-effect.obj' libtool=no @AMDEPBACKSLASH@ @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-annotation.obj `if test -f 'filters/annotation.cpp'; then $(CYGPATH_W) 'filters/annotation.cpp'; else $(CYGPATH_W) '$(srcdir)/filters/annotation.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-effect.obj `if test -f 'gl/effect.cpp'; then $(CYGPATH_W) 'gl/effect.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/effect.cpp'; fi` -3Depict-testing.o: testing.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-testing.o -MD -MP -MF $(DEPDIR)/3Depict-testing.Tpo -c -o 3Depict-testing.o `test -f 'testing.cpp' || echo '$(srcdir)/'`testing.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-testing.Tpo $(DEPDIR)/3Depict-testing.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testing.cpp' object='3Depict-testing.o' libtool=no @AMDEPBACKSLASH@ +3Depict-textures.o: gl/textures.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-textures.o -MD -MP -MF $(DEPDIR)/3Depict-textures.Tpo -c -o 3Depict-textures.o `test -f 'gl/textures.cpp' || echo '$(srcdir)/'`gl/textures.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-textures.Tpo $(DEPDIR)/3Depict-textures.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/textures.cpp' object='3Depict-textures.o' libtool=no @AMDEPBACKSLASH@ @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-testing.o `test -f 'testing.cpp' || echo '$(srcdir)/'`testing.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-textures.o `test -f 'gl/textures.cpp' || echo '$(srcdir)/'`gl/textures.cpp -3Depict-testing.obj: testing.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-testing.obj -MD -MP -MF $(DEPDIR)/3Depict-testing.Tpo -c -o 3Depict-testing.obj `if test -f 'testing.cpp'; then $(CYGPATH_W) 'testing.cpp'; else $(CYGPATH_W) '$(srcdir)/testing.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-testing.Tpo $(DEPDIR)/3Depict-testing.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testing.cpp' object='3Depict-testing.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-textures.obj: gl/textures.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-textures.obj -MD -MP -MF $(DEPDIR)/3Depict-textures.Tpo -c -o 3Depict-textures.obj `if test -f 'gl/textures.cpp'; then $(CYGPATH_W) 'gl/textures.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/textures.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-textures.Tpo $(DEPDIR)/3Depict-textures.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/textures.cpp' object='3Depict-textures.obj' libtool=no @AMDEPBACKSLASH@ @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-testing.obj `if test -f 'testing.cpp'; then $(CYGPATH_W) 'testing.cpp'; else $(CYGPATH_W) '$(srcdir)/testing.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-textures.obj `if test -f 'gl/textures.cpp'; then $(CYGPATH_W) 'gl/textures.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/textures.cpp'; fi` -3Depict-3Depict.o: 3Depict.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-3Depict.o -MD -MP -MF $(DEPDIR)/3Depict-3Depict.Tpo -c -o 3Depict-3Depict.o `test -f '3Depict.cpp' || echo '$(srcdir)/'`3Depict.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-3Depict.Tpo $(DEPDIR)/3Depict-3Depict.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='3Depict.cpp' object='3Depict-3Depict.o' libtool=no @AMDEPBACKSLASH@ +3Depict-select.o: gl/select.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-select.o -MD -MP -MF $(DEPDIR)/3Depict-select.Tpo -c -o 3Depict-select.o `test -f 'gl/select.cpp' || echo '$(srcdir)/'`gl/select.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-select.Tpo $(DEPDIR)/3Depict-select.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/select.cpp' object='3Depict-select.o' libtool=no @AMDEPBACKSLASH@ @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-3Depict.o `test -f '3Depict.cpp' || echo '$(srcdir)/'`3Depict.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-select.o `test -f 'gl/select.cpp' || echo '$(srcdir)/'`gl/select.cpp -3Depict-3Depict.obj: 3Depict.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-3Depict.obj -MD -MP -MF $(DEPDIR)/3Depict-3Depict.Tpo -c -o 3Depict-3Depict.obj `if test -f '3Depict.cpp'; then $(CYGPATH_W) '3Depict.cpp'; else $(CYGPATH_W) '$(srcdir)/3Depict.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-3Depict.Tpo $(DEPDIR)/3Depict-3Depict.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='3Depict.cpp' object='3Depict-3Depict.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-select.obj: gl/select.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-select.obj -MD -MP -MF $(DEPDIR)/3Depict-select.Tpo -c -o 3Depict-select.obj `if test -f 'gl/select.cpp'; then $(CYGPATH_W) 'gl/select.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/select.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-select.Tpo $(DEPDIR)/3Depict-select.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/select.cpp' object='3Depict-select.obj' libtool=no @AMDEPBACKSLASH@ @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-3Depict.obj `if test -f '3Depict.cpp'; then $(CYGPATH_W) '3Depict.cpp'; else $(CYGPATH_W) '$(srcdir)/3Depict.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-select.obj `if test -f 'gl/select.cpp'; then $(CYGPATH_W) 'gl/select.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/select.cpp'; fi` -3Depict-basics.o: basics.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-basics.o -MD -MP -MF $(DEPDIR)/3Depict-basics.Tpo -c -o 3Depict-basics.o `test -f 'basics.cpp' || echo '$(srcdir)/'`basics.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-basics.Tpo $(DEPDIR)/3Depict-basics.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='basics.cpp' object='3Depict-basics.o' libtool=no @AMDEPBACKSLASH@ +3Depict-cameras.o: gl/cameras.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cameras.o -MD -MP -MF $(DEPDIR)/3Depict-cameras.Tpo -c -o 3Depict-cameras.o `test -f 'gl/cameras.cpp' || echo '$(srcdir)/'`gl/cameras.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cameras.Tpo $(DEPDIR)/3Depict-cameras.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/cameras.cpp' object='3Depict-cameras.o' libtool=no @AMDEPBACKSLASH@ @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.o `test -f 'basics.cpp' || echo '$(srcdir)/'`basics.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-cameras.o `test -f 'gl/cameras.cpp' || echo '$(srcdir)/'`gl/cameras.cpp -3Depict-basics.obj: basics.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-basics.obj -MD -MP -MF $(DEPDIR)/3Depict-basics.Tpo -c -o 3Depict-basics.obj `if test -f 'basics.cpp'; then $(CYGPATH_W) 'basics.cpp'; else $(CYGPATH_W) '$(srcdir)/basics.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-basics.Tpo $(DEPDIR)/3Depict-basics.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='basics.cpp' object='3Depict-basics.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-cameras.obj: gl/cameras.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-cameras.obj -MD -MP -MF $(DEPDIR)/3Depict-cameras.Tpo -c -o 3Depict-cameras.obj `if test -f 'gl/cameras.cpp'; then $(CYGPATH_W) 'gl/cameras.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/cameras.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-cameras.Tpo $(DEPDIR)/3Depict-cameras.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/cameras.cpp' object='3Depict-cameras.obj' libtool=no @AMDEPBACKSLASH@ @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 'basics.cpp'; then $(CYGPATH_W) 'basics.cpp'; else $(CYGPATH_W) '$(srcdir)/basics.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-cameras.obj `if test -f 'gl/cameras.cpp'; then $(CYGPATH_W) 'gl/cameras.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/cameras.cpp'; fi` -3Depict-glPane.o: glPane.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-glPane.o -MD -MP -MF $(DEPDIR)/3Depict-glPane.Tpo -c -o 3Depict-glPane.o `test -f 'glPane.cpp' || echo '$(srcdir)/'`glPane.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-glPane.Tpo $(DEPDIR)/3Depict-glPane.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='glPane.cpp' object='3Depict-glPane.o' libtool=no @AMDEPBACKSLASH@ +3Depict-isoSurface.o: gl/isoSurface.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-isoSurface.o -MD -MP -MF $(DEPDIR)/3Depict-isoSurface.Tpo -c -o 3Depict-isoSurface.o `test -f 'gl/isoSurface.cpp' || echo '$(srcdir)/'`gl/isoSurface.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-isoSurface.Tpo $(DEPDIR)/3Depict-isoSurface.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/isoSurface.cpp' object='3Depict-isoSurface.o' libtool=no @AMDEPBACKSLASH@ @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-glPane.o `test -f 'glPane.cpp' || echo '$(srcdir)/'`glPane.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-isoSurface.o `test -f 'gl/isoSurface.cpp' || echo '$(srcdir)/'`gl/isoSurface.cpp -3Depict-glPane.obj: glPane.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-glPane.obj -MD -MP -MF $(DEPDIR)/3Depict-glPane.Tpo -c -o 3Depict-glPane.obj `if test -f 'glPane.cpp'; then $(CYGPATH_W) 'glPane.cpp'; else $(CYGPATH_W) '$(srcdir)/glPane.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-glPane.Tpo $(DEPDIR)/3Depict-glPane.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='glPane.cpp' object='3Depict-glPane.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-isoSurface.obj: gl/isoSurface.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-isoSurface.obj -MD -MP -MF $(DEPDIR)/3Depict-isoSurface.Tpo -c -o 3Depict-isoSurface.obj `if test -f 'gl/isoSurface.cpp'; then $(CYGPATH_W) 'gl/isoSurface.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/isoSurface.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-isoSurface.Tpo $(DEPDIR)/3Depict-isoSurface.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gl/isoSurface.cpp' object='3Depict-isoSurface.obj' libtool=no @AMDEPBACKSLASH@ @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-glPane.obj `if test -f 'glPane.cpp'; then $(CYGPATH_W) 'glPane.cpp'; else $(CYGPATH_W) '$(srcdir)/glPane.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-isoSurface.obj `if test -f 'gl/isoSurface.cpp'; then $(CYGPATH_W) 'gl/isoSurface.cpp'; else $(CYGPATH_W) '$(srcdir)/gl/isoSurface.cpp'; fi` -3Depict-scene.o: scene.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-scene.o -MD -MP -MF $(DEPDIR)/3Depict-scene.Tpo -c -o 3Depict-scene.o `test -f 'scene.cpp' || echo '$(srcdir)/'`scene.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-scene.Tpo $(DEPDIR)/3Depict-scene.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='scene.cpp' object='3Depict-scene.o' libtool=no @AMDEPBACKSLASH@ +3Depict-stringFuncs.o: common/stringFuncs.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-stringFuncs.o -MD -MP -MF $(DEPDIR)/3Depict-stringFuncs.Tpo -c -o 3Depict-stringFuncs.o `test -f 'common/stringFuncs.cpp' || echo '$(srcdir)/'`common/stringFuncs.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-stringFuncs.Tpo $(DEPDIR)/3Depict-stringFuncs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/stringFuncs.cpp' object='3Depict-stringFuncs.o' libtool=no @AMDEPBACKSLASH@ @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-scene.o `test -f 'scene.cpp' || echo '$(srcdir)/'`scene.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-stringFuncs.o `test -f 'common/stringFuncs.cpp' || echo '$(srcdir)/'`common/stringFuncs.cpp -3Depict-scene.obj: scene.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-scene.obj -MD -MP -MF $(DEPDIR)/3Depict-scene.Tpo -c -o 3Depict-scene.obj `if test -f 'scene.cpp'; then $(CYGPATH_W) 'scene.cpp'; else $(CYGPATH_W) '$(srcdir)/scene.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-scene.Tpo $(DEPDIR)/3Depict-scene.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='scene.cpp' object='3Depict-scene.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-stringFuncs.obj: common/stringFuncs.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-stringFuncs.obj -MD -MP -MF $(DEPDIR)/3Depict-stringFuncs.Tpo -c -o 3Depict-stringFuncs.obj `if test -f 'common/stringFuncs.cpp'; then $(CYGPATH_W) 'common/stringFuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/common/stringFuncs.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-stringFuncs.Tpo $(DEPDIR)/3Depict-stringFuncs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/stringFuncs.cpp' object='3Depict-stringFuncs.obj' libtool=no @AMDEPBACKSLASH@ @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-scene.obj `if test -f 'scene.cpp'; then $(CYGPATH_W) 'scene.cpp'; else $(CYGPATH_W) '$(srcdir)/scene.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-stringFuncs.obj `if test -f 'common/stringFuncs.cpp'; then $(CYGPATH_W) 'common/stringFuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/common/stringFuncs.cpp'; fi` -3Depict-viscontrol.o: viscontrol.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-viscontrol.o -MD -MP -MF $(DEPDIR)/3Depict-viscontrol.Tpo -c -o 3Depict-viscontrol.o `test -f 'viscontrol.cpp' || echo '$(srcdir)/'`viscontrol.cpp -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-viscontrol.Tpo $(DEPDIR)/3Depict-viscontrol.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='viscontrol.cpp' object='3Depict-viscontrol.o' libtool=no @AMDEPBACKSLASH@ +3Depict-xmlHelper.o: common/xmlHelper.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-xmlHelper.o -MD -MP -MF $(DEPDIR)/3Depict-xmlHelper.Tpo -c -o 3Depict-xmlHelper.o `test -f 'common/xmlHelper.cpp' || echo '$(srcdir)/'`common/xmlHelper.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-xmlHelper.Tpo $(DEPDIR)/3Depict-xmlHelper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/xmlHelper.cpp' object='3Depict-xmlHelper.o' libtool=no @AMDEPBACKSLASH@ @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.o `test -f 'viscontrol.cpp' || echo '$(srcdir)/'`viscontrol.cpp +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-xmlHelper.o `test -f 'common/xmlHelper.cpp' || echo '$(srcdir)/'`common/xmlHelper.cpp -3Depict-viscontrol.obj: viscontrol.cpp -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-viscontrol.obj -MD -MP -MF $(DEPDIR)/3Depict-viscontrol.Tpo -c -o 3Depict-viscontrol.obj `if test -f 'viscontrol.cpp'; then $(CYGPATH_W) 'viscontrol.cpp'; else $(CYGPATH_W) '$(srcdir)/viscontrol.cpp'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-viscontrol.Tpo $(DEPDIR)/3Depict-viscontrol.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='viscontrol.cpp' object='3Depict-viscontrol.obj' libtool=no @AMDEPBACKSLASH@ +3Depict-xmlHelper.obj: common/xmlHelper.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-xmlHelper.obj -MD -MP -MF $(DEPDIR)/3Depict-xmlHelper.Tpo -c -o 3Depict-xmlHelper.obj `if test -f 'common/xmlHelper.cpp'; then $(CYGPATH_W) 'common/xmlHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/common/xmlHelper.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-xmlHelper.Tpo $(DEPDIR)/3Depict-xmlHelper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/xmlHelper.cpp' object='3Depict-xmlHelper.obj' libtool=no @AMDEPBACKSLASH@ +@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-xmlHelper.obj `if test -f 'common/xmlHelper.cpp'; then $(CYGPATH_W) 'common/xmlHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/common/xmlHelper.cpp'; fi` + +3Depict-colourmap.o: common/colourmap.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourmap.o -MD -MP -MF $(DEPDIR)/3Depict-colourmap.Tpo -c -o 3Depict-colourmap.o `test -f 'common/colourmap.cpp' || echo '$(srcdir)/'`common/colourmap.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourmap.Tpo $(DEPDIR)/3Depict-colourmap.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/colourmap.cpp' object='3Depict-colourmap.o' libtool=no @AMDEPBACKSLASH@ +@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-colourmap.o `test -f 'common/colourmap.cpp' || echo '$(srcdir)/'`common/colourmap.cpp + +3Depict-colourmap.obj: common/colourmap.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-colourmap.obj -MD -MP -MF $(DEPDIR)/3Depict-colourmap.Tpo -c -o 3Depict-colourmap.obj `if test -f 'common/colourmap.cpp'; then $(CYGPATH_W) 'common/colourmap.cpp'; else $(CYGPATH_W) '$(srcdir)/common/colourmap.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-colourmap.Tpo $(DEPDIR)/3Depict-colourmap.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/colourmap.cpp' object='3Depict-colourmap.obj' libtool=no @AMDEPBACKSLASH@ +@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-colourmap.obj `if test -f 'common/colourmap.cpp'; then $(CYGPATH_W) 'common/colourmap.cpp'; else $(CYGPATH_W) '$(srcdir)/common/colourmap.cpp'; fi` + +3Depict-voxels.o: common/voxels.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-voxels.o -MD -MP -MF $(DEPDIR)/3Depict-voxels.Tpo -c -o 3Depict-voxels.o `test -f 'common/voxels.cpp' || echo '$(srcdir)/'`common/voxels.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-voxels.Tpo $(DEPDIR)/3Depict-voxels.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/voxels.cpp' object='3Depict-voxels.o' libtool=no @AMDEPBACKSLASH@ +@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-voxels.o `test -f 'common/voxels.cpp' || echo '$(srcdir)/'`common/voxels.cpp + +3Depict-voxels.obj: common/voxels.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-voxels.obj -MD -MP -MF $(DEPDIR)/3Depict-voxels.Tpo -c -o 3Depict-voxels.obj `if test -f 'common/voxels.cpp'; then $(CYGPATH_W) 'common/voxels.cpp'; else $(CYGPATH_W) '$(srcdir)/common/voxels.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-voxels.Tpo $(DEPDIR)/3Depict-voxels.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/voxels.cpp' object='3Depict-voxels.obj' libtool=no @AMDEPBACKSLASH@ @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 'viscontrol.cpp'; then $(CYGPATH_W) 'viscontrol.cpp'; else $(CYGPATH_W) '$(srcdir)/viscontrol.cpp'; fi` +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-voxels.obj `if test -f 'common/voxels.cpp'; then $(CYGPATH_W) 'common/voxels.cpp'; else $(CYGPATH_W) '$(srcdir)/common/voxels.cpp'; fi` + +3Depict-mathfuncs.o: common/mathfuncs.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathfuncs.o -MD -MP -MF $(DEPDIR)/3Depict-mathfuncs.Tpo -c -o 3Depict-mathfuncs.o `test -f 'common/mathfuncs.cpp' || echo '$(srcdir)/'`common/mathfuncs.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mathfuncs.Tpo $(DEPDIR)/3Depict-mathfuncs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/mathfuncs.cpp' object='3Depict-mathfuncs.o' libtool=no @AMDEPBACKSLASH@ +@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-mathfuncs.o `test -f 'common/mathfuncs.cpp' || echo '$(srcdir)/'`common/mathfuncs.cpp + +3Depict-mathfuncs.obj: common/mathfuncs.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-mathfuncs.obj -MD -MP -MF $(DEPDIR)/3Depict-mathfuncs.Tpo -c -o 3Depict-mathfuncs.obj `if test -f 'common/mathfuncs.cpp'; then $(CYGPATH_W) 'common/mathfuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mathfuncs.cpp'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-mathfuncs.Tpo $(DEPDIR)/3Depict-mathfuncs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/mathfuncs.cpp' object='3Depict-mathfuncs.obj' libtool=no @AMDEPBACKSLASH@ +@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-mathfuncs.obj `if test -f 'common/mathfuncs.cpp'; then $(CYGPATH_W) 'common/mathfuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mathfuncs.cpp'; fi` + +3Depict-basics.o: common/basics.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-basics.o -MD -MP -MF $(DEPDIR)/3Depict-basics.Tpo -c -o 3Depict-basics.o `test -f 'common/basics.cpp' || echo '$(srcdir)/'`common/basics.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-basics.Tpo $(DEPDIR)/3Depict-basics.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/basics.cpp' object='3Depict-basics.o' libtool=no @AMDEPBACKSLASH@ +@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.o `test -f 'common/basics.cpp' || echo '$(srcdir)/'`common/basics.cpp + +3Depict-basics.obj: common/basics.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT 3Depict-basics.obj -MD -MP -MF $(DEPDIR)/3Depict-basics.Tpo -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` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/3Depict-basics.Tpo $(DEPDIR)/3Depict-basics.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='common/basics.cpp' object='3Depict-basics.obj' libtool=no @AMDEPBACKSLASH@ +@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 @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 @@ -1497,15 +1601,13 @@ fi; \ done check-am: all-am -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-am +check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-am +install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am @@ -1535,7 +1637,6 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am @@ -1605,7 +1706,7 @@ uninstall-am: uninstall-binPROGRAMS -.MAKE: all check install install-am install-strip +.MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic ctags distclean distclean-compile \ @@ -1625,11 +1726,6 @@ $(WX_RESCOMP) $^ -o $@ %.o : %.rc $(WX_RESCOMP) $^ -o $@ -@USE_PRECOMPILED_HEADERS_TRUE@%.hh.gch: %.hh -@USE_PRECOMPILED_HEADERS_TRUE@ $(CXXCOMPILE) $(3Depict_CXXFLAGS)-c $< - -@USE_PRECOMPILED_HEADERS_TRUE@%.h.gch: %.h -@USE_PRECOMPILED_HEADERS_TRUE@ $(CXXCOMPILE) $(3Depict_CXXFLAGS) -c $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff -Nru 3depict-0.0.12/src/animator.cpp 3depict-0.0.13/src/animator.cpp --- 3depict-0.0.12/src/animator.cpp 2012-11-18 15:41:14.000000000 +0000 +++ 3depict-0.0.13/src/animator.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,442 +0,0 @@ -#include "animator.h" - -const char *INTERP_NAME[] ={ "Step", - "Linear", - "RGB Linear", - "List", - "3D Linear" - "3D Step" -}; - -PropertyAnimator::PropertyAnimator() -{ -} - -size_t PropertyAnimator::getMaxFrame() const -{ - size_t maxFrame=0; - - for(size_t ui=0; ui &vec) -{ - std::sort(vec.begin(),vec.end()); - - //FIXME: LAME!! Very inefficient - for(size_t ui=vec.size()-1;ui--;) - removeNthKeyFrame(ui); - -} - -void PropertyAnimator::getPropertiesAtFrame(size_t keyframe, - vector &propIds, - vector &props) const -{ - -#ifdef DEBUG - std::set conflicts; - ASSERT(checkSelfConsistent(conflicts)); -#endif - - std::set seenIds; - - //Find the frames that are active - for(size_t ui=0;ui= keyframe - && keyFrames[ui].getMinFrame() <=keyframe) - { - propIds.push_back(ui); - props.push_back(keyFrames[ui]); - seenIds.insert(keyFrames[ui].getFilterId()); - } - } - - //Map the filter Id's to the most recently active keyframe - map bestFrames; - - //Find the frames that have been active, and not overridden by a newer frame - // and are thus still in effect - for(size_t ui=0;uikeyframe) - continue; - - //OK, so we could be active, or there could be a newer - //frame in effect we haven't seen - if(bestFrames.find(filterId)==bestFrames.end()) - { - bestFrames[filterId] = ui; - continue; - } - - if(maxFrame >=keyFrames[bestFrames[filterId]].getMaxFrame()) - { - bestFrames[filterId]=ui; - continue; - } - } - - //Now sweep up all the best frames - for(map::iterator it=bestFrames.begin(); it!=bestFrames.end(); ++it) - { - propIds.push_back(it->second); - props.push_back(keyFrames[it->second]); - } - -} - -bool PropertyAnimator::checkSelfConsistent(std::set &conflictFrames) const -{ - for(size_t ui=0;ui conflicts; - ASSERT(checkSelfConsistent(conflicts)); -#endif - //Search for the unique keyframe that alters our target property - for(size_t ui=0;ui=keyFrames[ui].getMinFrame() && - frame <=keyFrames[ui].getMaxFrame() ) - { - keyFrameId=ui; - break; - } - } - - if(keyFrameId==(size_t)-1) - { - //So there is no interpolated data within this run - // check again for a "latest" modified version - // and "hold" that value to generate our interpolated result - - //First in pair is frame ID, second is max frame that this occured at - std::vector > seenFrames; - for(size_t ui=0;ui::max(); - - for(size_t ui=0; ui > &keyData,size_t frame) const -{ - - std::string resStr; - - switch(interpMode) - { - case INTERP_STEP: - case INTERP_STEP_POINT3D: - { - ASSERT(keyData.size() ==1); - - ASSERT(keyData[0].first==frame) - - return keyData[0].second; - } - case INTERP_LINEAR_FLOAT: - { - ASSERT(keyData.size() ==2); - - float a, b; - size_t startF,endF; - - //Either way around, it should succesfully - // transfer - ASSERT(!stream_cast(a,keyData[0].second)); - ASSERT(!stream_cast(b,keyData[1].second)); - - //Flip the key data such that it is the correct way 'round - if(keyData[0].first < keyData[1].first) - { - stream_cast(a,keyData[0].second); - stream_cast(b,keyData[1].second); - startF=keyData[0].first; - endF=keyData[1].first; - } - else - { - stream_cast(a,keyData[1].second); - stream_cast(b,keyData[0].second); - startF=keyData[0].first; - endF=keyData[1].first; - } - - //Obtain the linearly interpolated result - float res; - res=interpLinearRamp(startF,endF,frame,a,b); - - stream_cast(resStr,res); - return resStr; - } - case INTERP_LINEAR_COLOUR: - { - ASSERT(keyData.size() ==2); - //TODO: I don't have the internets here, - // so I can't look up the RGB->HSV interpolation - // matrix. HSV interpolation should look more natural - - //Perform linear RGB interpolation - - //Parse the colour start and end strings - //--------- - float colStart[4]; - float colEnd[4]; - - unsigned char r,g,b,alpha; - ASSERT(parseColString(keyData[0].second,r,g,b,alpha)); - ASSERT(parseColString(keyData[1].second,r,g,b,alpha)); - - parseColString(keyData[0].second,r,g,b,alpha); - alpha=255; - - colStart[0] = r/255.0f; - colStart[1] = g/255.0f; - colStart[2] = b/255.0f; - colStart[3] = alpha/255.0f; - - - parseColString(keyData[1].second,r,g,b,alpha); - - - colEnd[0] = r/255.0f; - colEnd[1] = g/255.0f; - colEnd[2] = b/255.0f; - colEnd[3] = alpha/255.0f; - - //--------- - - //Get and flip the key data such that it is the correct way 'round - size_t startF,endF; - if(keyData[0].first < keyData[1].first) - { - startF=keyData[0].first; - endF=keyData[1].first; - } - else - { - startF=keyData[1].first; - endF=keyData[0].first; - } - - //interpolate the colour value - unsigned char colInterp[4]; - for(size_t ui=0; ui<4;ui++) - { - float tmp; - tmp=(unsigned char)(interpLinearRamp(startF,endF,frame, - colStart[ui],colEnd[ui])*255.0f); - - ASSERT(tmp <256); - ASSERT(tmp >=0); - colInterp[ui] = tmp; - } - - std::string s; - genColString(colInterp[0],colInterp[1],colInterp[2], - colInterp[3],s); - return s; - } - case INTERP_LIST: - { - ASSERT(keyData.size()); - - size_t frameOffset=keyData[0].first; - ASSERT(frame-frameOffset =startFrame && curFrame <=endFrame); - - float frac; - frac = ((float)(curFrame-startFrame)) / (float)(endFrame - startFrame); - - return frac*(b-a) + a; -} diff -Nru 3depict-0.0.12/src/animator.h 3depict-0.0.13/src/animator.h --- 3depict-0.0.12/src/animator.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/animator.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/* - * animator.h - animation classes for 3Depict - * Copyright (C) 2012, 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 . - */ -#ifndef ANIMATOR_H -#define ANIMATOR_H - -#include "filter.h" -#include "basics.h" - -#include - -enum -{ - INTERP_STEP, - INTERP_LINEAR_FLOAT, - INTERP_LINEAR_COLOUR, - INTERP_LIST, - INTERP_LINEAR_POINT3D, - INTERP_STEP_POINT3D, - INTERP_END -}; - -extern const char *INTERP_NAME[]; - -class FrameProperties; - - -class InterpData -{ - public: - size_t interpMode; - - //!Obtain the interpolated data at the specified frame, - // for the properties given as a parameter. - // should only be called for frames that lie within the interpolated - // range - std::string getInterpolatedData(const vector > &keyData,size_t frame) const; - - float interpLinearRamp(size_t startFrame, size_t endFrame, size_t curFrame, - float a, float b) const; -}; - -//!Frame-by-frame properties for a specific filter -class FrameProperties -{ - private: - //ID of the filter that whose properties are to be altered - size_t filterId; - - //Property Key for filter - size_t propertyKey; - //!First in pair is frame offset, second is property at that frame - vector > frameData; - - //!Interpolation information - InterpData interpData; - public: - FrameProperties() {}; - FrameProperties(size_t filterIdVal,size_t propertyKeyVal); - ~FrameProperties(); - - //!Get the minimal frame (which is affected) - size_t getMinFrame() const; - //!Get tha maximal frame (which is affected) - size_t getMaxFrame() const; - - //!Add a key frame to the dataset - void addKeyFrame(size_t frame, const FilterProperty &p); - - //Set the interpolation mode - void setInterpMode(size_t mode) {ASSERT(mode keyFrames; - public: - PropertyAnimator(); - - //!Are the properties self-consistent - returns true if OK - bool checkSelfConsistent(std::set &conflictingFrames) const; - - //!Obtain the maximal frame for animation - size_t getMaxFrame() const; - - //!Get all the properties that intersect or precede - // a particular keyframe. - void getPropertiesAtFrame(size_t keyframe, vector &propIds, - vector &props) const; - - //Obtain the as-animated version of a specific filter for a particular frame. - // returns empty string if the filter ID/key is not known. - // Otherwise returns best-effort interpolated data - std::string getInterpolatedFilterData(size_t id, size_t propKey, size_t frame) const; - - //-- Data modification funcs -- - //!Add a property to the list of available props - void addProp(const FrameProperties &p) { keyFrames.push_back(p);} - //!Set a particlar property - void setProp(size_t id, const FrameProperties &p); - - //!Remove frame by its unique ID - void removeProp(size_t id); - - //!Remove all stored information - void clear(); - - //!Get the number of properties stored - size_t getNumProps() const { return keyFrames.size();} - - - //Obtain the frame property by its position - void getNthKeyFrame(size_t frameNum,FrameProperties &f) const { ASSERT(frameNum < keyFrames.size()); f=keyFrames[frameNum];}; - - //Remove this particular keyframe - void removeNthKeyFrame(size_t frameNum); - - //Remove the specified key frames. Input vector contents will be sorted. - void removeKeyFrames(vector &vec); - -}; - - - -#endif - diff -Nru 3depict-0.0.12/src/art.h 3depict-0.0.13/src/art.h --- 3depict-0.0.12/src/art.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/art.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * art.h - Program icons header - * 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 - * 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 . - */ - -#ifndef ART_H -#define ART_H - -#include - -#include "3Depict.xpm" - -class MyArtProvider : public wxArtProvider -{ - public: - MyArtProvider() {} - virtual ~MyArtProvider() {} - - protected: - wxBitmap CreateBitmap(const wxArtID& id, - const wxArtClient& client, - const wxSize& size) - { - if (id == _T("MY_ART_ID_ICON")) - return wxBitmap(_Depict); - - wxBitmap b; - return b; - - } -}; - -#endif // ART_H diff -Nru 3depict-0.0.12/src/assertion.h 3depict-0.0.13/src/assertion.h --- 3depict-0.0.12/src/assertion.h 2012-11-17 22:21:19.000000000 +0000 +++ 3depict-0.0.13/src/assertion.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* - * assertion.h - Program assertion header - * 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 - * 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 . - */ - -#ifndef ASSERTION_H -#define ASSERTION_H - -#ifdef DEBUG - #include "eventlogger.h" - #include - #include - - - void dh_assert(const char * const filename, const unsigned int lineNumber); - void dh_warn(const char * const filename, const unsigned int lineNumber, - const char *message); - - #ifndef ASSERT - #define ASSERT(f) if(!(f)) {dh_assert(__FILE__,__LINE__);} - #endif - - #ifndef WARN - #define WARN(f,g) if(!(f)) { dh_warn(__FILE__,__LINE__,g);} - #endif - - inline void dh_assert(const char * const filename, const unsigned int lineNumber) - { - extern EventLogger evtlog; - evtlog.dump(); - std::cerr << "ASSERTION ERROR!" << std::endl; - std::cerr << "Filename: " << filename << std::endl; - std::cerr << "Line number: " << lineNumber << std::endl; - - std::cerr << "Do you wish to continue?(y/n)"; - char y = 'a'; - while (y != 'n' && y != 'y') - std::cin >> y; - - if (y != 'y') - exit(1); - } - - inline void dh_warn(const char * const filename, const unsigned int lineNumber,const char *message) - { - std::cerr << "Warning to programmer." << std::endl; - std::cerr << "Filename: " << filename << std::endl; - std::cerr << "Line number: " << lineNumber << std::endl; - std::cerr << message << std::endl; - } - - //Debug timing routines - #define DEBUG_TIME_START timeval TIME_DEBUG_t; gettimeofday(&TIME_DEBUG_t,NULL); - #define DEBUG_TIME_END timeval TIME_DEBUG_tend; gettimeofday(&TIME_DEBUG_tend,NULL); \ - 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; - - //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)) { cerr << "Test fail :" << __FILE__ << ":" << __LINE__ << "\t"<< g << endl;return false;} - #endif - - //A hack to generate compile time asserts (thanks Internet). - //This causes gcc to give "duplicate case value", if the predicate is false - #define COMPILE_ASSERT(pred) \ - switch(0){case 0:case pred:;} - - -#else - #define ASSERT(f) - #define COMPILE_ASSERT(f) - #define WARN(f,g) - #define glError() -#endif - -#endif diff -Nru 3depict-0.0.12/src/backend/APT/APTClasses.cpp 3depict-0.0.13/src/backend/APT/APTClasses.cpp --- 3depict-0.0.12/src/backend/APT/APTClasses.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/APT/APTClasses.cpp 2013-04-10 20:38:01.000000000 +0000 @@ -0,0 +1,861 @@ +/* + * APTClasses.h - Generic APT components code + * 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 . + */ + +#include "APTClasses.h" +#include "../../common/stringFuncs.h" + +#include "../../common/translation.h" + + +using std::pair; +using std::string; +using std::vector; +using std::ifstream; +using std::make_pair; + +const char *POS_ERR_STRINGS[] = { "", + NTRANS("Memory allocation failure on POS load"), + NTRANS("Error opening pos file"), + NTRANS("Pos file empty"), + NTRANS("Pos file size appears to have non-integer number of entries"), + NTRANS("Error reading from pos file (after open)"), + NTRANS("Error - Found NaN in pos file"), + NTRANS("Pos load aborted by interrupt.") +}; + +enum +{ + TEXT_ERR_OPEN=1, + TEXT_ERR_ONLY_HEADER, + TEXT_ERR_REOPEN, + TEXT_ERR_READ_CONTENTS, + TEXT_ERR_FORMAT, + TEXT_ERR_NUM_FIELDS, + TEXT_ERR_ALLOC_FAIL, + TEXT_ERR_ENUM_END //not an error, just end of enum +}; + +const char *ION_TEXT_ERR_STRINGS[] = { "", + NTRANS("Error opening file"), + NTRANS("No numerical data found"), + NTRANS("Error re-opening file, after first scan"), + NTRANS("Unable to read file contents after open"), + NTRANS("Error interpreting field in file"), + 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 &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 &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 &ions, vector &p) +{ + p.resize(ions.size()); +#pragma omp parallel for + for(size_t ui=0;ui &posIons,const char *posFile, size_t limitCount, + unsigned int &progress, bool (*callback)(bool),bool strongSampling) +{ + + //Function is only defined for 4 columns here. + ASSERT(outputnumcols == 4); + //buffersize must be a power of two and at least outputnumcols*sizeof(float) + const unsigned int NUMROWS=1; + const unsigned int BUFFERSIZE=inputnumcols * sizeof(float) * NUMROWS; + const unsigned int BUFFERSIZE2=outputnumcols * sizeof(float) * NUMROWS; + char *buffer=new char[BUFFERSIZE]; + + + if(!buffer) + return POS_ALLOC_FAIL; + + char *buffer2=new char[BUFFERSIZE2]; + if(!buffer2) + { + delete[] buffer; + return POS_ALLOC_FAIL; + } + + //open pos file + std::ifstream CFile(posFile,std::ios::binary); + + if(!CFile) + { + delete[] buffer; + delete[] buffer2; + return POS_OPEN_FAIL; + } + + CFile.seekg(0,std::ios::end); + size_t fileSize=CFile.tellg(); + + if(!fileSize) + { + delete[] buffer; + delete[] buffer2; + return POS_EMPTY_FAIL; + } + + CFile.seekg(0,std::ios::beg); + + //calculate the number of points stored in the POS file + size_t pointCount=0; + size_t maxIons; + size_t maxCols = inputnumcols * sizeof(float); + //regular case + + if(fileSize % maxCols) + { + delete[] buffer; + delete[] buffer2; + return POS_SIZE_MODULUS_ERR; + } + + maxIons =fileSize/maxCols; + limitCount=std::min(limitCount,maxIons); + + //If we are going to load the whole file, don't use a sampling method to do it. + if(limitCount == maxIons) + { + //Close the file + CFile.close(); + delete[] buffer; + delete[] buffer2; + //Try opening it using the normal functions + return GenericLoadFloatFile(inputnumcols, outputnumcols, index, posIons,posFile,progress, callback); + } + + //Use a sampling method to load the pos file + std::vector ionsToLoad; + try + { + posIons.resize(limitCount); + + RandNumGen rng; + rng.initTimer(); + unsigned int dummy; + randomDigitSelection(ionsToLoad,maxIons,rng, + limitCount,dummy,callback,strongSampling); + } + catch(std::bad_alloc) + { + delete[] buffer; + delete[] buffer2; + return POS_ALLOC_FAIL; + } + + + //sort again + GreaterWithCallback g(callback,PROGRESS_REDUCE); + std::sort(ionsToLoad.begin(),ionsToLoad.end(),g); + + unsigned int curProg = PROGRESS_REDUCE; + + //TODO: probably not very nice to the disk drive. would be better to + //scan ahead for contiguous data regions, and load that where possible. + //Or switch between different algorithms based upon ionsToLoad.size()/ + std::ios::pos_type nextIonPos; + for(size_t ui=0;ui &posIons,const char *posFile, + unsigned int &progress, bool (*callback)(bool)) +{ + ASSERT(outputnumcols==4); //Due to ionHit.setHit + //buffersize must be a power of two and at least sizeof(float)*outputnumCols + const unsigned int NUMROWS=512; + const unsigned int BUFFERSIZE=inputnumcols * sizeof(float) * NUMROWS; + const unsigned int BUFFERSIZE2=outputnumcols * sizeof(float) * NUMROWS; + + char *buffer=new char[BUFFERSIZE]; + + if(!buffer) + return POS_ALLOC_FAIL; + + char *buffer2=new char[BUFFERSIZE2]; + if(!buffer2) + { + delete[] buffer; + return POS_ALLOC_FAIL; + } + //open pos file + std::ifstream CFile(posFile,std::ios::binary); + + if(!CFile) + { + delete[] buffer; + delete[] buffer2; + return POS_OPEN_FAIL; + } + + CFile.seekg(0,std::ios::end); + size_t fileSize=CFile.tellg(); + + if(!fileSize) + { + delete[] buffer; + delete[] buffer2; + return POS_EMPTY_FAIL; + } + + CFile.seekg(0,std::ios::beg); + + //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; + size_t curBufferSize2=BUFFERSIZE2; + + if(fileSize % (inputnumcols * sizeof(float))) + { + delete[] buffer; + delete[] buffer2; + return POS_SIZE_MODULUS_ERR; + } + + try + { + posIons.resize(fileSize/(inputnumcols*sizeof(float))); + } + catch(std::bad_alloc) + { + delete[] buffer; + delete[] buffer2; + return POS_ALLOC_FAIL; + } + + + while(fileSize < curBufferSize) { + curBufferSize = curBufferSize >> 1; + curBufferSize2 = curBufferSize2 >> 1; + } + + //Technically this is dependent upon the buffer size. + unsigned int curProg = 10000; + size_t ionP=0; + int maxCols = inputnumcols * sizeof(float); + int maxPosCols = outputnumcols * sizeof(float); + do + { + //Taking curBufferSize chunks at a time, read the input file + while((size_t)CFile.tellg() <= fileSize-curBufferSize) + { + CFile.read(buffer,curBufferSize); + if(!CFile.good()) + { + delete[] buffer; + delete[] buffer2; + return POS_READ_FAIL; + } + + for (unsigned int j = 0; j < NUMROWS; j++) // iterate through rows + { + for (unsigned int i = 0; i < outputnumcols; i++) // iterate through floats + { + memcpy(&(buffer2[j * maxPosCols + i * sizeof(float)]), + &(buffer[j * maxCols + index[i] * sizeof(float)]), sizeof(float)); + } + } + + unsigned int ui; + for(ui=0; ui> 1 ; + curBufferSize2 = curBufferSize2 >> 1 ; + }while(curBufferSize2 >= sizeof(IONHIT)); + + ASSERT((unsigned int)CFile.tellg() == fileSize); + delete[] buffer; + delete[] buffer2; + + return 0; +} + + +//TODO: Add progress +unsigned int limitLoadTextFile(unsigned int numColsTotal, unsigned int selectedCols[], + vector &posIons,const char *textFile, const char *delim, const size_t limitCount, + unsigned int &progress, bool (*callback)(bool),bool strongRandom) +{ + + ASSERT(numColsTotal); + ASSERT(textFile); + + vector newLinePositions; + std::vector subStrs; + + //Do a brute force scan through the dataset + //to locate newlines. + char *buffer; + const int BUFFER_SIZE=16384; //This is totally a guess. I don't know what is best. + + + //sort the selected columns into increasing order + vector sortedCols; + for(unsigned int ui=0;ui=subStrs.size()) + { + enoughSubStrs=false; + break; + } + } + + if(!enoughSubStrs) + continue; + + //Unable to stream + bool unStreamable; + unStreamable=false; + for(unsigned int ui=0; ui=maxPos) + return TEXT_ERR_ONLY_HEADER; + + + CFile.close(); + + //Re-open the file in binary mode to find the newlines + CFile.open(textFile,std::ios::binary); + + if(!CFile) + return TEXT_ERR_REOPEN; + + + //Jump to beyond the header + CFile.seekg(curPos); + + + //keep a beginning of file marker + newLinePositions.push_back(curPos); + bool seenNumeric=false; + buffer = new char[BUFFER_SIZE]; + while(!CFile.eof() && curPos < maxPos) + { + size_t bytesToRead; + + if(!CFile.good()) + { + delete[] buffer; + return TEXT_ERR_READ_CONTENTS; + } + //read up to BUFFER_SIZE bytes from the file + //but only if they are available + bytesToRead = std::min(maxPos-curPos,(size_t)BUFFER_SIZE); + + CFile.read(buffer,bytesToRead); + + //check that this buffer contains numeric info + for(unsigned int ui=0;ui= '0' && buffer[ui] <='9') + seenNumeric=true; + } + + curPos+=bytesToRead; + + } + + //Don't keep any newline that hits the end of the file, but do keep a zero position + if(newLinePositions.size()) + newLinePositions.pop_back(); + CFile.close(); + + + //OK, so now we know where those pesky endlines are. This gives us jump positions + //to new lines in the file. Each component must have some form of numeric data + //preceding it. That numeric data may not be fully parseable, but we assume it is until we know better. + // + //If it is *not* parseable, just throw an error when we find that out. + + //If we are going to load the whole file, don't use a sampling method to do it. + if(limitCount >=newLinePositions.size()) + { + delete[] buffer; + + vector > data; + vector header; + + //Just use the non-sampling method to load. + if(loadTextData(textFile,data,header,delim)) + return TEXT_ERR_FORMAT; + + if(data.size() !=4) + return TEXT_ERR_NUM_FIELDS; + + posIons.resize(data[0].size()); + for(size_t ui=0;ui dataToLoad; + try + { + posIons.resize(limitCount); + + RandNumGen rng; + rng.initTimer(); + unsigned int dummy; + randomDigitSelection(dataToLoad,newLinePositions.size(),rng, + limitCount,dummy,callback,strongRandom); + } + catch(std::bad_alloc) + { + delete[] buffer; + return TEXT_ERR_ALLOC_FAIL; + } + + + //Sort the data such that we are going to + //always jump forwards in the file; better disk access and whatnot. + GreaterWithCallback g(callback,PROGRESS_REDUCE); + std::sort(dataToLoad.begin(),dataToLoad.end(),g); + + //OK, so we have a list of newlines + //that we can use as entry points for random seek. + //We also have some random entry points (sorted). + // Now re-open the file in text mode and try to load the + // data specified at the offsets + + + //Open file in text mode + CFile.open(textFile); + + if(!CFile) + { + delete[] buffer; + return TEXT_ERR_REOPEN; + } + + + //OK, now jump to each of the random positions, + //as dictated by the endline position + //and attempt a parsing there. + + subStrs.clear(); + for(size_t ui=0;ui &points,Point3D ¢roid) +{ + //TODO: Paralellise me + centroid=Point3D(0,0,0); + for(unsigned int ui=0;ui &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::max(); + bounds[ui][1]=-std::numeric_limits::max(); + } + + for(unsigned int ui=0; ui 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 cubes; + + unsigned int nT=omp_get_max_threads(); + cubes.resize(nT); + for(unsigned int ui=0;ui. + */ + +#ifndef APTCLASSES_H +#define APTCLASSES_H + +#include "common/basics.h" + +#include //memcpy +#include //std::bad_alloc + +//!Allowable export ion formats +enum +{ + IONFORMAT_POS=1 +}; + +using std::vector; + +class IonHit; +class Point3D; + + +const unsigned int PROGRESS_REDUCE=5000; + +extern const char *POS_ERR_STRINGS[]; + +extern const char *ION_TEXT_ERR_STRINGS[]; + +//!Errors that can be encountered when openning pos files +enum posErrors +{ + POS_ALLOC_FAIL=1, + POS_OPEN_FAIL, + POS_EMPTY_FAIL, + POS_SIZE_MODULUS_ERR, + POS_READ_FAIL, + POS_NAN_LOAD_ERROR, + POS_ABORT_FAIL, + POS_ERR_FINAL // Not actually an error, but tells us where the end of the num is. +}; + + +//!make a pos file from a set of a set of IonHits +unsigned int IonVectorToPos(const vector &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 &ions, vector &pts); + +//!make/append to a pos file from a set of a set of IonHits +void appendPos(const vector &points, const char *name); + +//!Set the bounds from an array of ion hits +BoundCube getIonDataLimits(const vector &p);// + +//!Get the sum of all Point3Ds in an ion vector +void getPointSum(const std::vector &points,Point3D ¢roid); + +//!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 +/*! Pos files are fixed record size files, with data stored as 4byte + * big endian floating point. (IEEE 574?). Data is stored as + * x,y,z,mass/charge. + * */ +//!Load a pos file into a T of IonHits +unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int outputnumcols, + unsigned int index[], vector &posIons,const char *posFile, + unsigned int &progress, bool (*callback)(bool)); + + +unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, unsigned int index[], + vector &posIons,const char *posFile, size_t limitCount, + unsigned int &progress, bool (*callback)(bool),bool strongRandom); + + + +unsigned int limitLoadTextFile(unsigned int numColsTotal, unsigned int selectedCols[], + vector &posIons,const char *posFile, const char *deliminator, const size_t limitCount, + unsigned int &progress, bool (*callback)(bool),bool strongRandom); + + +#endif diff -Nru 3depict-0.0.12/src/backend/APT/APTRanges.cpp 3depict-0.0.13/src/backend/APT/APTRanges.cpp --- 3depict-0.0.12/src/backend/APT/APTRanges.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/APT/APTRanges.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -0,0 +1,2278 @@ +/* + * APTRanges.cpp - Atom probe rangefile 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 . + */ + + + +#include "APTRanges.h" + +#include "../../common/constants.h" +#include "../../common/stringFuncs.h" +#include "../../common/translation.h" + +#include +#include +#include + +using std::string; +using std::vector; +using std::pair; +using std::make_pair; +using std::map; +using std::accumulate; + + +const char *rangeErrStrings[] = +{ + "", + NTRANS("Error opening file, check name and permissions."), + NTRANS("Error interpreting range file header, expecting ion count and range count, respectively."), + NTRANS("Range file appears to be empty, check file is a proper range file and is not empty."), + NTRANS("Error reading the long name for ion."), + 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("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"), + NTRANS("Unable to read range table entry"), + NTRANS("Error reading file, unexpected format, are you sure it is a proper range file?"), + NTRANS("Too many ranges appeared to have range entries with no usable data (eg, all blank)"), + 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."), +}; + +const char *RANGE_EXTS[] = { "rng", + "rrng", + "env", + ""}; + + +//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 > &fragments) +{ + size_t lastMarker=0; + size_t digitMarker=0; + + if(!name.size()) + return true; + + //Atomic naming systems use uppercase ascii + // letters, like "A" in Au, or Ag as delimiters. + // + // numerals are multipliers, and are forbidden + // for the first char... + if(!isascii(name[0]) || + isdigit(name[0]) || islower(name[0])) + return false; + + //true - was last, or now am on ion name + //false - am still on multiplier + int nameMode=true; + for(size_t ui=1;ui &composedNames, + + const vector > &namesToFind, size_t &matchOffset) +{ + //Decomposition of composed names. + std::vector > > fragmentVec; + + //break each composed name into a vector of decomposed fragments + // and the multiplicity + //of that fragment (eg, AuHg2 would become { Au ,1} {Hg,2}) + fragmentVec.reserve(composedNames.size()); + for(std::map::const_iterator it=composedNames.begin(); + it!=composedNames.end();++it) + { + vector > frags; + if(!decomposeIonNames(it->first,frags)) + frags.clear(); + + + fragmentVec.push_back(frags); + + frags.clear(); + } + + + //Try to match all fragments in "namesToFind" (name-frequency pairings) + //in the master list of fragments of + // which consists of the decomposed composed names (fragmentVec entries) + + //If the decomposed fragments wholly constitute the + //master list, then thats good, and we have a match. + //Note that the master list will not necessarily be in + //the same order as the fragment list + //match tally for fragments + + + vector excludedMatch; + excludedMatch.resize(fragmentVec.size(),false); + + for(size_t uj=0;uj curFrag; + curFrag=namesToFind[uj]; + for(size_t ui=0;ui 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)) + { + 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 namePair; + + //Read ion short and full names as well as colour info + for(unsigned int i=0; i + 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; + } + + + vector colHeaders; + splitStrsRef(inBuffer,' ',colHeaders); + + //remove whitespace from each entry + for(size_t ui=0;ui 1) + { + + if(colHeaders.size() -1 !=numIons) + { + // Emit warning + delete[] inBuffer; + return RANGE_ERR_FORMAT_TABLESEPARATOR; + } + + //Strip any trailing newlines off the last of the colheaders, + // to avoid dos->unix conversion problems + std::string str = colHeaders[colHeaders.size() -1]; + + if(str[str.size() -1 ] == '\n') + colHeaders[colHeaders.size()-1]=str.substr(0,str.size()-1); + + //Each column header should match the original ion name + for(size_t ui=1;ui frequencyEntries; + frequencyEntries.clear(); + frequencyEntries.resize(numRanges*numIons,0); + //Load in each range file line + tempInt=0; + pair massPair; + + for(unsigned int i=0; i entries; + std::string tmpStr; + tmpStr=stripWhite(inBuffer); + + splitStrsRef(tmpStr.c_str()," ",entries); + stripZeroEntries(entries); + + //Should be two entries for the mass pair, + // one entry per ion, and optionally one + // entry for the marker (not used) + if(entries.size() != numIons + 2 && + entries.size() !=numIons+3) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT_RANGETABLE; + } + + size_t entryOff; + entryOff=0; + //if we have a leading entry, ignore it + if(entries.size() == numIons +3) + entryOff=1; + + 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 + + entryOff+=2; + for(unsigned int j=0; j composeMap; + + for(size_t uj=0;uj freqEntries; + size_t freq; + + freqEntries.clear(); + freq=0; + for(size_t uj=0;ujfirst); + } + 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 > entries; + + for(map::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 strVec; + + //Read file until we get beyond the range length + while(!beyondRanges && !feof(fpRange) ) + { + if(!fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange) + || strlen(inBuffer) >=MAX_LINE_SIZE-1) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + //Trick to "strip" the buffer + nullifyMarker(inBuffer,'#'); + + string s; + s=inBuffer; + + s=stripWhite(s); + + if(!s.size()) + continue; + + //Try different delimiters to split string + splitStrsRef(s.c_str(),"\t ",strVec); + + stripZeroEntries(strVec); + + if(strVec.empty()) + continue; + + if(!haveNumRanges) + { + //num ranges should have two entries, num ions and ranges + if(strVec.size() != 2) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + if(stream_cast(numIons,strVec[0])) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + if(stream_cast(numRanges,strVec[1])) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + haveNumRanges=true; + } + else + { + //Do we still have to process the name block? + if(!haveNameBlock) + { + //Just exiting name block, + if(strVec.size() == 5) + haveNameBlock=true; + else if(strVec.size() == 4) + { + //Entry in name block + if(!strVec[0].size()) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + //Check that name consists only of + //readable ascii chars, or period + for(unsigned int ui=0; ui1.0 || colourStruct.red < 0.0f || + colourStruct.green >1.0 || colourStruct.green < 0.0f || + colourStruct.blue >1.0 || colourStruct.blue < 0.0f ) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + + } + + + colours.push_back(colourStruct); + } + else + { + //Well thats not right, + //we should be looking at the first entry in the + //range block.... + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + } + + if(haveNameBlock) + { + //We are finished + if(strVec.size() == 5) + { + unsigned int thisIonID; + thisIonID=(unsigned int)-1; + for(unsigned int ui=0;ui basicIonNames; + + while (!feof(fpRange)) + { + if(!fgets((char *)inBuffer, MAX_LINE_SIZE, fpRange) + || strlen(inBuffer) >=MAX_LINE_SIZE-1) + break; + //Trick to "strip" the buffer, assuming # is a comment + nullifyMarker(inBuffer,'#'); + + string s; + s=inBuffer; + + s=stripWhite(s); + if (!s.size()) + continue; + + if (s == "[Ions]") + { + curBlock=BLOCK_IONS; + continue; + } + else if (s == "[Ranges]") + { + curBlock=BLOCK_RANGES; + continue; + } + + switch (curBlock) + { + case BLOCK_NONE: + break; + case BLOCK_IONS: + { + + //The ion section in RRNG seems almost completely redundant. + //This does not actually contain information about the ions + //in the file (this is in the ranges section). + //Rather it tells you what the constituents are from which + //complex ions may be formed. Apply Palm to Face. + + vector split; + splitStrsRef(s.c_str(),'=',split); + + if (split.size() != 2) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + std::string stmp; + stmp=lowercase(split[0]); + + haveSeenIonBlock=true; + + + if (stmp == "number") + { + //Should not have set the + //number of ions yet. + if (numBasicIons !=0) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + //Set the number of ions + if(stream_cast(numBasicIons, split[1])) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + if (numBasicIons == 0) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + } + else if (split[0].size() >3) + { + stmp = lowercase(split[0].substr(0,3)); + if (stmp == "ion") + { + //OK, its an ion. + basicIonNames.push_back(split[1]); + + if (basicIonNames.size() > numBasicIons) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + } + else + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + } + break; + } + case BLOCK_RANGES: + { + //Although it looks like the blocks are independent. + //it is more complicated to juggle a parser with them + //out of dependency order, as a second pass would + //need to be done. + if (!haveSeenIonBlock) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + vector split; + + if (s.size() > 6) + { + splitStrsRef(s.c_str(),'=',split); + + if (split.size() != 2) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + if (lowercase(split[0].substr(0,5)) == "numbe") + { + + //Should not have set the num ranges yet + if (numRanges) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + if (stream_cast(numRanges,split[1])) + { + + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + if (!numRanges) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + } + else if ( lowercase(split[0].substr(0,5)) == "range") + { + //Try to decode a range line, as best we can. + //These appear to come in a variety of flavours, + //which makes this section quite long. + + //OK, so the format here is a bit weird + //we first have to strip the = bit + //then we have to step across fields, + //I assume the fields are in order (or missing) + //* denotes 0 or more, + denotes 1 or more, brackets denote grouping + // Vol: [0-9]* ([A-z]+: [0-9]+)* (Name:[0-9]*([A-z]+[0-9]*)+ Color:[0-F][0-F][0-F][0-F][0-F][0-F] + // Examples: + // Range1=31.8372 32.2963 Vol:0.01521 Zn:1 Color:999999 + // or + // Range1=31.8372 32.2963 Zn:1 Color:999999 + // or + // Range1=95.3100 95.5800 Vol:0.04542 Zn:1 Sb:1 Color:00FFFF + // or + // Range1=95.3100 95.5800 Vol:0.04542 Name:1Zn1Sb1 Color:00FFFF + // or + // Range1=95.3100 95.5800 Vol:0.04542 Zn:1 Sb:1 Name:1Zn1Sb1 Color:00FFFF + // or + // Range1= 95.3100 95.5800 Color:00FFFF Vol:0.04542 Zn:1 Sb:1 Name:1Zn1Sb1 + + //Starting positions (string index) + //of range start and end + //Range1=31.8372 32.2963 Vol:0.01521 Zn:1 Color:999999 + // ^rngmid ^rngend + size_t rngMidIdx,rngEndIdx; + string rngStart,rngEnd; + split[1]=stripWhite(split[1]); + rngMidIdx = split[1].find_first_of(' '); + + if (rngMidIdx == std::string::npos) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + rngEndIdx=split[1].find_first_of(' ',rngMidIdx+1); + if (rngEndIdx == std::string::npos) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + rngStart = split[1].substr(0,rngMidIdx); + rngEnd = split[1].substr(rngMidIdx+1,rngEndIdx-(rngMidIdx+1)); + + + //Strip the range + string strTmp; + strTmp = split[1].substr(rngEndIdx+1);//,split[1].size()-(rngEndIdx+1)); + + //Split the remaining field into key:value pairs + split.clear(); + splitStrsRef(strTmp.c_str(),' ',split); + + stripZeroEntries(split); + RGBf col; + bool haveColour,haveNameField; + haveColour=false; + haveNameField=false; + string strIonNameTmp,strNameFieldValue; + + for (unsigned int ui=0; ui 0 + unsigned int uintVal; + if (stream_cast(uintVal,value) || !uintVal) + { + delete[] inBuffer; + return RANGE_ERR_FORMAT; + } + + //If it is 1, then use straight name. Otherwise try to give it a + //chemical formula look by mixing in the multiplicity after the key + if (uintVal==1) + strIonNameTmp+=key; + else + strIonNameTmp+=key+value; + } + } + + if (!haveColour ) + { + //Okay, so a colour wasn't provided. + // to make our users lives a bit less + // boring, lets just use some semi-random ones + col.red=rand()/(float)std::numeric_limits::max(); + col.green=rand()/(float)std::numeric_limits::max(); + col.blue=rand()/(float)std::numeric_limits::max(); + + } + + //Get the range values + float rngStartV,rngEndV; + if(strIonNameTmp.size() || haveNameField) + { + if (stream_cast(rngStartV,rngStart)) + { + delete[] inBuffer; + + return RANGE_ERR_FORMAT; + } + + if (stream_cast(rngEndV,rngEnd)) + { + delete[] inBuffer; + + return RANGE_ERR_FORMAT; + } + } + + //So the ion field appears to be optional (that is, + //ivas emits RRNGs that do not contain an ion listed in the + //ion field). It is unclear what the purpose of these lines is, + //so we shall ignore it, in preference to aborting + if(strIonNameTmp.size()) + { + //Check to see if we have this ion. + //If we don't, we create a new one. + //if we do, we check that the colours match + //and if not reject the file parsing. + unsigned int pos=(unsigned int)(-1); + for (unsigned int ui=0; ui '9') + { + chargeStrStop =ui; + break; + } + + } + + //Strip off the charge value, to get the ion name + strNameFieldValue =strNameFieldValue.substr(chargeStrStop,strNameFieldValue.size()-chargeStrStop); + + //Check to see if we have this ion. + //If we dont, we create a new one. + //if we do, we check that the colours match + //and if not reject the file parsing. + unsigned int pos=(unsigned int)(-1); + for (unsigned int ui=0; ui &exts) +{ + //subtract one for the guard terminator, which + // we do not want to return + exts.resize(THREEDEP_ARRAYSIZE(RANGE_EXTS)-1); + + for(unsigned int ui=0;ui ranges[uj].first && + ranges[ui].first < ranges[uj].second ) + return false; + if(ranges[ui].second > ranges[uj].first && + ranges[ui].second < ranges[uj].second ) + return false; + + //check for not spanning a range + if(ranges[ui].first < ranges[uj].first && + ranges[ui].second > ranges[uj].second) + return false; + + //Check for range duplication + if(ranges[ui].first == ranges[uj].first && + ranges[ui].second == ranges[uj].second) + return false; + + } + } + + return true; +} + +bool RangeFile::isRanged(float mass) const +{ + unsigned int numRanges = ranges.size(); + + for(unsigned int ui=0; ui= ranges[ui].first && + mass <= ranges[ui].second ) + return true; + } + + return false; +} + +bool RangeFile::isRanged(const IonHit &ion) const +{ + return isRanged(ion.getMassToCharge()); +} + +bool RangeFile::range(vector &ions, string ionShortName) +{ + vector rangedVec; + + //find the Ion ID of what we want + unsigned int targetIonID=(unsigned int)-1; + for(unsigned int ui=0; ui subRanges; + for(unsigned int ui=0; ui= ranges[subRanges[uj]].first && + ions[ui].getMassToCharge() <= ranges[subRanges[uj]].second ) + { + rangedVec.push_back(ions[ui]); + break; + } + } + } + + //Do the switcheroonie + //such that the un-ranged ions are destroyed + //and the ranged ions are kept + ions.swap(rangedVec); + return true; +} + +void RangeFile::range(vector &ions) +{ + vector rangedVec; + + unsigned int numIons=ions.size(); + rangedVec.reserve(numIons); + + for(unsigned int ui=0; ui &ions, unsigned int rangeID) +{ + vector rangedVec; + + unsigned int numIons=ions.size(); + rangedVec.reserve(numIons); + + for(unsigned int ui=0; ui= ranges[rangeID].first && + ions[ui].getMassToCharge() <= ranges[rangeID].second ) + { + rangedVec.push_back(ions[ui]); + break; + } + } + + //Do the switcheroonie + //such that the un-ranged ions are destroyed + //and the ranged ions are kept + ions.swap(rangedVec); +} + + +void RangeFile::printErr(std::ostream &strm) const +{ + ASSERT(errState < RANGE_ERR_ENUM_END); + strm < RangeFile::getRange(unsigned int ui) const +{ + return ranges[ui]; +} + +RGBf RangeFile::getColour(unsigned int ui) const +{ + ASSERT(ui < colours.size()); + return colours[ui]; +} + +unsigned int RangeFile::getIonID(float mass) const +{ + unsigned int numRanges = ranges.size(); + + for(unsigned int ui=0; ui= ranges[ui].first && + mass <= ranges[ui].second ) + return ionIDs[ui]; + } + + return (unsigned int)-1; +} + +unsigned int RangeFile::getRangeID(float mass) const +{ + unsigned int numRanges = ranges.size(); + + for(unsigned int ui=0; ui= ranges[ui].first && + mass <= ranges[ui].second ) + return ui; + } + + return (unsigned int)-1; +} + +unsigned int RangeFile::getIonID(unsigned int range) const +{ + ASSERT(range < ranges.size()); + + return ionIDs[range]; +} + +unsigned int RangeFile::getIonID(const char *name) const +{ + for(unsigned int ui=0; ui &ionHits, unsigned int rng) +{ + //This is a bit slack, could be faster, but should work. + return range(ionHits,ionNames[rng].first); +} + +bool RangeFile::isRanged(string shortName, bool caseSensitive) +{ + if(caseSensitive) + { + for(unsigned int ui=ionNames.size(); ui--; ) + { + if(ionNames[ui].first == shortName) + return true; + } + } + else + { + for(unsigned int ui=ionNames.size(); ui--; ) + { + //perform a series of case independent + //string comparisons + string str; + str = ionNames[ui].first; + + if(str.size() !=shortName.size()) + continue; + + bool next; + next=false; + for(unsigned int ui=str.size(); ui--; ) + { + if(tolower(str[ui]) != + tolower(shortName[ui])) + { + next=true; + break; + } + } + + if(!next) + return true; + } + } + + 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 ionIDs.size()) + return 0; + + string str= getName(ionID); + + for(unsigned int ui=0; ui= ranges[rangeId].second) + return false; + } + + //Check that moving this range will not cause any overlaps with + //other ranges + for(unsigned int ui=0; ui ranges[ui].first)) + return false; + + if((ranges[rangeId].first < ranges[ui].second && + newMass > ranges[ui].second)) + return false; + } + else + { + //moving low range + //check for overlap on first + if((ranges[rangeId].second > ranges[ui].first && + newMass < ranges[ui].first)) + return false; + + if((ranges[rangeId].second > ranges[ui].second && + newMass < ranges[ui].second)) + return false; + } + + } + + if(limit) + ranges[rangeId].second = newMass; + else + ranges[rangeId].first= newMass; + + return true; +} + +bool RangeFile::moveBothRanges(unsigned int rangeId, float newLow, float newHigh) +{ + + //Check that moving this range will not cause any overlaps with + //other ranges + for(unsigned int ui=0; ui ranges[ui].first)) + return false; + + if((ranges[rangeId].first < ranges[ui].second && + newHigh > ranges[ui].second)) + return false; + //moving low range + //check for overlap on first + if((ranges[rangeId].second > ranges[ui].first && + newLow < ranges[ui].first)) + return false; + + if((ranges[rangeId].second > ranges[ui].second && + newLow < ranges[ui].second)) + return false; + } + + ranges[rangeId].second = newHigh; + ranges[rangeId].first= newLow; + + return true; +} + + + +unsigned int RangeFile::addRange(float start, float end, unsigned int parentIonID) +{ + ASSERT(start < end); + //Ensure that they do NOT overlap + for(unsigned int ui=0;ui ranges[ui].first && + start<=ranges[ui].second) + return -1; + + if(end > ranges[ui].first && + end<=ranges[ui].second) + return -1; + + //check for start/end spanning range entirely + if(start < ranges[ui].first && end > ranges[ui].second) + return -1; + } + + //Got this far? Good - valid range. Insert it and move on + ionIDs.push_back(parentIonID); + ranges.push_back(std::make_pair(start,end)); + + ASSERT(isSelfConsistent()); + return ranges.size(); +} + +unsigned int RangeFile::addIon(std::string &shortN, std::string &longN, RGBf &newCol) +{ + for(unsigned int ui=9; ui. + */ + +#ifndef APTRANGES_H +#define APTRANGES_H + +#include "APTClasses.h" + +enum{ + RANGE_ERR_OPEN =1, + RANGE_ERR_FORMAT_HEADER, + RANGE_ERR_EMPTY, + RANGE_ERR_FORMAT_LONGNAME, + RANGE_ERR_FORMAT_SHORTNAME, + RANGE_ERR_FORMAT_COLOUR, + RANGE_ERR_FORMAT_TABLESEPARATOR, + RANGE_ERR_FORMAT_RANGE_DUMMYCHARS, + RANGE_ERR_FORMAT_RANGETABLE, + RANGE_ERR_FORMAT_MASS_PAIR, + RANGE_ERR_FORMAT_TABLE_ENTRY, + RANGE_ERR_FORMAT, + RANGE_ERR_DATA_TOO_MANY_USELESS_RANGES, + RANGE_ERR_DATA_FLIPPED, + RANGE_ERR_DATA_INCONSISTENT, + RANGE_ERR_DATA_NOMAPPED_IONNAME, + RANGE_ERR_ENUM_END +}; + +//!Data holder for colour as float +typedef struct RGBf +{ + float red; + float green; + float blue; +} RGBf; + +//Number of elements stored in the table +const unsigned int NUM_ELEMENTS=119; + +enum{ RANGE_FORMAT_ORNL=1, + RANGE_FORMAT_ENV, + RANGE_FORMAT_RRNG, + RANGE_FORMAT_END_OF_ENUM //not a format, just end of enumueration. +}; +//!Data storage and retrieval class for various range files +class RangeFile +{ + private: + //These vectors will contain the number of ions + + //The first element is the shortname for the Ion + //the second is the full name + std::vector > ionNames; + //This holds the colours for the ions + std::vector colours; + + //This will contains the number of ranges + // + //This holds the min and max masses for the range + std::vector > ranges; + //The ion ID number for each range + //FIXME: Convert to proper uniqueID system + std::vector ionIDs; + + unsigned int errState; + //Warning messages, used when loading rangefiles + std::vector warnMessages; + + + //!Erase the contents of the rangefile + void clear(); + + //!Performs limited checks for self consistency. + bool isSelfConsistent() const; + + //!Load an ORNL formatted "RNG" rangefile + // caller must supply and release file pointer + unsigned int openRNG(FILE *fp); + //!Load an RRNG file + // caller must supply and release file pointer + unsigned int openRRNG(FILE *fp); + //!Load an ENV file + // caller must supply and release file pointer + unsigned int openENV(FILE *fp); + + public: + RangeFile(); + //!Open a specified range file + unsigned int open(const char *rangeFile, unsigned int format=RANGE_FORMAT_ORNL); + //!Open a specified range file + 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. + static bool extensionIsRange(const char *ext); + //!Grab a vector that contains all the extensions that are valid for range files + static void getAllExts(std::vector &exts); + + //!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 + std::string getErrString() const; + //!Get the number of unique ranges + unsigned int getNumRanges() const; + //!Get the number of ranges for a given ion ID + unsigned int getNumRanges(unsigned int ionID) const; + //!Get the number of unique ions + unsigned int getNumIons() const; + //!Retrieve the start and end of a given range as a pair(start,end) + std::pair getRange(unsigned int ) const; + //!Retrieve a given colour from the ion ID + RGBf getColour(unsigned int) const; + //!Set the colour using the ion ID + void setColour(unsigned int, const RGBf &r); + + + //!Retrieve the colour from a given ion ID + + //!Get the ion's ID from a specified mass + /*! Returns the ions ID if there exists a range that + * contains this mass. Otherwise (unsigned int)-1 is returned + */ + unsigned int getIonID(float mass) const; + //!Get the ion ID from a given range ID + /*!No validation checks are performed outside debug mode. Ion + range *must* exist*/ + unsigned int getIonID(unsigned int range) const; + //!Get the ion ID from its short name + unsigned int getIonID(const char *name) const; + + //!Set the ion ID for a given range + void setIonID(unsigned int range, unsigned int newIonId); + + //!returns true if a specified mass is ranged + bool isRanged(float mass) const; + //! Returns true if an ion is ranged + bool isRanged(const IonHit &) const; + //!Clips out ions that are not inside the range + void range(std::vector &ionHits); + //!Clips out ions that dont match the specified ion name + /*! Returns false if the ion name given doesn't match + * any in the rangefile (case sensitive) + */ + bool range(std::vector &ionHits, + std::string shortIonName); + + //!Clips out ions that dont lie in the specified range number + /*! Returns false if the range does not exist + * any in the rangefile (case sensitive) + */ + bool rangeByID(std::vector &ionHits, + unsigned int range); + void rangeByRangeID(std::vector &ionHits, + unsigned int rangeID); + //!Get the short name or long name of a specified ionID + /*! Pass shortname=false to retireve the long name + * ionID passed in must exist. No checking outside debug mode + */ + std::string getName(unsigned int ionID,bool shortName=true) const; + + std::string getName(const IonHit &ion, bool shortName) const; + + //!set the short name for a given ion + void setIonShortName(unsigned int ionID, const std::string &newName); + + //!Set the long name for a given ion + void setIonLongName(unsigned int ionID, const std::string &newName); + + //!Check to see if an atom is ranged + /*! Returns true if rangefile holds at least one range with shortname + * corresponding input value. Case sensitivite search is default + */ + bool isRanged(std::string shortName, bool caseSensitive=true); + + //!Write the rangefile to the specified output stream (default ORNL format) + unsigned int write(std::ostream &o,size_t format=RANGE_FORMAT_ORNL) const; + //!WRite the rangefile to a file (ORNL format) + unsigned int write(const char *datafile, size_t format=RANGE_FORMAT_ORNL) const; + + //!Return the atomic number of the element from either the long or short version of the atomic name + /* + * Short name takes precedence + * + * Example : if range is "H" or "Hydrogen" function returns 1 + * Returns 0 on error (bad atomic name) + */ + unsigned int atomicNumberFromRange(unsigned int range) const; + + + //!Get atomic number from ion ID + unsigned int atomicNumberFromIonID(unsigned int ionID) const; + + //!Get a range ID from mass to charge + unsigned int getRangeID(float mass) const; + + //!Swap a range file with this one + void swap(RangeFile &rng); + + //!Move a range's mass to a new location + bool moveRange(unsigned int range, bool limit, float newMass); + //!Move both of a range's masses to a new location + bool moveBothRanges(unsigned int range, float newLow, float newHigh); + + //!Add a range to the rangefile. Returns ID number of added range + // if adding successful, (unsigned int)-1 otherwise + unsigned int addRange(float start, float end, unsigned int ionID); + + //Add the ion to the database returns ion ID if successful, -1 otherwise + unsigned int addIon(std::string &shortName, std::string &longName, RGBf &ionCol); + +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/animator.cpp 3depict-0.0.13/src/backend/animator.cpp --- 3depict-0.0.12/src/backend/animator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/animator.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,480 @@ +/* + * animatior.cpp - animation interopolator implementation + * 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 . +*/ + +#include "animator.h" +#include "common/stringFuncs.h" + +#include + +const char *INTERP_NAME[] ={ "Step", + "Linear", + "RGB Linear", + "List", + "3D Linear", + "3D Step" +}; + +PropertyAnimator::PropertyAnimator() +{ +} + +void PropertyAnimator::getNthKeyFrame(size_t frameNum,FrameProperties &f) const +{ + ASSERT(frameNum < keyFrames.size()); + f=keyFrames[frameNum]; +} + +size_t PropertyAnimator::getMaxFrame() const +{ + size_t maxFrame=0; + + for(size_t ui=0; ui &vec) +{ + std::sort(vec.begin(),vec.end()); + + //FIXME: LAME!! Very inefficient + for(size_t ui=vec.size();ui;) + { + ui--; + removeNthKeyFrame(vec[ui]); + } + +} + +void PropertyAnimator::getPropertiesAtFrame(size_t keyframe, + vector &propIds, + vector &props) const +{ + +#ifdef DEBUG + std::set conflicts; + ASSERT(checkSelfConsistent(conflicts)); +#endif + + std::set seenIds; + + //Find the frames that are active + for(size_t ui=0;ui= keyframe + && keyFrames[ui].getMinFrame() <=keyframe) + { + propIds.push_back(ui); + props.push_back(keyFrames[ui]); + seenIds.insert(keyFrames[ui].getFilterId()); + } + } + + //Map the filter Id's to the most recently active keyframe + map bestFrames; + + //Find the frames that have been active, and not overridden by a newer frame + // and are thus still in effect + for(size_t ui=0;uikeyframe) + continue; + + //OK, so we could be active, or there could be a newer + //frame in effect we haven't seen + if(bestFrames.find(filterId)==bestFrames.end()) + { + bestFrames[filterId] = ui; + continue; + } + + if(maxFrame >=keyFrames[bestFrames[filterId]].getMaxFrame()) + { + bestFrames[filterId]=ui; + continue; + } + } + + //Now sweep up all the best frames + for(map::iterator it=bestFrames.begin(); it!=bestFrames.end(); ++it) + { + propIds.push_back(it->second); + props.push_back(keyFrames[it->second]); + } + +} + +bool PropertyAnimator::checkSelfConsistent(std::set &conflictFrames) const +{ + for(size_t ui=0;ui conflicts; + ASSERT(checkSelfConsistent(conflicts)); +#endif + //Search for the unique keyframe that alters our target property + for(size_t ui=0;ui=keyFrames[ui].getMinFrame() && + frame <=keyFrames[ui].getMaxFrame() ) + { + keyFrameId=ui; + break; + } + } + + if(keyFrameId==(size_t)-1) + { + //So there is no interpolated data within this run + // check again for a "latest" modified version + // and "hold" that value to generate our interpolated result + + //First in pair is frame ID, second is max frame that this occurred at + std::vector > seenFrames; + for(size_t ui=0;ui::max(); + + for(size_t ui=0; ui > &keyData,size_t frame) const +{ + + std::string resStr; + + switch(interpMode) + { + case INTERP_STEP: + case INTERP_STEP_POINT3D: + { + ASSERT(keyData.size() ==1); + + ASSERT(keyData[0].first==frame) + + return keyData[0].second; + } + case INTERP_LINEAR_FLOAT: + { + ASSERT(keyData.size() ==2); + + float a, b; + size_t startF,endF; + + //Either way around, it should successfully + // transfer + ASSERT(!stream_cast(a,keyData[0].second)); + ASSERT(!stream_cast(b,keyData[1].second)); + + //Flip the key data such that it is the correct way 'round + if(keyData[0].first < keyData[1].first) + { + stream_cast(a,keyData[0].second); + stream_cast(b,keyData[1].second); + startF=keyData[0].first; + endF=keyData[1].first; + } + else + { + stream_cast(a,keyData[1].second); + stream_cast(b,keyData[0].second); + startF=keyData[0].first; + endF=keyData[1].first; + } + + //Obtain the linearly interpolated result + float res; + res=interpLinearRamp(startF,endF,frame,a,b); + + stream_cast(resStr,res); + return resStr; + } + case INTERP_LINEAR_COLOUR: + { + ASSERT(keyData.size() ==2); + //TODO: I don't have the internets here, + // so I can't look up the RGB->HSV interpolation + // matrix. HSV interpolation should look more natural + + //Perform linear RGB interpolation + + //Parse the colour start and end strings + //--------- + float colStart[4]; + float colEnd[4]; + + unsigned char r,g,b,alpha; + ASSERT(parseColString(keyData[0].second,r,g,b,alpha)); + ASSERT(parseColString(keyData[1].second,r,g,b,alpha)); + + parseColString(keyData[0].second,r,g,b,alpha); + alpha=255; + + colStart[0] = r/255.0f; + colStart[1] = g/255.0f; + colStart[2] = b/255.0f; + colStart[3] = alpha/255.0f; + + + parseColString(keyData[1].second,r,g,b,alpha); + + + colEnd[0] = r/255.0f; + colEnd[1] = g/255.0f; + colEnd[2] = b/255.0f; + colEnd[3] = alpha/255.0f; + + //--------- + + //Get and flip the key data such that it is the correct way 'round + size_t startF,endF; + if(keyData[0].first < keyData[1].first) + { + startF=keyData[0].first; + endF=keyData[1].first; + } + else + { + startF=keyData[1].first; + endF=keyData[0].first; + } + + //interpolate the colour value + unsigned char colInterp[4]; + for(size_t ui=0; ui<4;ui++) + { + float tmp; + tmp=(interpLinearRamp(startF,endF,frame, + colStart[ui],colEnd[ui])*255.0f); + + tmp = std::max(tmp,255.0f); + tmp=std::min(tmp,0.0f); + + colInterp[ui] = (unsigned char)tmp; + } + + std::string s; + genColString(colInterp[0],colInterp[1],colInterp[2], + colInterp[3],s); + return s; + } + case INTERP_LIST: + { + ASSERT(keyData.size()); + + size_t frameOffset=keyData[0].first; + ASSERT(frame-frameOffset =startFrame && curFrame <=endFrame); + + float frac; + frac = ((float)(curFrame-startFrame)) / (float)(endFrame - startFrame); + + return frac*(b-a) + a; +} diff -Nru 3depict-0.0.12/src/backend/animator.h 3depict-0.0.13/src/backend/animator.h --- 3depict-0.0.12/src/backend/animator.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/animator.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,154 @@ +/* + * animator.h - animation classes for 3Depict + * 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 . + */ +#ifndef ANIMATOR_H +#define ANIMATOR_H + +#include "filter.h" + +#include + +enum +{ + INTERP_STEP, + INTERP_LINEAR_FLOAT, + INTERP_LINEAR_COLOUR, + INTERP_LIST, + INTERP_LINEAR_POINT3D, + INTERP_STEP_POINT3D, + INTERP_END +}; + +extern const char *INTERP_NAME[]; + +class FrameProperties; + + +class InterpData +{ + public: + size_t interpMode; + + //!Obtain the interpolated data at the specified frame, + // for the properties given as a parameter. + // should only be called for frames that lie within the interpolated + // range + std::string getInterpolatedData(const vector > &keyData,size_t frame) const; + + float interpLinearRamp(size_t startFrame, size_t endFrame, size_t curFrame, + float a, float b) const; +}; + +//!Frame-by-frame properties for a specific filter +class FrameProperties +{ + private: + //ID of the filter that whose properties are to be altered + size_t filterId; + + //Property Key for filter + size_t propertyKey; + //!First in pair is frame offset, second is property at that frame + vector > frameData; + + //!Interpolation information + InterpData interpData; + public: + FrameProperties() {}; + FrameProperties(size_t filterIdVal,size_t propertyKeyVal); + ~FrameProperties(); + + //!Get the minimal frame (which is affected) + size_t getMinFrame() const; + //!Get tha maximal frame (which is affected) + size_t getMaxFrame() const; + + //!Add a key frame to the dataset + void addKeyFrame(size_t frame, const FilterProperty &p); + + //Set the interpolation mode + void setInterpMode(size_t mode) ; + + //obtain the interpolation method + size_t getInterpMode() const { return interpData.interpMode;}; + + size_t getFilterId() const { return filterId;} + size_t getPropertyKey() const { return propertyKey;} + + std::string getInterpolatedData(size_t frame) const + { return interpData.getInterpolatedData(frameData,frame);} + +}; + +//!Animation of filter properties +class PropertyAnimator +{ + private: + //Vector containing each properties new + // value/key pairing + vector keyFrames; + public: + PropertyAnimator(); + + //!Are the properties self-consistent - returns true if OK + bool checkSelfConsistent(std::set &conflictingFrames) const; + + //!Obtain the maximal frame for animation + size_t getMaxFrame() const; + + //!Get all the properties that intersect or precede + // a particular keyframe. + void getPropertiesAtFrame(size_t keyframe, vector &propIds, + vector &props) const; + + //Obtain the as-animated version of a specific filter for a particular frame. + // returns empty string if the filter ID/key is not known. + // Otherwise returns best-effort interpolated data + std::string getInterpolatedFilterData(size_t id, size_t propKey, size_t frame) const; + + //-- Data modification funcs -- + //!Add a property to the list of available props + void addProp(const FrameProperties &p) { keyFrames.push_back(p);} + //!Set a particlar property + void setProp(size_t id, const FrameProperties &p); + + //!Remove frame by its unique ID + void removeProp(size_t id); + + //!Remove all stored information + void clear(); + + //!Get the number of properties stored + size_t getNumProps() const { return keyFrames.size();} + + + //Obtain the frame property by its position + void getNthKeyFrame(size_t frameNum,FrameProperties &f) const ; + + //Remove this particular keyframe + void removeNthKeyFrame(size_t frameNum); + + //Remove the specified key frames. Input vector contents will be sorted. + void removeKeyFrames(vector &vec); + +}; + + + +#endif + diff -Nru 3depict-0.0.12/src/backend/configFile.cpp 3depict-0.0.13/src/backend/configFile.cpp --- 3depict-0.0.12/src/backend/configFile.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/configFile.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,705 @@ +/* + * configFile.cpp - User configuration loading/saving + * 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 . +*/ + +#include "configFile.h" +#include "wxcommon.h" + + +#include "backend/filters/allFilter.h" + +#include "common/stringFuncs.h" +#include "common/xmlHelper.h" + + + +const char *CONFIG_FILENAME="config.xml"; + +const unsigned int MAX_RECENT=9; + +const unsigned int MAX_MOUSE_PERCENT= 400; + + + +#include + + +using std::endl; +using std::string; + + +ConfigFile::ConfigFile() : configLoadOK(false), panelMode(CONFIG_PANELMODE_REMEMBER), + haveIntialAppSize(false), mouseZoomRatePercent(100),mouseMoveRatePercent(100), + allowOnline(true), allowOnlineVerCheck(true), leftRightSashPos(0), + topBottomSashPos(0),filterSashPos(0),plotListSashPos(0) + +{ +} + + +ConfigFile::~ConfigFile() +{ + for(unsigned int ui=0;ui MAX_RECENT) + recentFiles.pop_front(); +} + +void ConfigFile::getRecentFiles(std::vector &files) const +{ + files.resize(recentFiles.size()); + std::copy(recentFiles.begin(),recentFiles.end(),files.begin()); +} + +void ConfigFile::removeRecentFile(const std::string &str) +{ + std::deque::iterator it; + it=std::find(recentFiles.begin(),recentFiles.end(),str); + + if(it!=recentFiles.end()) + recentFiles.erase(it); +} + +void ConfigFile::getFilterDefaults(vector &defs) +{ + defs.resize(filterDefaults.size()); + std::copy(filterDefaults.begin(),filterDefaults.end(),defs.begin()); +} +void ConfigFile::setFilterDefaults(const vector &defs) +{ + for(unsigned int ui=0;uicanBeHazardous())); + } +} + + + +bool ConfigFile::getInitialAppSize(unsigned int &x, unsigned int &y) const +{ + if(haveIntialAppSize) + { + x=initialSizeX; + y=initialSizeY; + } + + return haveIntialAppSize; +} + +void ConfigFile::setInitialAppSize(unsigned int x, unsigned int y) +{ + haveIntialAppSize=true; + initialSizeX=x; + initialSizeY=y; +} + +Filter *ConfigFile::getDefaultFilter(unsigned int type) const +{ + for(unsigned int ui=0;uigetType()) + { + ASSERT(!filterDefaults[ui]->canBeHazardous()); + return filterDefaults[ui]->cloneUncached(); + } + } + + return makeFilter(type); +} + +unsigned int ConfigFile::read() +{ + string filename; + filename = getConfigDir() + std::string("/") + std::string(CONFIG_FILENAME); + + //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) + { + return CONFIG_ERR_NOPARSER; + } + + //Open the XML file again, but without DTD validation + doc = xmlCtxtReadFile(context, filename.c_str(), NULL, 0); + + if(!doc) + return CONFIG_ERR_NOFILE; + + //release the context + xmlFreeParserCtxt(context); + + //retrieve root node + xmlNodePtr nodePtr = xmlDocGetRootElement(doc); + + + try + { + std::stack nodeStack; + + //Umm where is our root node guys? + if(!nodePtr) + throw 1; + + //push root tag + nodeStack.push(nodePtr); + + //This *should* be an threeDepict state file + if(xmlStrcmp(nodePtr->name, (const xmlChar *)"threeDepictconfig")) + { + errMessage=TRANS("Config file present, but is not valid (root node test)"); + throw 1; + } + + //push root node + nodeStack.push(nodePtr); + nodePtr=nodePtr->xmlChildrenNode; + + //push not quite root tag + nodeStack.push(nodePtr); + if(!XMLHelpFwdToElem(nodePtr,"initialwinsize")) + { + if(XMLGetAttrib(nodePtr, initialSizeX, "width") && + XMLGetAttrib(nodePtr,initialSizeY,"height")) + { + if( initialSizeX >0 && initialSizeY > 0) + haveIntialAppSize=true; + } + } + nodePtr=nodeStack.top(); + nodeStack.pop(); + + + //Clean up current configuration + recentFiles.clear(); + + if(!XMLHelpFwdToElem(nodePtr,"recent")) + { + nodeStack.push(nodePtr); + nodePtr=nodePtr->xmlChildrenNode; + + + std::string thisName; + while(!XMLHelpFwdToElem(nodePtr,"file") && recentFiles.size() < MAX_RECENT) + { + xmlChar *xmlString; + + //read name of file + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); + if(!xmlString) + { + errMessage=TRANS("Unable to interpret recent file entry"); + throw 1; + } + thisName=(char *)xmlString; + + recentFiles.push_back(thisName); + + xmlFree(xmlString); + } + } + + //restore old node + nodePtr=nodeStack.top(); + nodeStack.pop(); + + //Advance and push + if(!nodePtr->next) + goto nodeptrEndJump; + + nodePtr=nodePtr->next; + nodeStack.push(nodePtr); + + if(!XMLHelpFwdToElem(nodePtr,"filterdefaults")) + { + nodePtr=nodePtr->xmlChildrenNode; + + if(nodePtr) + { + + + while(!XMLHelpNextType(nodePtr,XML_ELEMENT_NODE)) + { + string s; + + s=(char *)(nodePtr->name); + Filter *f; + f=makeFilter(s); + + if(!f) + { + errMessage=TRANS("Unable to determine filter type in defaults listing."); + throw 1; + } + + + //potentially hazardous filters cannot have their + //default properties altered. Quietly drop them + if(!f->canBeHazardous()) + { + nodeStack.push(nodePtr); + nodePtr=nodePtr->xmlChildrenNode; + if(f->readState(nodePtr)) + filterDefaults.push_back(f); + + nodePtr=nodeStack.top(); + nodeStack.pop(); + } + } + + } + } + + //restore old node + nodePtr=nodeStack.top(); + nodeStack.pop(); + + //Advance and push + if(!nodePtr->next) + goto nodeptrEndJump; + + nodePtr=nodePtr->next; + nodeStack.push(nodePtr); + if(!XMLHelpFwdToElem(nodePtr,"startuppanels")) + { + startupPanelView.resize(CONFIG_STARTUPPANEL_END_ENUM); + + std::string tmpStr; + xmlChar *xmlString; + xmlString=xmlGetProp(nodePtr,(xmlChar*)"mode"); + + if(xmlString) + { + tmpStr=(char*)xmlString; + stream_cast(panelMode,tmpStr); + + if(panelMode >=CONFIG_PANELMODE_END_ENUM) + panelMode=CONFIG_PANELMODE_NONE; + + xmlFree(xmlString); + } + + if(panelMode) + { + xmlString=xmlGetProp(nodePtr,(xmlChar*)"rawdata"); + if(xmlString) + { + + tmpStr=(char *)xmlString; + if(tmpStr == "1") + startupPanelView[CONFIG_STARTUPPANEL_RAWDATA]=true; + else + startupPanelView[CONFIG_STARTUPPANEL_RAWDATA]=false; + + xmlFree(xmlString); + } + + xmlString=xmlGetProp(nodePtr,(xmlChar*)"control"); + if(xmlString) + { + + tmpStr=(char *)xmlString; + if(tmpStr == "1") + startupPanelView[CONFIG_STARTUPPANEL_CONTROL]=true; + else + startupPanelView[CONFIG_STARTUPPANEL_CONTROL]=false; + xmlFree(xmlString); + } + + xmlString=xmlGetProp(nodePtr,(xmlChar*)"plotlist"); + if(xmlString) + { + + tmpStr=(char *)xmlString; + if(tmpStr == "1") + startupPanelView[CONFIG_STARTUPPANEL_PLOTLIST]=true; + else + startupPanelView[CONFIG_STARTUPPANEL_PLOTLIST]=false; + xmlFree(xmlString); + } + + } + } + + //restore old node + nodePtr=nodeStack.top(); + nodeStack.pop(); + + //Advance and push, as needed + if(!nodePtr->next) + goto nodeptrEndJump; + + nodePtr=nodePtr->next; + nodeStack.push(nodePtr); + if(!XMLHelpFwdToElem(nodePtr,"mousedefaults")) + { + xmlNodePtr mouseDataNodePtr=nodePtr->xmlChildrenNode; + if(mouseDataNodePtr) + { + nodeStack.push(mouseDataNodePtr); + if(!XMLHelpFwdToElem(mouseDataNodePtr,"speed")) + { + unsigned int percentage; + if(XMLGetAttrib(mouseDataNodePtr,percentage,"zoom") && percentage next; + nodeStack.push(nodePtr); + if(!XMLHelpFwdToElem(nodePtr,"netaccess")) + { + std::string tmpStr; + xmlChar *xmlString; + + xmlString=xmlGetProp(nodePtr,(xmlChar*)"enabled"); + if(xmlString) + { + tmpStr=(char *)xmlString; + + if(!(tmpStr == "1" || tmpStr == "0")) + throw 1; + + allowOnline = (tmpStr == "1"); + xmlFree(xmlString); + } + + if(nodePtr->xmlChildrenNode) + { + nodePtr=nodePtr->xmlChildrenNode; + + if(!XMLHelpFwdToElem(nodePtr,"versioncheck")) + { + xmlChar *xmlString; + + xmlString=xmlGetProp(nodePtr,(xmlChar*)"enabled"); + if(xmlString) + { + tmpStr=(char *)xmlString; + if(!(tmpStr == "1" || tmpStr == "0")) + throw 1; + + allowOnlineVerCheck = (tmpStr == "1"); + xmlFree(xmlString); + } + + } + } + } + nodePtr=nodeStack.top(); + nodeStack.pop(); + + + nodeStack.push(nodePtr); + if(!XMLHelpFwdToElem(nodePtr,"sashposition")) + { + if(nodePtr->xmlChildrenNode) + { + nodePtr=nodePtr->xmlChildrenNode; + + while(!XMLHelpFwdToElem(nodePtr,"pos")) + { + + string name; + if(XMLGetAttrib(nodePtr, name,"name")) + { + if(name == "topbottom") + XMLGetAttrib(nodePtr,topBottomSashPos,"value"); + if(name == "leftright") + XMLGetAttrib(nodePtr,leftRightSashPos,"value"); + if(name == "filter") + XMLGetAttrib(nodePtr,filterSashPos,"value"); + if(name == "plotlist") + XMLGetAttrib(nodePtr,plotListSashPos,"value"); + } + + nodePtr=nodePtr->next; + } + } + } + nodePtr=nodeStack.top(); + nodeStack.pop(); +nodeptrEndJump: + ; + + } + catch (int) + { + //Code threw an error, just say "bad parse" and be done with it + xmlFreeDoc(doc); + return CONFIG_ERR_BADFILE; + } + + + xmlFreeDoc(doc); + + configLoadOK=true; + return 0; + +} + +bool ConfigFile::createConfigDir() +{ + wxString filePath = wxStr(getConfigDir()); + + //Create the folder if it does not exist + if(!wxDirExists(filePath)) + { + if(!wxMkdir(filePath)) + return false; + + //Make it a hidden folder +#if defined(__WIN32) || defined(__WIN64) + SetFileAttributes(filePath.wc_str(),FILE_ATTRIBUTE_HIDDEN); +#endif + } + + return true; +} + +std::string ConfigFile::getConfigDir() +{ + wxStandardPaths *paths = new wxStandardPaths; + wxString filePath = paths->GetDocumentsDir()+wxCStr("/.")+wxCStr(PROGRAM_NAME); + + delete paths; + + return stlStr(filePath); +} + + +bool ConfigFile::write() +{ + string filename; + + if(!createConfigDir()) + return false; + + filename = getConfigDir() + std::string("/") + std::string(CONFIG_FILENAME); + + //Open file for output + std::ofstream f(filename.c_str()); + + if(!f) + return false; + + //Write state open tag + f<< "" << endl; + f<" << endl; + + if(haveIntialAppSize) + { + f<" << endl; + } + + f<" << endl; + + for(unsigned int ui=0;ui" << endl; + + f<< tabs(1) << "" << endl; + + f<< tabs(1) << "" << endl; + + for(unsigned int ui=0;uiwriteState(f,STATE_FORMAT_XML,2); + f<< tabs(1) << "" << endl; + + if(startupPanelView.size()) + { + ASSERT(startupPanelView.size() == CONFIG_STARTUPPANEL_END_ENUM); + + f << tabs(1) << "" << endl; + } + + f << tabs(1) << " " << endl; + f << tabs(2) << "" << endl; + f << tabs(1) << " " << endl; + + //Online access settings +#if (!defined(__APPLE__) && !defined(WIN32)) + f << tabs(1) <<"" << endl; +#endif + f << tabs(1) << " " << endl; + + f << tabs(2) << " " << endl; + + f << tabs(1) << "" << endl; + + + //Online access settings + f << tabs(1) << "" << endl; + if(topBottomSashPos) + f << tabs(2) << "" << endl; + if(leftRightSashPos) + f << tabs(2) << "" << endl; + if(filterSashPos) + f << tabs(2) << "" << endl; + if(plotListSashPos) + f << tabs(2) << "" << endl; + f << tabs(1) << "" << endl; + + f << "" << endl; + + ASSERT(isValidXML(filename.c_str())); + + return true; +} + +bool ConfigFile::getPanelEnabled(unsigned int panelID) const +{ + ASSERT(panelID < CONFIG_STARTUPPANEL_END_ENUM); + + switch(panelMode) + { + case CONFIG_PANELMODE_NONE: + return true; + case CONFIG_PANELMODE_REMEMBER: + case CONFIG_PANELMODE_SPECIFY: + if(startupPanelView.size()) + { + ASSERT(startupPanelView.size() == CONFIG_STARTUPPANEL_END_ENUM); + return startupPanelView[panelID]; + } + else + return true; + default: + ASSERT(false); + } +} + +void ConfigFile::setPanelEnabled(unsigned int panelID, bool enabled, bool permanent) +{ + ASSERT(panelID < CONFIG_STARTUPPANEL_END_ENUM); + + //Create the vector as needed, filling with default of "enabled" + if(startupPanelView.empty()) + startupPanelView.resize(CONFIG_STARTUPPANEL_END_ENUM,true); + + ASSERT(startupPanelView.size() == CONFIG_STARTUPPANEL_END_ENUM); + + if(panelMode != CONFIG_PANELMODE_SPECIFY || permanent) + startupPanelView[panelID] = enabled; +} + +void ConfigFile::setStartupPanelMode(unsigned int panelM) +{ + ASSERT(panelM < CONFIG_PANELMODE_END_ENUM); + panelMode=panelM; +} + +unsigned int ConfigFile::getStartupPanelMode() const +{ + return panelMode; +} + + +bool ConfigFile::getAllowOnlineVersionCheck() const +{ + #if defined(WIN32) || defined(__APPLE__) + //windows don't have good package + //management systems as yet, so we check, + //iff the user opts in + return allowOnlineVerCheck; + #else + //Linux and friends should NEVER look online. + //as they have package management systems to do this. + return false; + #endif +} + +void ConfigFile::setAllowOnline(bool v) +{ + //Do not allow this setting to + //be modified from the default for non-apple-non windows + //platforms + #if defined( __APPLE__) || defined(WIN32) + allowOnline=v; + #endif +} +void ConfigFile::setAllowOnlineVersionCheck(bool v) +{ + //Do not allow this setting to + //be modified from the default for non windows + //platforms + #if defined(WIN32) || defined(__APPLE__) + allowOnlineVerCheck=v; + #endif +} + + +void ConfigFile::setLeftRightSashPos(float fraction) +{ + ASSERT(fraction <= 1.0f && fraction >=0.0f); + leftRightSashPos=fraction; +} + +void ConfigFile::setTopBottomSashPos(float fraction) +{ + ASSERT(fraction <= 1.0f && fraction >=0.0f); + topBottomSashPos=fraction; +} + + +void ConfigFile::setFilterSashPos(float fraction) +{ + ASSERT(fraction <= 1.0f && fraction >=0.0f); + filterSashPos=fraction; +} + + +void ConfigFile::setPlotListSashPos(float fraction) +{ + ASSERT(fraction <= 1.0f && fraction >=0.0f); + plotListSashPos=fraction; +} + + diff -Nru 3depict-0.0.12/src/backend/configFile.h 3depict-0.0.13/src/backend/configFile.h --- 3depict-0.0.12/src/backend/configFile.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/configFile.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,171 @@ +/* + * configFile.h - Configuration file management 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 . + */ + +#ifndef CONFIGFILE_H +#define CONFIGFILE_H + + +#include "backend/filter.h" + + +//!Startup panel identifiers. +enum { + CONFIG_STARTUPPANEL_RAWDATA, + CONFIG_STARTUPPANEL_CONTROL, + CONFIG_STARTUPPANEL_PLOTLIST, + CONFIG_STARTUPPANEL_END_ENUM +}; + +enum +{ + CONFIG_PANELMODE_NONE, + CONFIG_PANELMODE_REMEMBER, + CONFIG_PANELMODE_SPECIFY, + CONFIG_PANELMODE_END_ENUM +}; + +enum +{ + CONFIG_ERR_NOFILE=1, + CONFIG_ERR_BADFILE, + CONFIG_ERR_NOPARSER +}; + + +class ConfigFile +{ + private: + std::deque recentFiles; + vector filterDefaults; + + //!Did the configuration load from file OK? + bool configLoadOK; + + //!Panel + vector startupPanelView; + + //!Any errors that occur during file IO. Set by class members during read()/write() + std::string errMessage; + + //!Method for showing/hiding panel at startup + unsigned int panelMode; + + //!Initial application window size in pixels + unsigned int initialSizeX,initialSizeY; + //!Do we have a valid initial app size? + bool haveIntialAppSize; + + //!Percentile speeds for mouse zoom and move + unsigned int mouseZoomRatePercent,mouseMoveRatePercent; + + //!Master allow the program to do stuff online check. This is AND-ed, so cannot override disabled items + bool allowOnline; + + //!Should the program perform online version number checking? + bool allowOnlineVerCheck; + + //!fractional initial positions of sashes in main UI + float leftRightSashPos,topBottomSashPos, + filterSashPos,plotListSashPos; + + + public: + ConfigFile(); + ~ConfigFile(); + void addRecentFile(const std::string &str); + void getRecentFiles(std::vector &filenames) const; + void removeRecentFile(const std::string &str); + + unsigned int read(); + bool write(); + + bool configLoadedOK() const { return configLoadOK;} + + //Create the configuration folder, if needed. + static bool createConfigDir() ; + //Get the configuration dir path + static std::string getConfigDir(); + + std::string getErrMessage() const { return errMessage;}; + + static unsigned int getMaxHistory(); + + //Get a vector of the default filter pointers + void getFilterDefaults(vector &defs); + //Set the default filter pointers (note this will take ownership of the pointer) + void setFilterDefaults(const vector &defs); + + //Get a clone of the default filter for a given type, + //even if it is not in the array (use hardcoded) + Filter *getDefaultFilter(unsigned int type) const; + + //!Return startup status of UI panels + bool getPanelEnabled(unsigned int panelID) const; + + //!Return startup status of UI panels + void setPanelEnabled(unsigned int panelID,bool enabled, bool permanent=false); + + //!Get the mouse movement rate (for all but zoom) + unsigned int getMouseMoveRate() const { return mouseMoveRatePercent; } + //!Get the mouse movement rate for zoom + unsigned int getMouseZoomRate() const { return mouseZoomRatePercent; } + + //Set the mouse zoom rate(percent) + void setMouseZoomRate(unsigned int rate) { mouseZoomRatePercent=rate;}; + //Set the mouse move rate (percent) + void setMouseMoveRate(unsigned int rate) { mouseMoveRatePercent=rate;}; + + //!Return the current panelmode + unsigned int getStartupPanelMode() const; + //!Set the mode to use for recalling the startup panel layout + void setStartupPanelMode(unsigned int panelM); + + //!Returns true if we have a suggested initial window size; with x & y being the suggestion + bool getInitialAppSize(unsigned int &x, unsigned int &y) const; + //!Set the initial window suggested size + void setInitialAppSize(unsigned int x, unsigned int y); + + bool getAllowOnlineVersionCheck() const; + + //!Set if the program is allowed to access network resources + void setAllowOnline(bool v); + //!Set if the program is allowed to phone home to get latest version #s + void setAllowOnlineVersionCheck(bool v); + + //!Set the position for the main window left/right sash + void setLeftRightSashPos(float fraction); + //!Set the position for the top/bottom sash + void setTopBottomSashPos(float fraction); + //!Set the position for the filter property/tree sash + void setFilterSashPos(float fraction); + //!Set the position for the plot list panel + void setPlotListSashPos(float fraction); + + //!Set the position for the main window left/right sash + float getLeftRightSashPos() const { return leftRightSashPos;}; + //!Set the position for the top/bottom sash + float getTopBottomSashPos() const{ return topBottomSashPos;} + //!Set the position for the filter property/tree sash + float getFilterSashPos() const { return filterSashPos;}; + //!Set the position for the plot list panel + float getPlotListSashPos()const { return plotListSashPos;}; + + +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filter.cpp 3depict-0.0.13/src/backend/filter.cpp --- 3depict-0.0.12/src/backend/filter.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filter.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -0,0 +1,678 @@ +/* + * filter.h - modular data filter implementation + * 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 . +*/ + +#include "filter.h" + +#include "common/stringFuncs.h" +#include "common/translation.h" + +#include "wxcomponents.h" + +#include + +#ifdef _OPENMP +#include +#endif + +using std::list; +using std::vector; +using std::string; +using std::pair; +using std::make_pair; + + + + +bool Filter::strongRandom= false; + +const char *STREAM_NAMES[] = { NTRANS("Ion"), + NTRANS("Plot"), + NTRANS("Draw"), + NTRANS("Range"), + NTRANS("Voxel")}; + +//Internal names for each filter +const char *FILTER_NAMES[] = { "posload", + "iondownsample", + "rangefile", + "spectrumplot", + "ionclip", + "ioncolour", + "compositionprofile", + "boundingbox", + "transform", + "externalprog", + "spatialanalysis", + "clusteranalysis", + "voxelise", + "ioninfo", + "annotation" + }; + +void updateFilterPropertyGrid(wxPropertyGrid *g, const Filter *f) +{ + + ASSERT(f); + ASSERT(g); + + FilterPropGroup p; + f->getProperties(p); +#ifdef DEBUG + //If debugging, test self consistency + p.checkConsistent(); +#endif + g->clearKeys(); + g->setNumGroups(p.numGroups()); + + + //Create the keys to add to the grid + for(size_t ui=0;ui propGrouping; + p.getGroup(ui,propGrouping); + + for(size_t uj=0;ujaddKey(propGrouping[uj].name,ui, + propGrouping[uj].key, + propGrouping[uj].type, + propGrouping[uj].data, + propGrouping[uj].helpText); + } + + //Set the name that is to be displayed for this grouping + // of properties + std::string title; + p.getGroupTitle(ui,title); + g->setGroupName(ui,title); + } + + //Let the property grid layout what it needs to + g->propertyLayout(); +} + +size_t numElements(const vector &v, unsigned int mask) +{ + size_t nE=0; + for(unsigned int ui=0;uigetStreamType() & mask)) + nE+=v[ui]->getNumBasicObjects(); + } + + return nE; +} + +#ifdef DEBUG +bool FilterProperty::checkSelfConsistent() const +{ + //Filter data type must be known + ASSERT(type < PROPERTY_TYPE_ENUM_END); + ASSERT(name.size()); + + //Check each item is parseable as its own type + switch(type) + { + case PROPERTY_TYPE_BOOL: + { + if(data != "0" && data != "1") + return false; + break; + } + case PROPERTY_TYPE_REAL: + { + float f; + if(stream_cast(f,data)) + return false; + break; + } + case PROPERTY_TYPE_COLOUR: + { + unsigned char r,g,b,a; + if(!parseColString(data,r,g,b,a)) + return false; + + break; + } + case PROPERTY_TYPE_CHOICE: + { + if(!isMaybeChoiceString(data)) + return false; + break; + } + case PROPERTY_TYPE_POINT3D: + { + Point3D p; + if(!p.parse(data)) + return false; + break; + } + case PROPERTY_TYPE_INTEGER: + { + int i; + if(stream_cast(i,data)) + return false; + break; + } + default: + { + //Check for the possibility that a choice string is mistyped + // - this has happened. However, its possible to get a false positive + if(isMaybeChoiceString(data)) + { + WARN(false, "Possible property not set as choice? It seems to be a choice string..."); + } + } + } + + + return true; +} +#endif + +void FilterPropGroup::addProperty(const FilterProperty &prop, size_t group) +{ +#ifdef DEBUG + prop.checkSelfConsistent(); +#endif + if(group >=groupCount) + { +#ifdef DEBUG + WARN(!(group > (groupCount+1)),"Appeared to add multiple groups in one go - not wrong, just unusual."); +#endif + groupCount=std::max(group+1,groupCount); + groupNames.resize(groupCount,string("")); + } + + keyGroupings.push_back(make_pair(prop.key,group)); + properties.push_back(prop); +} + +void FilterPropGroup::setGroupTitle(size_t group, const std::string &str) +{ + ASSERT(group &vec) const +{ + ASSERT(targetGroup s; + + //Check that each key is unique in the keyGroupings list + for(size_t ui=0;ui::max(); + hardMaxX=hardMaxY=std::numeric_limits::max(); +} + +void PlotStreamData::autoSetHardBounds() +{ + if(xyData.size()) + { + hardMinX=std::numeric_limits::max(); + hardMinY=std::numeric_limits::max(); + hardMaxX=-std::numeric_limits::max(); + hardMaxY=-std::numeric_limits::max(); + + for(size_t ui=0;ui=0 + ASSERT(!(logarithmic && hardMinY < 0) ); + + //hardMin should be <=hardMax + //-- + ASSERT(hardMinX<=hardMaxX); + + ASSERT(hardMinY<=hardMaxY); + //-- + + //If we have regions that can be interacted with, need to have parent + ASSERT(!(regionID.size() && !regionParent)); + + //Must have valid trace style + ASSERT(plotStylegetNumIons() == enabledIons.size()); + + ASSERT(rangeFile->getNumRanges() == enabledIons.size()); + +} +#endif + +FilterStreamData::FilterStreamData() : parent(0),cached((unsigned int)-1) +{ +} + +IonStreamData::IonStreamData() : representationType(ION_REPRESENT_POINTS), + r(1.0f), g(0.0f), b(0.0f), a(1.0f), + ionSize(2.0f), valueType("Mass-to-Charge (amu/e)") +{ + streamType=STREAM_TYPE_IONS; +} + +VoxelStreamData::VoxelStreamData() : representationType(VOXEL_REPRESENT_POINTCLOUD), + r(1.0f),g(0.0f),b(0.0f),a(0.3f), splatSize(2.0f),isoLevel(0.5f) +{ + streamType=STREAM_TYPE_VOXEL; +} + +RangeStreamData::RangeStreamData() : rangeFile(0) +{ + streamType = STREAM_TYPE_RANGE; +} + +bool RangeStreamData::save(const char *filename, size_t format) const +{ + return !rangeFile->write(filename,format); +} + +Filter::Filter() : cache(true), cacheOK(false) +{ + for(unsigned int ui=0;uicached); + delete filterOutputs[ui]; + } + + filterOutputs.clear(); +} + +bool Filter::haveCache() const +{ + return cacheOK; +} + +void Filter::getSelectionDevices(vector *> &outD) +{ + outD.resize(devices.size()); + + std::copy(devices.begin(),devices.end(),outD.begin()); + +#ifdef DEBUG + for(unsigned int ui=0;ui > tmp; + outD[ui]->getModifiedBindings(tmp); + tmp.clear(); + } +#endif +} + +void Filter::updateOutputInfo(const std::vector &dataOut) +{ + //Reset the number ouf output streams to zero + for(unsigned int ui=0;uigetStreamType()) < NUM_STREAM_TYPES); + numStreamsLastRefresh[getBitNum(dataOut[ui]->getStreamType())]++; + } +} + +unsigned int Filter::getNumOutput(unsigned int streamType) const +{ + ASSERT(streamType < NUM_STREAM_TYPES); + return numStreamsLastRefresh[streamType]; +} + +std::string Filter::getUserString() const +{ + if(userString.size()) + return userString; + else + return typeString(); +} + +void Filter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + dataOut.resize(dataIn.size()); + std::copy(dataIn.begin(),dataIn.end(),dataOut.begin()); +} + +#ifdef DEBUG +extern Filter *makeFilter(unsigned int ui); +extern Filter *makeFilter(const std::string &s); + +bool Filter::boolToggleTests() +{ + //Each filter should allow user to toggle any boolean value + // here we just test the default visible ones + for(unsigned int ui=0;uigetProperties(propGroupOrig); + + + for(size_t ui=0;uisetProperty(p.key,p.data,needUp); + + //Re-get properties to find altered property + FilterPropGroup propGroup; + f->getProperties(propGroup); + + FilterProperty p2; + p2 = propGroup.getPropValue(p.key); + //Check the property values + TEST(p2.data == p.data,"displayed bool property can't be toggled"); + + //Toggle value back to original status + if(p2.data== "0") + p2.data= "1"; + else + p2.data= "0"; + //re-set value to toggled version + f->setProperty(p2.key,p2.data,needUp); + + //Re-get properties to see if original value is restored + FilterPropGroup fp2; + f->getProperties(fp2); + p = fp2.getPropValue(p2.key); + + TEST(p.data== p2.data,"failed trying to set bool value back to original after toggle"); + } + delete f; + } + + return true; +} + +bool Filter::helpStringTests() +{ + //Each filter should provide help text for each property + // here we just test the default visible ones + for(unsigned int ui=0;uigetProperties(propGroup); + for(size_t ui=0;ui. +*/ +#ifndef FILTER_H +#define FILTER_H +class Filter; +class FilterStreamData; +class ProgressData; +class RangeFileFilter; + +#include "APT/APTRanges.h" +#include "common/constants.h" + +#include "gl/select.h" + +#include "common/voxels.h" + +//ifdef inclusion as there is some kind of symbol clash... +#ifdef ATTRIBUTE_PRINTF + #pragma push_macro("ATTRIBUTE_PRINTF") + #include + #pragma pop_macro(" ATTRIBUTE_PRINTF") +#else + #include + #undef ATTRIBUTE_PRINTF +#endif + + + +const unsigned int NUM_CALLBACK=50000; + +const unsigned int IONDATA_SIZE=4; + +//!Filter types -- must match array FILTER_NAMES +enum +{ + FILTER_TYPE_DATALOAD, + FILTER_TYPE_IONDOWNSAMPLE, + FILTER_TYPE_RANGEFILE, + FILTER_TYPE_SPECTRUMPLOT, + FILTER_TYPE_IONCLIP, + FILTER_TYPE_IONCOLOURFILTER, + FILTER_TYPE_COMPOSITION, + FILTER_TYPE_BOUNDBOX, + FILTER_TYPE_TRANSFORM, + FILTER_TYPE_EXTERNALPROC, + FILTER_TYPE_SPATIAL_ANALYSIS, + FILTER_TYPE_CLUSTER_ANALYSIS, + FILTER_TYPE_VOXELS, + FILTER_TYPE_IONINFO, + FILTER_TYPE_ANNOTATION, + FILTER_TYPE_ENUM_END // not a filter. just end of enum +}; + +extern const char *FILTER_NAMES[]; + + + +//Stream data types. note that bitmasks are occasionally used, so we are limited in +//the number of stream types that we can have. +//Current bitmask using functions are +// VisController::safeDeleteFilterList +const unsigned int NUM_STREAM_TYPES=5; +const unsigned int STREAMTYPE_MASK_ALL= (1<<(NUM_STREAM_TYPES)) -1; +enum +{ + STREAM_TYPE_IONS=1, + STREAM_TYPE_PLOT=2, + STREAM_TYPE_DRAW=4, + STREAM_TYPE_RANGE=8, + STREAM_TYPE_VOXEL=16 +}; + + +//Keys for binding IDs +enum +{ + BINDING_CYLINDER_RADIUS=1, + BINDING_SPHERE_RADIUS, + BINDING_CYLINDER_ORIGIN, + BINDING_SPHERE_ORIGIN, + BINDING_PLANE_ORIGIN, + BINDING_CYLINDER_DIRECTION, + BINDING_PLANE_DIRECTION, + BINDING_RECT_TRANSLATE, + BINDING_RECT_CORNER_MOVE +}; + +extern const char *STREAM_NAMES[]; + +//Representations +enum +{ + //IonStreamData + ION_REPRESENT_POINTS + +}; + +//Representations +enum +{ + //VoxelStreamData + VOXEL_REPRESENT_POINTCLOUD, + VOXEL_REPRESENT_ISOSURF, + VOXEL_REPRESENT_END +}; + +//Error codes for each of the filters. +//These can be passed to the getErrString() function for +//a human readable error message +//--- + +enum +{ + FILE_TYPE_NULL, + FILE_TYPE_XML, + FILE_TYPE_POS +}; + +//--- +// + +//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 +size_t numElements(const vector &vm, unsigned int mask=STREAMTYPE_MASK_ALL); + + +void updateFilterPropertyGrid(wxPropertyGrid *g, const Filter *f); + +//!Abstract base class for data types that can propagate through filter system +class FilterStreamData +{ + protected: + unsigned int streamType; + public: + //!Parent filter pointer + const Filter *parent; + + //!Tells us if the filter has cacehd this data for later use. + //this is a boolean value, but not declared as such, as there + //are debug traps to tell us if this is not set by looking for non-boolean values. + unsigned int cached; + + FilterStreamData(); + virtual ~FilterStreamData() {}; + virtual size_t getNumBasicObjects() const =0; + //!Returns an integer unique to the clas to identify type (yes rttid...) + virtual unsigned int getStreamType() const {return streamType;} ; + //!Free mem held by objects + virtual void clear()=0; + +#ifdef DEBUG + //Cross-checks fields to determine if (best guess) + ///data structure has a sane combination of values + virtual void checkSelfConsistent() const {} +#endif + +}; + +class FilterProperty +{ + public: + //!Human readable short help (tooltip) for each of the keys + std::string helpText; + //!Data type for this element + unsigned int type; + //!Unique key value for this element + size_t key; + //!Property data + std::string data; + //!name of property + std::string name; + + bool checkSelfConsistent() const; +}; + +class FilterPropGroup +{ + private: + //!The groupings for the keys in contained properties. + // First entry is the key ID, second is he group that it belongs to + std::vector > keyGroupings; + //!Names for each group of keys. + std::vector groupNames; + //!Key information + std::vector properties; + + size_t groupCount; + public: + FilterPropGroup() { groupCount=0;} + //!Add a property to a grouping + void addProperty(const FilterProperty &prop, size_t group); + + + //!Set the title text for a particular group + void setGroupTitle(size_t group, const std::string &str); + + //!Obtain the title of the nth group + void getGroupTitle(size_t group, std::string &str) const ; + + //Obtain a property by its key + const FilterProperty &getPropValue(size_t key) const; + + //Retrieve the number of groups + size_t numGroups() const { return groupCount;}; + + bool hasProp(size_t key) const; + //Get number of keys + size_t numProps() const { return properties.size(); } + //Erase all stored information + void clear() + { groupNames.clear();keyGroupings.clear(); properties.clear(); + groupCount=0;} + + //!Grab all properties from the specified group + void getGroup(size_t group, vector &groupVec) const; + //!Get the nth key + const FilterProperty &getNthProp(size_t nthProp) const { return properties[nthProp];}; + +#ifdef DEBUG + void checkConsistent() const; +#endif + +}; + +//!Point with m-t-c value data +class IonStreamData : public FilterStreamData +{ +public: + IonStreamData(); + void clear(); + size_t getNumBasicObjects() const { return data.size();}; + + unsigned int representationType; + float r,g,b,a; + float ionSize; + + //!The name for the type of data -- nominally "mass-to-charge" + std::string valueType; + + //!Apply filter to input data stream + std::vector data; +}; + +//!Point with m-t-c value data +class VoxelStreamData : public FilterStreamData +{ +public: + VoxelStreamData(); + size_t getNumBasicObjects() const { return data.getSize();}; + void clear(); + + unsigned int representationType; + float r,g,b,a; + float splatSize; + float isoLevel; + //!Apply filter to input data stream + Voxels data; + +}; + +//!Plotting data +class PlotStreamData : public FilterStreamData +{ + public: + PlotStreamData(); + + bool save(const char *filename) const; + + //erase plot contents + void clear() {xyData.clear();}; + //Get data size + size_t getNumBasicObjects() const { return xyData.size();}; + + //Use the contained XY data to set hard plot bounds + void autoSetHardBounds(); + //plot colour + float r,g,b,a; + //plot trace mode - enum PLOT_TRACE + unsigned int plotStyle; + //plot mode - enum PLOT_MODE + unsigned int plotMode; + + //use logarithmic mode? + bool logarithmic; + //title for data + std::string dataLabel; + //Label for X, Y axes + std::string xLabel,yLabel; + + //!When showing raw XY data, is the data + // label a better descriptor of Y than the y-label? + bool useDataLabelAsYDescriptor; + + //!XY data pairs for plotting curve + std::vector > xyData; + //!Rectangular marked regions + vector > regions; + //!Region colours + vector regionR,regionB,regionG; + + //!Region indicies from parent region + vector regionID; + + //!Region parent filter pointer, used for matching interaction + // with region to parent property + Filter *regionParent; + //!Parent filter index + unsigned int index; + //!Error bar mode + PLOT_ERROR errDat; + + //!Hard bounds that cannot be exceeded when drawing plot + float hardMinX,hardMaxX,hardMinY,hardMaxY; + +#ifdef DEBUG + //Cross-checks fields to determine if (best guess) + ///data structure has a sane combination of values + virtual void checkSelfConsistent() const; +#endif + +}; + +//!Drawable objects, for 3D decoration. +class DrawStreamData: public FilterStreamData +{ + public: + //!Vector of 3D objects to draw. + vector drawables; + //!constructor + DrawStreamData(){ streamType=STREAM_TYPE_DRAW;}; + //!Destructor + ~DrawStreamData(); + //!Returns 0, as this does not store basic object types -- i.e. is not for data storage per se. + size_t getNumBasicObjects() const { return 0; } + + //!Erase the drawing vector, deleting its componets + void clear(); +#ifdef DEBUG + //Cross-checks fields to determine if (best guess) + ///data structure has a sane combination of values + void checkSelfConsistent() const; +#endif +}; + +//!Range file propagation +class RangeStreamData : public FilterStreamData +{ + public: + //!range file filter from whence this propagated. Do not delete[] pointer at all, this class does not OWN the range data + //it merely provides access to existing data. + RangeFile *rangeFile; + //Enabled ranges from source filter + vector enabledRanges; + //Enabled ions from source filter + vector enabledIons; + + + //!constructor + RangeStreamData(); + //!Destructor + ~RangeStreamData() {}; + //!save the range data to a file + bool save(const char *filename, size_t format) const; + //!Returns 0, as this does not store basic object types -- i.e. is not for data storage per se. + size_t getNumBasicObjects() const { return 0; } + + //!Unlink the pointer + void clear() { rangeFile=0;enabledRanges.clear();enabledIons.clear();}; + +#ifdef DEBUG + void checkSelfConsistent() const ; +#endif +}; + +//!Abstract base filter class. +class Filter +{ + protected: + + bool cache, cacheOK; + static bool strongRandom; + + bool wantMonitor; + + //!Array of the number of streams propagated on last refresh + //THis is initialised to -1, which is considered invalid + unsigned int numStreamsLastRefresh[NUM_STREAM_TYPES]; + + + //!temporary console output. Should be only nonzero size immediately after refresh + vector consoleOutput; + //!User settable labelling string (human readable ID, etc etc) + std::string userString; + //Filter output cache + std::vector filterOutputs; + //!User interaction "Devices" associated with this filter + std::vector *> devices; + public: + Filter() ; + virtual ~Filter(); + + //Pure virtual functions + //==== + //!Duplicate filter contents, excluding cache. + virtual Filter *cloneUncached() const = 0; + + //!Apply filter to new data, updating cache as needed. Vector of returned pointers must be deleted manually, first checking ->cached. + virtual unsigned int refresh(const std::vector &dataIn, + std::vector &dataOut, + ProgressData &progress, bool (*callback)(bool)) =0; + //!Erase cache + virtual void clearCache(); + + //!Erase any active devices + virtual void clearDevices(); + + //!Get (approx) number of bytes required for cache + virtual size_t numBytesForCache(size_t nObjects) const =0; + + //!return type ID + virtual unsigned int getType() const=0; + + //!Return filter type as std::string + virtual std::string typeString()const =0; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + virtual void getProperties(FilterPropGroup &propertyList) const =0; + + //!Set the properties for the nth filter, + //!needUpdate tells us if filter output changes due to property set + //NOte that if you modify a result without clearing the cache, + //then any downstream decision based upon that may not be noted in an update + //Take care. + virtual bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate) = 0; + + //!Get the human readable error string associated with a particular error code during refresh(...) + virtual std::string getErrString(unsigned int code) const =0; + + //!Dump state to output stream, using specified format + /* Current supported formats are STATE_FORMAT_XML + */ + virtual bool writeState(std::ostream &f, unsigned int format, + unsigned int depth=0) const = 0; + + //!Read state from XML stream, using xml format + /* Current supported formats are STATE_FORMAT_XML + */ + virtual bool readState(xmlNodePtr& n, const std::string &packDir="") = 0; + + //!Get the bitmask encoded list of filterStreams that this filter blocks from propagation. + // i.e. if this filterstream is passed to refresh, it is not emitted. + // This MUST always be consistent with ::refresh for filters current state. + virtual unsigned int getRefreshBlockMask() const =0; + + //!Get the bitmask encoded list of filterstreams that this filter emits from ::refresh. + // This MUST always be consistent with ::refresh for filters current state. + virtual unsigned int getRefreshEmitMask() const = 0; + + + //!Mask of filter streams that will not examined by the filter in its computation. + // note that these *may* be emitted as a pass-through - check emitmask if needed + virtual unsigned int getRefreshUseMask() const =0; + + //==== + + //!Return the unique name for a given filter -- DO NOT TRANSLATE + string trueName() const { return FILTER_NAMES[getType()];}; + + + + //!Initialise the filter's internal state using limited filter stream data propagation + //NOTE: CONTENTS MAY NOT BE CACHED. + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + + + //!Return the XML elements that refer to external entities (i.e. files) which do not move with the XML file + //Each element is to be referred to using "/" as entity separator, for the first pair element, and the attribute name for the second. + virtual void getStateOverrides(std::vector &overrides) const {}; + + //!Enable/disable caching for this filter + void setCaching(bool enableCache) {cache=enableCache;}; + + //!Have cached output data? + bool haveCache() const; + + + //!Return a user-specified string, or just the typestring if user set string not active + virtual std::string getUserString() const ; + //!Set a user-specified string return value is + virtual void setUserString(const std::string &str) { userString=str;}; + + + //!Modified version of writeState for packaging. By default simply calls writeState. + //value overrides override the values returned by getStateOverrides. In order. + virtual bool writePackageState(std::ostream &f, unsigned int format, + const std::vector &valueOverrides,unsigned int depth=0) const {return writeState(f,format,depth);}; + + + + //!Get the selection devices for this filter. MUST be called after refresh() + /*No checking is done that the selection devices will not interfere with one + * 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 *> &devices); + + + //!Update the output statistics for this filter (num items of streams of each type output) + void updateOutputInfo(const std::vector &dataOut); + + //!Set the binding value for a float + virtual void setPropFromBinding(const SelectionBinding &b)=0; + + //!Set a region update + virtual void setPropFromRegion(unsigned int method, unsigned int regionID, float newPos); + + //!Can this filter perform actions that are potentially a security concern? + virtual bool canBeHazardous() const {return false;} ; + + //!Get the number of outputs for the specified type during the filter's last refresh + unsigned int getNumOutput(unsigned int streamType) const; + + //!Get the filter messages from the console -- also deletes the + // console messages as a side-effect + void getConsoleStrings(std::vector &v) { v.resize(consoleOutput.size());std::copy(consoleOutput.begin(),consoleOutput.end(),v.begin()); consoleOutput.clear();}; + + //!Should filters use strong randomisation (where applicable) or not? + static void setStrongRandom(bool strongRand) {strongRandom=strongRand;}; + + //Check to see if the filter needs to be refreshed + virtual bool monitorNeedsRefresh() const { return false;}; + + //Are we a pure data source - i.e. can function with no input + virtual bool isPureDataSource() const { return false;}; + + //Can we be a useful filter, even if given no input specified by the Use mask? + virtual bool isUsefulAsAppend() const { return false;} +#ifdef DEBUG + //!Run all the registered unit tests for this filter + virtual bool runUnitTests() { cerr << "No test for " << typeString() << endl; return true;} ; + //!Is the filter caching? + bool cacheEnabled() const {return cache;}; + + static bool boolToggleTests() ; + + static bool helpStringTests() ; +#endif + +}; + + +//!Class that tracks the progress of scene updates +class ProgressData +{ + public: + //!Progress of filter (out of 100) for current filter + unsigned int filterProgress; + //!Number of filters (n) that we have proccessed (n out of m filters) + unsigned int totalProgress; + + //!number of filters which need processing for this update + unsigned int totalNumFilters; + + //!Current step + unsigned int step; + //!Maximum steps + unsigned int maxStep; + + //!Pointer to the current filter that is being updated. Only valid during an update callback + const Filter *curFilter; + + //!Name of current operation, if specified + std::string stepName; + + void reset() { filterProgress=totalProgress=step=maxStep=0;curFilter=0; stepName.clear();}; + void clock() { filterProgress=step=maxStep=0;curFilter=0;totalProgress++; stepName.clear();}; +}; + + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/K3DTree-mk2.cpp 3depict-0.0.13/src/backend/filters/K3DTree-mk2.cpp --- 3depict-0.0.12/src/backend/filters/K3DTree-mk2.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/K3DTree-mk2.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -0,0 +1,741 @@ +/* + * K3DTree-mk2.cpp : 3D Point KD tree - precise implementation + * 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 . + */ + +#include "K3DTree-mk2.h" + + +#include +#include + +using std::stack; +using std::vector; +using std::pair; + +void K3DTreeMk2::resetPts(std::vector &p, bool clear) +{ + //Compute bounding box for indexedPoints + treeBounds.setBounds(p); + indexedPoints.resize(p.size()); + +#pragma omp parallel for + for(size_t ui=0;ui &p, bool clear) +{ + indexedPoints.resize(p.size()); + nodes.resize(p.size()); + + if(p.empty()) + return; + + + //Compute bounding box for indexedPoints + treeBounds=getIonDataLimits(p); + +#pragma omp parallel for + for(size_t ui=0;ui > limits; + stack buildStatus; + stack splitStack; + + //Data runs from 0 to size-1 INCLUSIVE + limits.push(make_pair(0,indexedPoints.size()-1)); + buildStatus.push(BUILT_NONE); + splitStack.push((size_t)-1); + + + AxisCompareMk2 axisCmp; + + size_t numSeen=0; // for progress reporting + size_t splitIndex=0; + + + + size_t *childPtr; + +#ifdef DEBUG + for(size_t ui=0;uilimits.top().first) + { + //There is; we have to branch again + limits.push(make_pair( + limits.top().first,splitIndex-1)); + + buildStatus.push(BUILT_NONE); + //Set the child pointer, as we don't know + //the correct value until the next sort. + childPtr=&nodes[splitIndex].childLeft; + } + else + { + //There is not. Set the left branch to null + nodes[splitIndex].childLeft=(size_t)-1; + } + splitStack.push(splitIndex); + + break; + } + + case BUILT_LEFT: + { + //Either of these cases results in use + //handling the right branch. + buildStatus.top()++; + splitIndex=splitStack.top(); + //Check to see if there is any right data + if(splitIndex status; + stack nodeStack; + status.push(PRINT_NONE); + nodeStack.push(indexedPoints.size()/2); + + do + { + for(size_t ui=0;ui" <" <" <" <Left() + NODE_THIRD_VISIT // Third visit is when you come back from ->Right() + }; + + size_t nodeStack[maxDepth+1]; + float domainStack[maxDepth+1][2]; + unsigned int visitStack[maxDepth+1]; + + size_t bestPoint; + size_t curNode; + + BoundCube curDomain; + unsigned int visit; + unsigned int stackTop; + unsigned int curAxis; + + float bestDistSqr; + float tmpEdge; + + if(nodes.empty()) + return -1; + + bestPoint=(size_t)-1; + bestDistSqr =std::numeric_limits::max(); + curDomain=domainCube; + visit=NODE_FIRST_VISIT; + curAxis=0; + stackTop=0; + + //Start at median of array, which is top of tree, + //by definition + curNode=treeRoot; + + //check root node + if(!nodes[curNode].tagged) + { + float tmpDistSqr; + tmpDistSqr = indexedPoints[curNode].first.sqrDist(searchPt); + if(tmpDistSqr < bestDistSqr) + { + bestDistSqr = tmpDistSqr; + bestPoint=curNode; + } + } + + do + { + switch(visit) + { + //Examine left branch + case NODE_FIRST_VISIT: + { + if(searchPt[curAxis] < indexedPoints[curNode].first[curAxis]) + { + if(nodes[curNode].childLeft!=(size_t)-1) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][1]; + curDomain.bounds[curAxis][1] = indexedPoints[curNode].first[curAxis]; + if(!curDomain.intersects(searchPt,bestDistSqr)) + { + curDomain.bounds[curAxis][1] = tmpEdge; + visit++; + continue; + } + //Preserve our current state. + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. + domainStack[stackTop][1] = tmpEdge; + domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; + stackTop++; + + //Update the current information + curNode=nodes[curNode].childLeft; + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + } + } + else + { + if(nodes[curNode].childRight!=(size_t)-1) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][0]; + curDomain.bounds[curAxis][0] = indexedPoints[curNode].first[curAxis]; + + if(!curDomain.intersects(searchPt,bestDistSqr)) + { + curDomain.bounds[curAxis][0] =tmpEdge; + visit++; + continue; + } + + //Preserve our current state. + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. + domainStack[stackTop][0] = tmpEdge; + domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; + stackTop++; + + //Update the information + curNode=nodes[curNode].childRight; + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + } + } + visit++; + //Fall through + } + //Examine right branch + case NODE_SECOND_VISIT: + { + if(searchPt[curAxis]< indexedPoints[curNode].first[curAxis]) + { + if(nodes[curNode].childRight!=(size_t)-1) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][0]; + curDomain.bounds[curAxis][0] = indexedPoints[curNode].first[curAxis]; + + if(!curDomain.intersects(searchPt,bestDistSqr)) + { + curDomain.bounds[curAxis][0] = tmpEdge; + visit++; + continue; + } + + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_THIRD_VISIT; + domainStack[stackTop][0] = tmpEdge; + domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; + stackTop++; + + //Update the information + curNode=nodes[curNode].childRight; + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + + } + } + else + { + if(nodes[curNode].childLeft!=(size_t)-1) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][1]; + curDomain.bounds[curAxis][1] = indexedPoints[curNode].first[curAxis]; + + if(!curDomain.intersects(searchPt,bestDistSqr)) + { + curDomain.bounds[curAxis][1] = tmpEdge; + visit++; + continue; + } + //Preserve our current state. + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_THIRD_VISIT; + domainStack[stackTop][1] = tmpEdge; + domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; + stackTop++; + + //Update the information + curNode=nodes[curNode].childLeft; + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + + } + } + visit++; + //Fall through + } + case NODE_THIRD_VISIT: + { + //Decide if we should promote the current node + //to "best" (ie nearest untagged) node. + //To promote, it musnt be tagged, and it must + //be closer than cur best estimate. + if(!nodes[curNode].tagged) + { + float tmpDistSqr; + tmpDistSqr = indexedPoints[curNode].first.sqrDist(searchPt); + if(tmpDistSqr < bestDistSqr) + { + bestDistSqr = tmpDistSqr; + bestPoint=curNode; + } + } + + //DEBUG + ASSERT(stackTop%3 == curAxis) + // + if(curAxis) + curAxis--; + else + curAxis=2; + + + + ASSERT(stackTop < maxDepth+1); + if(stackTop) + { + stackTop--; + visit=visitStack[stackTop]; + curNode=nodeStack[stackTop]; + curDomain.bounds[curAxis][0]=domainStack[stackTop][0]; + curDomain.bounds[curAxis][1]=domainStack[stackTop][1]; + ASSERT((stackTop)%3 == curAxis); + } + + break; + } + default: + ASSERT(false); + + + } + + + //Keep going until we meet the root nde for the third time (one left, one right, one finish) + }while(!(curNode== treeRoot && visit== NODE_THIRD_VISIT)); + + if(bestPoint != (size_t) -1) + nodes[bestPoint].tagged|=shouldTag; + return bestPoint; + +} + + +void K3DTreeMk2::getTreesInSphere(const Point3D &pt, float sqrDist, const BoundCube &domainCube, + vector > &contigousBlocks ) const +{ + using std::queue; + using std::pair; + using std::make_pair; + + queue nodeQueue; + queue axisQueue; + queue boundQueue; + + queue > limitQueue; + if(treeRoot == (size_t) -1) + return; + + + nodeQueue.push(treeRoot); + boundQueue.push(domainCube); + axisQueue.push(0); + limitQueue.push(make_pair(0,nodes.size()-1)); + do + { + BoundCube tmpCube; + tmpCube=boundQueue.front(); + + ASSERT(nodeQueue.size() == boundQueue.size() && + nodeQueue.size() == axisQueue.size() && + nodeQueue.size() == limitQueue.size()); + + //There are three cases here. + // - KD limits for this subdomain + // wholly contained by sphere + // > contiguous subtree is interior. + // - KD Limits for this subdomain partially + // contained by sphere. + // > some subtree may be interior -- refine. + // - Does not intersect, do nothing. + + if(tmpCube.containedInSphere(pt,sqrDist)) + { + //We are? Interesting. We must be a contiguous block from our lower + //to upper limits + contigousBlocks.push_back(limitQueue.front()); + } + else if(tmpCube.intersects(pt,sqrDist)) + { + size_t axis,curNode; + //Not wholly contained... but our kids might be! + axis=axisQueue.front(); + curNode=nodeQueue.front(); + + if(nodes[curNode].childLeft !=(size_t)-1) + { + //Construct left hand domain + tmpCube=boundQueue.front(); + //Set upper bound + tmpCube.bounds[axis][1] = indexedPoints[curNode].first[axis]; + + if(tmpCube.intersects(pt,sqrDist)) + { + //We have to examine left child. + nodeQueue.push(nodes[curNode].childLeft); + boundQueue.push(tmpCube); + limitQueue.push(make_pair( + limitQueue.front().first,curNode-1)); + axisQueue.push((axis+1)%3); + } + } + + if(nodes[curNode].childRight !=(size_t)-1) + { + //Construct right hand domain + tmpCube=boundQueue.front(); + //Set lower bound + tmpCube.bounds[axis][0] = indexedPoints[curNode].first[axis]; + + if(tmpCube.intersects(pt,sqrDist)) + { + //We have to examine right child. + nodeQueue.push(nodes[curNode].childRight); + boundQueue.push(tmpCube); + limitQueue.push(make_pair(curNode+1,limitQueue.front().second )); + axisQueue.push((axis+1)%3); + } + } + } + + axisQueue.pop(); + limitQueue.pop(); + boundQueue.pop(); + nodeQueue.pop(); + } + while(!nodeQueue.empty()); + +} + +size_t K3DTreeMk2::tagCount() const +{ + size_t count=0; + for(size_t ui=0;ui &tagsToClear) +{ +#pragma omp parallel for + for(size_t ui=0;ui. + */ + +#ifndef K3DTREEMK2_H +#define K3DTREEMK2_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 +// and avoiding recursive implementations +// - 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 + * that axis only + */ +class AxisCompareMk2 +{ + private: + unsigned int axis; + public: + void setAxis(unsigned int Axis){axis=Axis;}; + inline bool operator()(const std::pair &p1,const std::pair &p2) const + {return p1.first[axis] > indexedPoints; + + //!Tree node array (stores parent->child relations) + std::vector nodes; + + //!total size of array + size_t arraySize; + + //!Which entry is the root of the tree? + size_t treeRoot; + + BoundCube treeBounds; + + //Callback for progress reporting + bool (*callback)(bool); + + unsigned int *progress; //Progress counter + + public: + //KD Tree constructor + K3DTreeMk2(){}; + + //!Cleans up tree, deallocates nodes + ~K3DTreeMk2(){}; + + //Reset the points + void resetPts(std::vector &pts, bool clear=true); + void resetPts(std::vector &pts, bool clear=true); + + /*! Builds a balanced KD tree from a list of points + * previously set by "resetPts". returns false if callback returns + * false; + */ + bool build(); + + void getBoundCube(BoundCube &b); + + //!Textual output of tree. tabs are used to separate different levels of the tree + /*!The output from this function can be quite large for even modest trees. + * Recommended for debugging only*/ + void dump(std::ostream &,size_t depth=0, size_t offset=-1) const; + + + //Find the nearest "untagged" point's internal index. + //Mark the found point as "tagged" in the tree. Returns -1 on failure (no untagged points) + size_t findNearestUntagged(const Point3D &queryPt, + const BoundCube &b, bool tag=true); + + + //!Get the contigous node IDs for a subset of points in the tree that are contained + // within a sphere positioned about pt, with a sqr radius of sqrDist. + // - This does *NOT* get *all* points - only some. + // - It should be faster than using findNearestUntagged repeatedly + // for large enough sqrDist. + // - It does not check tags. + void getTreesInSphere(const Point3D &pt, float sqrDist, const BoundCube &domainCube, + std::vector > &contigousBlocks ) const; + + //Obtain a point from its internal index + const Point3D *getPt(size_t index) const ; + + //reset the specified "tags" in the tree + void clearTags(std::vector &tagsToClear); + + size_t getOrigIndex(size_t treeIndex) const ; + + //Set the callback routine for progress reporting + void setCallback(bool (*cb)(bool)) {callback = cb;} + + //Set a pointer that can be used to write the current progress + void setProgressPointer(unsigned int *p) { progress=p;}; + + //Erase tree contents + void clear() { nodes.clear(); indexedPoints.clear();}; + void tag(size_t tagID,bool tagVal=true) ; + + bool getTag(size_t tagID) const ; + + size_t size() const ; + + size_t rootIdx() const { return treeRoot;} + + size_t tagCount() const; + + void clearAllTags(); +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/K3DTree.cpp 3depict-0.0.13/src/backend/filters/K3DTree.cpp --- 3depict-0.0.12/src/backend/filters/K3DTree.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/K3DTree.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,562 @@ +/* + * K3DTree.cpp : 3D Point KD tree + * 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 . + */ +#include "K3DTree.h" + +using std::vector; + + +//Axis compare +//========== +AxisCompare::AxisCompare() : axis(0) +{ +} + +void AxisCompare::setAxis(unsigned int sortAxis) +{ + axis=sortAxis; +} + +//========== + +//K3D node +//========== + +void K3DNode::setLoc(const Point3D &locNew) +{ + loc=locNew; +} + +Point3D K3DNode::getLoc() const +{ + return loc; +} + +void K3DNode::deleteChildren() +{ + + if(childLeft) + { + childLeft->deleteChildren(); + delete childLeft; + childLeft=0; + } + + if(childRight) + { + childRight->deleteChildren(); + delete childRight; + childRight=0; + } + + +} + +void K3DNode::dump(std::ostream &strm, unsigned int depth) const +{ + for(unsigned int ui=0;uidump(strm,depth+1); + + if(childRight) + childRight->dump(strm,depth+1); +} + +//=========== + +//K3D Tree +//============= +K3DTree::K3DTree() : treeSize(0),maxDepth(0),root(0), callback(0),progress(0) +{ +} + + +K3DTree::~K3DTree() +{ + kill(); +} + + +/*void K3DTree::verify() +{ + std::stack nodeStack; + std::stack visitStack; + + K3DNode *curNode; + curNode=root; + unsigned int visit=0; + unsigned int totalVisits; + totalVisits=1; + unsigned int measuredDepth=0; + + std::stack bounds; + + BoundCube curBounds; + + //Set to limits of floating point + curBounds.setInverseLimits(); + bounds.push(curBounds); + + unsigned int curAxis=0; + do + { + //Check to see what the max. depth of the tree really is + if(visitStack.size() > measuredDepth) + measuredDepth=visitStack.size(); + + switch(visit) + { + //Examine left branch + case 0: + { + //verifyChildren(curNode) + if(curNode->left()) + { + curBounds.bounds[curAxis][1] = curNode->getLocVal(curAxis); + totalVisits++; + curAxis++; + + visitStack.push(1); + nodeStack.push(curNode); + + visit=0; + curNode=curNode->left(); + ASSERT(curBounds.containsPt(curNode->getLoc())); + continue; + } + visit++; + break; + } + //Examine right branch + case 1: + { + if(curNode->right()) + { + curBounds.bounds[curAxis][0] = curNode->getLocVal(curAxis); + totalVisits++; + curAxis++; + + visitStack.push(2); + nodeStack.push(curNode); + + visit=0; + curNode=curNode->right(); + ASSERT(curBounds.containsPt(curNode->getLoc())); + continue; + } + visit++; + break; + } + //Go up + case 2: + { + curNode=nodeStack.top(); + nodeStack.pop(); + visit=visitStack.top(); + visitStack.pop(); + curAxis--; + break; + } + } + + //Keep going until we meet the root nde for the third time (one left, one right, one finish) + }while(!(curNode==root && visit== 2)); + + std::cerr << "===COMPARE===" << std::endl; + std::cerr << " -<<>>-" << std::endl; + std::cerr << "Nodes walked : " << totalVisits << std::endl; + std::cerr << "Measered Depth: " << measuredDepth << std::endl; + + std::cerr << " -<<>>-" << std::endl; + std::cerr << "Tree reports # nodes: " << treeSize << std::endl; + std::cerr << "Tree reports Max Depth: " << maxDepth << std::endl; +}*/ + +void K3DTree::kill() +{ + if(root) + { + root->deleteChildren(); + delete root; + root=0; + treeSize=0; + } +} + +//Build the KD tree +void K3DTree::build(vector pts) +{ + //che. to see if the pts vector is empty + if(!pts.size()) + { + maxDepth=0; + return; + } + + if(root) + kill(); + + treeSize=pts.size(); + maxDepth=1; + root=buildRecurse(pts.begin(), pts.end(),0); + +} + +//Build the KD tree, shuffling original +void K3DTree::buildByRef(vector &pts) +{ + //che. to see if the pts vector is empty + if(!pts.size()) + { + maxDepth=0; + return; + } + + if(root) + kill(); + + treeSize=pts.size(); + maxDepth=1; + *progress=0; + curNodeCount=0; + root=buildRecurse(pts.begin(), pts.end(),0); +} + +K3DNode *K3DTree::buildRecurse(vector::iterator pts_start, vector::iterator pts_end, unsigned int depth) +{ + + K3DNode *node= new K3DNode; + unsigned int curAxis=depth%3; + unsigned int ptsSize=pts_end - pts_start - 1;//pts.size()-1 + node->setAxis(curAxis); + + //if we are deeper, then record that + if(depth > maxDepth) + maxDepth=depth; + + unsigned int median =(ptsSize)/2; + + //set up initial node + AxisCompare axisCmp; + axisCmp.setAxis(curAxis); + + //Find the median value in the current axis + sort(pts_start,pts_end,axisCmp); + + //allocate node (this stores a copy of the point) and set. + node->setLoc(*(pts_start + median)); + + if(median) + { + + //Only do process if callback is OK + if((*callback)(false)) + { + node->setLeft(buildRecurse(pts_start,pts_start + median,depth+1)); + *progress= (unsigned int)((float)curNodeCount/(float)treeSize*100.0f); + } + else + node->setLeft(0); + } + else + node->setLeft(0); + + if(median!=ptsSize) + { + //Only do process if callback is OK + if((*callback)(false)) + { + node->setRight(buildRecurse(pts_start + median + 1, pts_end,depth+1)); + *progress= (unsigned int)((float)curNodeCount/(float)treeSize*100.0f); + } + else + node->setRight(0); + + } + else + node->setRight(0); + + curNodeCount++; + return node; + +} + +void K3DTree::dump( std::ostream &strm) const +{ + if(root) + root->dump(strm,0); +} + + +const Point3D *K3DTree::findNearest(const Point3D &searchPt, const BoundCube &domainCube, + const float deadDistSqr) const +{ + enum { NODE_FIRST_VISIT, //First visit is when you descend the tree + NODE_SECOND_VISIT, //Second visit is when you come back from ->Left() + NODE_THIRD_VISIT // Third visit is when you come back from ->Right() + }; + + + //The stacks are for the nodes above the current Node. + const K3DNode *nodeStack[maxDepth+1]; + float domainStack[maxDepth+1][2]; + unsigned int visitStack[maxDepth+1]; + + const Point3D *bestPoint; + const K3DNode *curNode; + + BoundCube curDomain; + unsigned int visit; + unsigned int stackTop; + unsigned int curAxis; + + float bestDistSqr; + float tmpEdge; + + //Set the root as the best estimate + + bestPoint =0; + bestDistSqr =std::numeric_limits::max(); + curDomain=domainCube; + visit=NODE_FIRST_VISIT; + curAxis=0; + + stackTop=0; + + curNode=root; + + do + { + + switch(visit) + { + //Examine left branch + case NODE_FIRST_VISIT: + { + if(searchPt[curAxis] < curNode->getLocVal(curAxis)) + { + if(curNode->left()) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][1]; + curDomain.bounds[curAxis][1] = curNode->getLocVal(curAxis); + if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) + { + curDomain.bounds[curAxis][1] = tmpEdge; + visit++; + continue; + } + + //Preserve our current state. + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. + domainStack[stackTop][1] = tmpEdge; + domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; + stackTop++; + + //Update the current information + curNode=curNode->left(); + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + } + } + else + { + if(curNode->right()) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][0]; + curDomain.bounds[curAxis][0] = curNode->getLocVal(curAxis); + + if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) + { + curDomain.bounds[curAxis][0] =tmpEdge; + visit++; + continue; + } + //Preserve our current state. + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_SECOND_VISIT; //Oh, It will be. It will be. + domainStack[stackTop][0] = tmpEdge; + domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; + stackTop++; + + //Update the information + curNode=curNode->right(); + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + } + + } + visit++; + //Fall through + } + //Examine right branch + case NODE_SECOND_VISIT: + { + if(searchPt[curAxis]< curNode->getLocVal(curAxis)) + { + if(curNode->right()) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][0]; + curDomain.bounds[curAxis][0] = curNode->getLocVal(curAxis); + + if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) + { + curDomain.bounds[curAxis][0] = tmpEdge; + visit++; + continue; + } + + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_THIRD_VISIT; //Oh, It will be. It will be. + domainStack[stackTop][0] = tmpEdge; + domainStack[stackTop][1]= curDomain.bounds[curAxis][1]; + stackTop++; + + //Update the information + curNode=curNode->right(); + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + + } + } + else + { + if(curNode->left()) + { + //Check bounding box when shrunk overlaps best + //estimate sphere + tmpEdge= curDomain.bounds[curAxis][1]; + curDomain.bounds[curAxis][1] = curNode->getLocVal(curAxis); + + if(bestPoint && !curDomain.intersects(*bestPoint,bestDistSqr)) + { + curDomain.bounds[curAxis][1] = tmpEdge; + visit++; + continue; + } + //Preserve our current state. + nodeStack[stackTop]=curNode; + visitStack[stackTop] = NODE_THIRD_VISIT; //Oh, It will be. It will be. + domainStack[stackTop][1] = tmpEdge; + domainStack[stackTop][0]= curDomain.bounds[curAxis][0]; + stackTop++; + + //Update the information + curNode=curNode->left(); + visit=NODE_FIRST_VISIT; + curAxis++; + curAxis%=3; + continue; + + } + } + visit++; + //Fall through + } + //Go up + case NODE_THIRD_VISIT: + { + float tmpDistSqr; + tmpDistSqr = curNode->sqrDist(searchPt); + if(tmpDistSqr < bestDistSqr && tmpDistSqr > deadDistSqr) + { + bestDistSqr = tmpDistSqr; + bestPoint=curNode->getLocRef(); + } + + //DEBUG + ASSERT(stackTop%3 == curAxis) + // + if(curAxis) + curAxis--; + else + curAxis=2; + + + + ASSERT(stackTop < maxDepth+1); + if(stackTop) + { + stackTop--; + visit=visitStack[stackTop]; + curNode=nodeStack[stackTop]; + curDomain.bounds[curAxis][0]=domainStack[stackTop][0]; + curDomain.bounds[curAxis][1]=domainStack[stackTop][1]; + ASSERT((stackTop)%3 == curAxis) + } + + break; + } + default: + ASSERT(false); + + + } + + //Keep going until we meet the root nde for the third time (one left, one right, one finish) + }while(!(curNode==root && visit== NODE_THIRD_VISIT)); + + return bestPoint; + +} + + +void K3DTree::findKNearest(const Point3D &searchPt, const BoundCube &domainCube, + unsigned int num, vector &bestPts, + float deadDistSqr) const +{ + //find the N nearest points + float sqrDist; + bestPts.clear(); + bestPts.reserve(num); + + const Point3D *p; + for(unsigned int ui=0; uisqrDist(searchPt); + deadDistSqr = sqrDist+std::numeric_limits::epsilon(); + + } + +} +//============= diff -Nru 3depict-0.0.12/src/backend/filters/K3DTree.h 3depict-0.0.13/src/backend/filters/K3DTree.h --- 3depict-0.0.12/src/backend/filters/K3DTree.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/K3DTree.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,171 @@ +/* + * K3DTree.h - limited precision KD tree implementation + * 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 . + */ +#ifndef K3DTREE_H +#define K3DTREE_H + + + +#include "common/basics.h" //For BoundCube + +class K3DNode; +class AxisCompare; +class K3DTree; + + +//!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 + * that axis only + */ +class AxisCompare +{ + private: + unsigned int axis; + public: + AxisCompare(); + void setAxis(unsigned int Axis); + inline bool operator()(const Point3D &p1,const Point3D &p2) const + {return p1[axis]::iterator pts_start, + std::vector::iterator pts_end, unsigned int depth ); + + bool (*callback)(bool); + + unsigned int *progress; //Progress counter + size_t curNodeCount; //Counter for build operations + public: + + //KD Tree constructor + K3DTree(); + + //!Cleans up tree, deallocates nodes + ~K3DTree(); + + //Set the callback routine for progress reporting + void setCallbackMethod(bool (*cb)(bool)) {callback = cb;} + + void setProgressPointer(unsigned int *p) { progress=p;}; + + + /*! Builds a balanced KD tree from a list of points + * This call is being passed by copy in order to prevent + * re-ordering of the points. It may be worth having two calls + * a pass by ref version where the points get scrambled and this one + * which preserves input point ordering (due to the copy) + */ + void build(std::vector pts); + + /*! Builds a balanced KD tree from a list of points + * This uses a pass by ref where the points get scrambled (sorted). + * Resultant tree should be identical to that generated by build() + */ + void buildByRef(std::vector &pts); + + + //Tree walker that counts the number of nodes + //void verify(); + + //! Clean the tree + void kill(); + + //!Find the nearest point to a given P that lies outsid some dead zone + /*!deadDistSqr can be used ot disallow exact matching on NN searching + * simply pass epsilon =std::numeric_limits::epsilon() + * (#include ) + * Boundcube is the bounding box around the entire dataset + */ + const Point3D *findNearest(const Point3D &, const BoundCube &, + + float deadDistSqr) const; + + //!Find the nearest N points + /*!Finds the nearest N points, that lie outside a + * dead distance of deadDistSqr. k is the number to find + */ + void findKNearest(const Point3D & sourcePoint, const BoundCube& treeDomain, + unsigned int numNNs, std::vector &results, + float deadDistSqr=0.0f) const; + + //!Textual output of tree. tabs are used to separate different levels of the tree + /*!The output from this function can be quite large for even modest trees. + * Recommended for debugging only*/ + void dump(std::ostream &) const; + + //!Print the number of nodes stored in the tree + inline unsigned int nodeCount() const{return treeSize;}; +}; + + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/allFilter.cpp 3depict-0.0.13/src/backend/filters/allFilter.cpp --- 3depict-0.0.12/src/backend/filters/allFilter.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/allFilter.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * allFilter.cpp - factory functions for filter classes + * 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 . +*/ +#include "allFilter.h" + + +//Filter "factory" type function. If this gets too big, +//we could use a pre-populated hashtable in +//a static class to speed things up. +//returns null pointer if string is invalid +Filter *makeFilter(const std::string &s) +{ + Filter *f; + unsigned int type=(unsigned int)-1; + for(unsigned int ui=0;uitrueName() == s); +#endif + return f; +} + +Filter *makeFilter(unsigned int ui) +{ + Filter *f; + + switch(ui) + { + case FILTER_TYPE_DATALOAD: + f=new DataLoadFilter; + break; + case FILTER_TYPE_IONDOWNSAMPLE: + f=new IonDownsampleFilter; + break; + case FILTER_TYPE_RANGEFILE: + f=new RangeFileFilter; + break; + case FILTER_TYPE_SPECTRUMPLOT: + f=new SpectrumPlotFilter; + break; + case FILTER_TYPE_IONCLIP: + f=new IonClipFilter; + break; + case FILTER_TYPE_IONCOLOURFILTER: + f=new IonColourFilter; + break; + case FILTER_TYPE_IONINFO: + f=new IonInfoFilter; + break; + case FILTER_TYPE_COMPOSITION: + f=new CompositionProfileFilter; + break; + case FILTER_TYPE_BOUNDBOX: + f = new BoundingBoxFilter; + break; + case FILTER_TYPE_TRANSFORM: + f= new TransformFilter; + break; + case FILTER_TYPE_EXTERNALPROC: + f= new ExternalProgramFilter; + break; + case FILTER_TYPE_SPATIAL_ANALYSIS: + f = new SpatialAnalysisFilter; + break; + case FILTER_TYPE_CLUSTER_ANALYSIS: + f = new ClusterAnalysisFilter; + break; + case FILTER_TYPE_VOXELS: + f = new VoxeliseFilter; + break; + case FILTER_TYPE_ANNOTATION: + f = new AnnotateFilter; + break; + default: + ASSERT(false); + } + + return f; +} + +Filter *makeFilterFromDefUserString(const std::string &s) +{ + //This is a bit of a hack. Build each object, then retrieve its string. + //Could probably use static functions and type casts to improve this + for(unsigned int ui=0;uitypeString()) + return t; + + delete t; + } + + ASSERT(false); +} diff -Nru 3depict-0.0.12/src/backend/filters/allFilter.h 3depict-0.0.13/src/backend/filters/allFilter.h --- 3depict-0.0.12/src/backend/filters/allFilter.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/allFilter.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * allFilter.h - Filter class factory 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 . +*/ +#ifndef ALLFILTER_H +#define ALLFILTER_H +#include "boundingBox.h" +#include "ionDownsample.h" +#include "dataLoad.h" +#include "compositionProfile.h" +#include "externalProgram.h" +#include "ionClip.h" +#include "ionColour.h" +#include "rangeFile.h" +#include "clusterAnalysis.h" +#include "spatialAnalysis.h" +#include "spectrumPlot.h" +#include "transform.h" +#include "voxelise.h" +#include "ionInfo.h" +#include "annotation.h" + +//!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_* +Filter *makeFilter(unsigned int ui) ; + +//!Create a true default filter from its type string +Filter *makeFilterFromDefUserString(const string &s) ; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/annotation.cpp 3depict-0.0.13/src/backend/filters/annotation.cpp --- 3depict-0.0.12/src/backend/filters/annotation.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/annotation.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1863 @@ +/* + * annotation.cpp - 3D annotations filter for 3depict + * 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 . +*/ +#include "annotation.h" + +#include "filterCommon.h" + +//grab size when doing convex hull calculations +const unsigned int HULL_GRAB_SIZE=4096; + +enum +{ + KEY_POSITION=1, + KEY_MODE, + KEY_UPVEC, + KEY_ACROSSVEC, + KEY_ANNOTATE_TEXT, + KEY_TARGET, + KEY_COLOUR, + KEY_ARROW_SIZE, + KEY_TEXTSIZE, + KEY_LINESIZE, + KEY_REFLEXIVE, + KEY_SPHERE_ANGLE_SIZE, + KEY_ANGLE_TEXT_VISIBLE, + KEY_ANGLE_FORMAT_STRING, + KEY_LINEAR_FONTSIZE, + KEY_LINEAR_NUMTICKS, + KEY_LINEAR_FIXED_TICKS, + KEY_LINEAR_TICKSPACING, + KEY_ANGLE_POS_ZERO, + KEY_ANGLE_POS_ONE, + KEY_ANGLE_POS_TWO +}; + +enum +{ + BINDING_TEXT_ORIGIN=1, + BINDING_ARROW_ORIGIN, + BINDING_ARROW_VECTOR, + BINDING_ANGLE_ORIGIN, + BINDING_ANGLE_FIRST, + BINDING_ANGLE_SECOND, + BINDING_ANGLE_SPHERERADIUS, + BINDING_LINEAR_ORIGIN, + BINDING_LINEAR_TARGET, + BINDING_LINEAR_SPHERERADIUS +}; + + +const char *annotationModeStrings[] = +{ + NTRANS("Arrow"), + NTRANS("Text"), + NTRANS("Arrow+Text"), + NTRANS("Angle"), + NTRANS("Ruler") +}; + + +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), + reflexAngle(true), angleFormatPreDecimal(0),angleFormatPostDecimal(0), + linearFixedTicks(true),linearMeasureTicks(10),linearMeasureSpacing(10.0f), + fontSizeLinearMeasure(5),linearMeasureMarkerSize(3) +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(annotationModeStrings) == ANNOTATION_MODE_END); + + annotationMode=ANNOTATION_TEXT; + + anglePos[0]=Point3D(0,0,0); + anglePos[1]=Point3D(0,5,5); + anglePos[2]=Point3D(0,-5,5); + + textSize=1; + annotateSize=1; + sphereAngleSize=1.5; + + //Set the colour to default blue + r=g=0;b=a=1.0; + + active=true; + showAngleText=true; + + reflexAngle=false; + fontSizeLinearMeasure=5; + linearMeasureTicks=10; + linearFixedTicks=true; + linearMeasureSpacing=10.0f; + linearMeasureMarkerSize=3.0f; + lineSize=1.0f; + angleFormatPreDecimal=angleFormatPostDecimal=0; + + cacheOK=false; + cache=true; //By default, we should cache, but decision is made higher up +} + +Filter *AnnotateFilter::cloneUncached() const +{ + AnnotateFilter *p=new AnnotateFilter(); + + p->annotationMode=annotationMode; + p->position=position; + p->target=target; + p->upVec=upVec; + p->acrossVec=acrossVec; + + for(unsigned int ui=0;ui<3; ui++) + p->anglePos[ui]=anglePos[ui]; + + p->textSize=textSize; + p->annotateSize=annotateSize; + p->sphereAngleSize=sphereAngleSize; + + p->r=r; + p->g=g; + p->b=b; + p->a=a; + + p->active=active; + p->showAngleText=showAngleText; + + p->reflexAngle=reflexAngle; + + p->angleFormatPreDecimal=angleFormatPreDecimal; + p->angleFormatPostDecimal=angleFormatPostDecimal; + + + p->fontSizeLinearMeasure=fontSizeLinearMeasure; + p->linearFixedTicks=linearFixedTicks; + p->linearMeasureSpacing=linearMeasureSpacing; + p->linearMeasureTicks=linearMeasureTicks; + p->linearMeasureMarkerSize=linearMeasureMarkerSize; + p->lineSize=lineSize; + + //We are copying whether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +unsigned int AnnotateFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + + //Clear selection devices, first deleting any we have + clearDevices(); + + //Pipe everything through + getOut.resize(dataIn.size()); + for(size_t ui=0;uiparent=this; + + //Draw text output as needed + if( annotationMode == ANNOTATION_TEXT || + annotationMode== ANNOTATION_TEXT_WITH_ARROW) + { + DrawGLText *dt; + dt = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); + + dt->setString(annotateText); + dt->setOrigin(position); + dt->setUp(upVec); + dt->setColour(r,g,b,a); + dt->setTextDir(acrossVec); + dt->setSize((unsigned int)textSize); + + dt->setAlignment(DRAWTEXT_ALIGN_CENTRE); + + dt->canSelect=true; + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding bind[1]; + + bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_TEXT_BIND_ORIGIN, + BINDING_TEXT_ORIGIN,dt->getOrigin(),dt); + bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(bind[0]); + + + devices.push_back(s); + d->drawables.push_back(dt); + } + + //Draw annotation mode as needed + if(annotationMode==ANNOTATION_ARROW || + annotationMode==ANNOTATION_TEXT_WITH_ARROW) + { + DrawVector *dv; + dv = new DrawVector; + + dv->setOrigin(position); + dv->setVector(target-position); + dv->setArrowSize(annotateSize); + dv->setColour(r,g,b,a); + dv->setLineSize(lineSize); + + dv->canSelect=true; + dv->wantsLight=true; + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding bind[2]; + + bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_VECTOR_BIND_TARGET, + BINDING_ARROW_VECTOR,dv->getVector(),dv); + bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(bind[0]); + + + bind[1].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_VECTOR_BIND_ORIGIN, + BINDING_ARROW_ORIGIN,dv->getOrigin(),dv); + bind[1].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(bind[1]); + + + devices.push_back(s); + d->drawables.push_back(dv); + } + + if(annotationMode == ANNOTATION_ANGLE_MEASURE) + { + //Draw the three spheres that are the handles + //for the angle motion + for(unsigned int ui=0;ui<3;ui++) + { + DrawSphere *dS; + SelectionDevice *s= new SelectionDevice(this); + SelectionBinding bind[2]; + + dS=new DrawSphere; + dS->setOrigin(anglePos[ui]); + dS->setRadius(sphereAngleSize); + dS->setColour(r,g,b,a); + + dS->canSelect=true; + dS->wantsLight=true; + + //Create binding for sphere translation. + //Note that each binding is a bit different, as it + //affects each sphere separately. + bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, + BINDING_ANGLE_ORIGIN+ui,anglePos[ui],dS); + bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(bind[0]); + + //Create binding for sphere scaling, each binding is the same + bind[1].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_SPHERE_BIND_RADIUS, + BINDING_ANGLE_SPHERERADIUS,dS->getRadius(),dS); + bind[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + bind[1].setFloatLimits(0,std::numeric_limits::max()); + + s->addBinding(bind[1]); + + devices.push_back(s); + d->drawables.push_back(dS); + } + + //Now draw the two lines that form the angle + DrawVector *dv; + dv=new DrawVector; + dv->setOrigin(anglePos[0]); + dv->setVector(anglePos[1]-anglePos[0]); + dv->setColour(r,g,b,a); + dv->setDrawArrow(false); + d->drawables.push_back(dv); + + dv=new DrawVector; + dv->setOrigin(anglePos[0]); + dv->setVector(anglePos[2]-anglePos[0]); + dv->setColour(r,g,b,a); + dv->setDrawArrow(false); + d->drawables.push_back(dv); + + + //If required, + //show the text that + //indicates the included or reflexive angle + if(showAngleText) + { + std::string angleString; + + Point3D d1,d2; + float angleVal=0; + + d1=anglePos[1]-anglePos[0]; + d2=anglePos[2]-anglePos[0]; + + //Work out the angle if there is a non-degenerate vector. + //otherwise set it to the "undefined" value of zero + if(fabs(d1.dotProd(d2)) > sqrt(std::numeric_limits::epsilon())) + angleVal =d1.angle(d2); + + if(reflexAngle) + angleVal=2.0*M_PI-angleVal; + angleVal=180.0f/M_PI*angleVal; + angleVal=fmod(angleVal,360.0f); + + //FIXME: print specifier computation is still a bit off + if(angleFormatPreDecimal+angleFormatPostDecimal) + { + //One space for the decimal, one for the null + //and the rest for the actual integer + size_t num; + num = angleFormatPreDecimal+angleFormatPostDecimal+1; + char *buf = new char[num+1]; + + std::string tmp,formatStr; + formatStr="%"; + if(angleFormatPreDecimal) + { + + stream_cast(tmp,angleFormatPreDecimal + angleFormatPostDecimal+2); + formatStr+=std::string("0") + tmp; + } + + if(angleFormatPostDecimal) + { + + stream_cast(tmp,angleFormatPostDecimal); + formatStr+="."; + formatStr+=tmp; + } + formatStr+="f"; + + snprintf(buf,num,formatStr.c_str(),angleVal); + angleString=buf; + delete[] buf; + + } + else + stream_cast(angleString, angleVal); + + //Place the string appropriately + DrawGLText *dt; + dt = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); + + dt->setString(angleString); + dt->setAlignment(DRAWTEXT_ALIGN_CENTRE); + //Place the text using + //a factor of the text size in + //the direction of the average + //of the two vector components + Point3D averageVec(1,0,0); + if(averageVec.sqrMag() > std::numeric_limits::epsilon()) + { + averageVec = (d1+d2)*0.5f; + averageVec.normalise(); + averageVec*=textSize*1.1; + if(reflexAngle) + averageVec.negate(); + } + dt->setOrigin(anglePos[0]+averageVec); + //Use user-specifications for colour, + //size and orientation + dt->setUp(upVec); + dt->setColour(r,g,b,a); + dt->setTextDir(acrossVec); + dt->setSize((unsigned int)textSize); + + + d->drawables.push_back(dt); + } + } + + if(annotationMode == ANNOTATION_LINEAR_MEASURE) + { + DrawVector *dv; + dv = new DrawVector; + + dv->setOrigin(position); + dv->setColour(r,g,b,a); + dv->setVector(target-position); + dv->setDrawArrow(false); + + d->drawables.push_back(dv); + + //Compute the tick spacings + vector tickSpacings; + if(linearFixedTicks) + { + tickSpacingsFromFixedNum(0,sqrt(target.sqrDist(position)), + linearMeasureTicks,tickSpacings); + } + else + { + tickSpacingsFromInterspace(0,sqrt(target.sqrDist(position)), + linearMeasureSpacing,tickSpacings); + } + + if(tickSpacings.size()) + { + + Point3D measureNormal; + measureNormal = target-position; + measureNormal.normalise(); + + //Construct the drawable text object + for(unsigned int ui=0;uisetColour(r,g,b,a); + dT->setOrigin(measureNormal*tickSpacings[ui] + position); + dT->setUp(upVec); + dT->setTextDir(acrossVec); + dT->setSize((unsigned int)fontSizeLinearMeasure); + + string s; + stream_cast(s,tickSpacings[ui]); + + dT->setString(s); + + d->drawables.push_back(dT); + } + + + //Now draw the end markers + + //Start marker + DrawSphere *dS; + dS = new DrawSphere; + dS->setRadius(linearMeasureMarkerSize); + dS->setOrigin(position); + dS->setColour(r,g,b,a); + + dS->canSelect=true; + dS->wantsLight=true; + + SelectionDevice *s= new SelectionDevice(this); + SelectionBinding bind[4]; + //Create binding for sphere translation. + //Note that each binding is a bit different, as it + //affects each sphere separately. + bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, + BINDING_LINEAR_ORIGIN,position,dS); + bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(bind[0]); + + //Create binding for sphere scaling, each binding is the same + bind[1].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_SPHERE_BIND_RADIUS, + BINDING_LINEAR_SPHERERADIUS,dS->getRadius(),dS); + bind[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + bind[1].setFloatLimits(0,std::numeric_limits::max()); + + s->addBinding(bind[1]); + + devices.push_back(s); + d->drawables.push_back(dS); + + + //Now do the second sphere (end marker) + s= new SelectionDevice(this); + dS = new DrawSphere; + + dS->setRadius(linearMeasureMarkerSize); + dS->setOrigin(target); + dS->setColour(r,g,b,a); + + dS->canSelect=true; + dS->wantsLight=true; + + bind[2].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, + BINDING_LINEAR_TARGET,target,dS); + bind[2].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(bind[2]); + + //Create binding for sphere scaling, each binding is the same + bind[3].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_SPHERE_BIND_RADIUS, + BINDING_LINEAR_SPHERERADIUS,dS->getRadius(),dS); + bind[3].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + bind[3].setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(bind[3]); + + + devices.push_back(s); + d->drawables.push_back(dS); + + + } + } + + d->cached=0; + getOut.push_back(d); + + return 0; +} + +size_t AnnotateFilter::numBytesForCache(size_t nObjects) const +{ + return 0; +} + +void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const +{ + string str; + FilterProperty p; + size_t curGroup=0; + + vector > choices; + string tmpStr; + + for(unsigned int ui=0;ui::epsilon()) + return false; + + acrossVec=normVec.crossProd(newPt); + + ASSERT(acrossVec.sqrMag() > std::numeric_limits::epsilon()); + + if(!(upVec == newPt)) + { + upVec=newPt; + needUpdate=true; + } + + break; + } + case KEY_ACROSSVEC: + { + //This sets the up direction + //which must be normal to the + //across direction for the text. + // + //Compute the normal component of acrossVec. + //and override that. + // + //Be careful not to "invert" the text, so it + //does not show. + Point3D newPt; + if(!newPt.parse(value)) + return false; + newPt.normalise(); + + //Use double-cross-product method + //to orthogonalise the two vectors + Point3D normVec; + normVec=newPt.crossProd(upVec); + + if(normVec.sqrMag() < std::numeric_limits::epsilon()) + return false; + + upVec=normVec.crossProd(newPt); + + ASSERT(upVec.sqrMag() > std::numeric_limits::epsilon()); + + if(!(acrossVec == newPt)) + { + acrossVec=newPt; + needUpdate=true; + } + + break; + } + case KEY_POSITION: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(acrossVec == newPt)) + { + position=newPt; + needUpdate=true; + } + + break; + } + case KEY_TARGET: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(target== newPt)) + { + target=newPt; + needUpdate=true; + } + + break; + } + case KEY_ANGLE_POS_ZERO: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(anglePos[0]== newPt)) + { + anglePos[0]=newPt; + needUpdate=true; + } + break; + } + case KEY_ANGLE_POS_ONE: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(anglePos[1]== newPt)) + { + anglePos[1]=newPt; + needUpdate=true; + } + break; + } + case KEY_ANGLE_POS_TWO: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(anglePos[2]== newPt)) + { + anglePos[2]=newPt; + needUpdate=true; + } + break; + } + case KEY_ARROW_SIZE: + { + float tmp; + if(stream_cast(tmp,value)) + return false; + + if(tmp!=annotateSize) + { + annotateSize=tmp; + needUpdate=true; + } + + break; + } + case KEY_ANNOTATE_TEXT: + { + if(value!=annotateText) + { + needUpdate=true; + annotateText=value; + } + + break; + } + case KEY_COLOUR: + { + unsigned char newR,newG,newB,newA; + + parseColString(value,newR,newG,newB,newA); + + if(newB != b || newR != r || + newG !=g || newA != a) + { + r=(float)newR/255.0; + g=(float)newG/255.0; + b=(float)newB/255.0; + a=(float)newA/255.0; + + needUpdate=true; + } + else + needUpdate=false; + break; + } + case KEY_TEXTSIZE: + { + float tmp; + stream_cast(tmp,value); + if(fabs(tmp-textSize) > std::numeric_limits::epsilon() + && tmp > sqrt(std::numeric_limits::epsilon())) + { + needUpdate=true; + textSize=tmp; + } + + break; + } + case KEY_REFLEXIVE: + { + bool tmp; + tmp=(value=="1"); + + if(tmp==reflexAngle) + return false; + + reflexAngle=tmp; + + needUpdate=true; + break; + } + case KEY_SPHERE_ANGLE_SIZE: + { + float tmp; + stream_cast(tmp,value); + + if(tmp == sphereAngleSize) + return false; + + sphereAngleSize=tmp; + needUpdate=true; + + break; + } + case KEY_ANGLE_TEXT_VISIBLE: + { + bool tmp; + tmp=(value=="1"); + + if(tmp == showAngleText) + return false; + + showAngleText=tmp; + needUpdate=true; + + break; + } + + case KEY_ANGLE_FORMAT_STRING: + { + //Must contain only #,[0-9] + if(value.find_first_not_of("#,.0123456789")!=std::string::npos) + return false; + + if(value.size()) + { + //Must contain 0 or 1 separator. + size_t sepCount; + sepCount=std::count(value.begin(),value.end(),','); + sepCount+=std::count(value.begin(),value.end(),'.'); + if(sepCount > 1) + return false; + + //If we have a separator, + //split into two parts + if(sepCount) + { + size_t decPos; + decPos=value.find_first_of(",."); + angleFormatPreDecimal=decPos; + angleFormatPostDecimal=value.size()-(decPos+1); + } + else + angleFormatPreDecimal=value.size(); + + } + else + angleFormatPreDecimal=angleFormatPostDecimal=0; + + needUpdate=true; + break; + } + + case KEY_LINEAR_FONTSIZE: + { + unsigned int tmp; + stream_cast(tmp,value); + + if(tmp == fontSizeLinearMeasure) + return false; + + fontSizeLinearMeasure=tmp; + needUpdate=true; + break; + } + case KEY_LINEAR_FIXED_TICKS: + { + bool tmpTicks; + + if(value == "0") + tmpTicks=false; + else if(value =="1") + tmpTicks=true; + else + return false; + + if(tmpTicks == linearFixedTicks) + return false; + + needUpdate=true; + linearFixedTicks=tmpTicks; + break; + + } + case KEY_LINEAR_NUMTICKS: + { + unsigned int tmp; + stream_cast(tmp,value); + + if(tmp == linearMeasureTicks) + return false; + + linearMeasureTicks=tmp; + needUpdate=true; + + break; + } + case KEY_LINEAR_TICKSPACING: + { + float tmp; + stream_cast(tmp,value); + + if(tmp == linearMeasureSpacing) + return false; + + linearMeasureSpacing=tmp; + needUpdate=true; + + break; + } + case KEY_LINESIZE: + { + float tmp; + stream_cast(tmp,value); + + if(tmp == lineSize || tmp <0) + return false; + + lineSize=tmp; + needUpdate=true; + break; + } + + default: + ASSERT(false); + } + + return true; +} + +std::string AnnotateFilter::getErrString(unsigned int code) const +{ + ASSERT(false); +} + +bool AnnotateFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + for(unsigned int ui=0;ui<3;ui++) + f << tabs(depth+2) << "" << endl; + f << tabs(depth+1) << "" << endl; + + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + std::string colourString; + genColString((unsigned char)(r*255),(unsigned char)(g*255), + (unsigned char)(b*255),(unsigned char)(a*255),colourString); + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool AnnotateFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + using std::string; + string tmpStr; + + xmlChar *xmlString; + + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Annotation mode + if(!XMLGetNextElemAttrib(nodePtr,annotationMode,"annotationmode","value")) + return false; + + if(annotationMode >=ANNOTATION_MODE_END) + return false; + + //position + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"position","value")) + return false; + + if(!position.parse(tmpStr)) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"target","value")) + return false; + + if(!target.parse(tmpStr)) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"upvec","value")) + return false; + + if(!upVec.parse(tmpStr)) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"acrossvec","value")) + return false; + + if(!acrossVec.parse(tmpStr)) + return false; + + //Ensure acrossVec/upvec orthogonal + if(!upVec.orthogonalise(acrossVec)) + return false; + + xmlNodePtr tmpPtr; + tmpPtr=nodePtr; + + if(XMLHelpFwdToElem(nodePtr,"anglepos")) + return false; + + if(!nodePtr->xmlChildrenNode) + return false; + + nodePtr=nodePtr->xmlChildrenNode; + + for(unsigned int ui=0;ui<3;ui++) + { + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"position","value")) + return false; + + if(!anglePos[ui].parse(tmpStr)) + return false; + } + + nodePtr=tmpPtr; + + //If it fails, thats OK, just use the empty string. + if(!XMLGetNextElemAttrib(nodePtr,annotateText,"annotatetext","value")) + annotateText=""; + + if(!XMLGetNextElemAttrib(nodePtr,textSize,"textsize","value")) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,annotateSize,"annotatesize","value")) + return false; + + if(annotateSize <0.0f) + return false; + + + if(!XMLGetNextElemAttrib(nodePtr,sphereAngleSize,"sphereanglesize","value")) + return false; + if(sphereAngleSize<0.0f) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,lineSize,"linesize","value")) + return false; + if(lineSize<0.0f) + return false; + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"colour","value")) + return false; + + unsigned char rc,gc,bc,ac; + if(!parseColString(tmpStr,rc,gc,bc,ac)) + return false; + r=(float)(rc)/255.0f; + g=(float)(gc)/255.0f; + b=(float)(bc)/255.0f; + a=(float)(ac)/255.0f; + + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"active","value")) + return false; + + if(!(tmpStr=="0" || tmpStr=="1")) + return false; + + active = (tmpStr=="1"); + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"showangletext","value")) + return false; + + if(!(tmpStr=="0" || tmpStr=="1")) + return false; + + showAngleText = (tmpStr=="1"); + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"reflexangle","value")) + return false; + + if(!(tmpStr=="0" || tmpStr=="1")) + return false; + + reflexAngle = (tmpStr=="1"); + + if(!XMLGetNextElemAttrib(nodePtr,angleFormatPreDecimal,"angleformat","predecimal")) + return false; + + if(!XMLGetAttrib(nodePtr,angleFormatPostDecimal,"predecimal")) + return false; + + + return true; +} + +unsigned int AnnotateFilter::getRefreshBlockMask() const +{ + return 0; +} + +unsigned int AnnotateFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_DRAW; +} + +unsigned int AnnotateFilter::getRefreshUseMask() const +{ + //annotate only adds to the ignore mask, so + // we now essentially ignore all inputs, other than pass-through + return 0; +} + +void AnnotateFilter::setPropFromBinding(const SelectionBinding &b) +{ + switch(b.getID()) + { + case BINDING_ARROW_ORIGIN: + { + Point3D dv; + dv=target-position; + b.getValue(position); + target=position+dv; + break; + } + case BINDING_LINEAR_ORIGIN: + case BINDING_TEXT_ORIGIN: + { + b.getValue(position); + break; + } + case BINDING_LINEAR_TARGET: + case BINDING_ARROW_VECTOR: + { + b.getValue(target); + break; + } + case BINDING_ANGLE_ORIGIN: + b.getValue(anglePos[0]); + break; + case BINDING_ANGLE_FIRST: + b.getValue(anglePos[1]); + break; + case BINDING_ANGLE_SECOND: + b.getValue(anglePos[2]); + break; + case BINDING_ANGLE_SPHERERADIUS: + b.getValue(sphereAngleSize); + break; + default: + ASSERT(false); + } +} + + +#ifdef DEBUG + +//Test the ruler functionality +bool rulerTest(); +//Test the angle measurement tool +bool angleTest(); +//Test the pointing arrow annotation +bool arrowTest(); +//Test the text+arrow functionality +bool textArrowTest(); + + +bool AnnotateFilter::runUnitTests() +{ + if(!rulerTest()) + return false; + + if(!angleTest()) + return false; + + if(!arrowTest()) + return false; + + if(!textArrowTest()) + return false; + + return true; +} + + +bool rulerTest() +{ + vector streamIn,streamOut; + AnnotateFilter*f=new AnnotateFilter; + f->setCaching(false); + + bool needUp; std::string s; + //Set linear ruler mode + TEST(f->setProperty(KEY_MODE,TRANS(annotationModeStrings[ANNOTATION_LINEAR_MEASURE]),needUp),"Set prop"); + //Set ruler position & length + stream_cast(s,Point3D(0,0,0)); + TEST(f->setProperty(KEY_POSITION,s,needUp),"Set prop"); + stream_cast(s,Point3D(1,1,1)); + TEST(f->setProperty(KEY_TARGET,s,needUp),"Set prop"); + stream_cast(s,sqrt(2)/10); + TEST(f->setProperty(KEY_LINEAR_TICKSPACING,s,needUp),"Set prop"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + + delete f; + + + TEST(streamOut.size(),"stream size"); + + //Count the number of text object types + size_t textCount,vecCount,otherDrawCount; + textCount=vecCount=otherDrawCount=0; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_DRAW: + { + const DrawStreamData* d; + d= (const DrawStreamData*)streamOut[ui]; + for(unsigned int ui=0;uidrawables.size();ui++) + { + switch(d->drawables[ui]->getType()) + { + case DRAW_TYPE_GLTEXT: + textCount++; + break; + case DRAW_TYPE_VECTOR: + vecCount++; + break; + default: + otherDrawCount++; + break; + } + + } + break; + } + default: + ; + } + + } + + //We should have a line, one would hope + TEST(vecCount>0,"Number of lines in ruler test"); + //Floating pt errors, and not setting the zero could alter this + //so it should be close to, but not exactly 10 + TEST(textCount == 10 || textCount == 9 || textCount == 11, + "Number of lines in ruler test"); + + for(unsigned int ui=0;ui streamIn,streamOut; + AnnotateFilter*f=new AnnotateFilter; + f->setCaching(false); + + bool needUp; std::string s; + //Set arrow annotation mode + TEST(f->setProperty(KEY_MODE, + TRANS(annotationModeStrings[ANNOTATION_ANGLE_MEASURE]),needUp),"set property"); + //Set position & target for arrow + const Point3D ANGLE_ORIGIN(0,0,0); + const Point3D ANGLE_A(0,0,1); + const Point3D ANGLE_B(0,1,0); + stream_cast(s,ANGLE_ORIGIN); + TEST(f->setProperty(KEY_ANGLE_POS_ONE,s,needUp),"Set prop"); + stream_cast(s,ANGLE_A); + TEST(f->setProperty(KEY_ANGLE_POS_ZERO,s,needUp),"Set prop"); + stream_cast(s,ANGLE_B); + TEST(f->setProperty(KEY_ANGLE_POS_TWO,s,needUp),"Set prop"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + + delete f; + + + + TEST(streamOut.size(),"stream size"); + + //Count the number of text object types + size_t vecCount,otherDrawCount,textDrawCount,sphereDrawCount; + vecCount=otherDrawCount=textDrawCount=sphereDrawCount=0; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_DRAW: + { + const DrawStreamData* d; + d= (const DrawStreamData*)streamOut[ui]; + for(unsigned int ui=0;uidrawables.size();ui++) + { + switch(d->drawables[ui]->getType()) + { + case DRAW_TYPE_VECTOR: + vecCount++; + break; + case DRAW_TYPE_GLTEXT: + textDrawCount++; + break; + case DRAW_TYPE_SPHERE: + sphereDrawCount++; + break; + default: + otherDrawCount++; + break; + } + + } + break; + } + default: + ; + } + } + + + TEST(textDrawCount,"angle text drawable"); + TEST(vecCount,"angle arms drawable"); + TEST(sphereDrawCount,"sphere marker drawable"); + TEST(!otherDrawCount,"unexpected drawable in angle measure"); + + for(unsigned int ui=0;ui streamIn,streamOut; + AnnotateFilter*f=new AnnotateFilter; + f->setCaching(false); + + bool needUp; std::string s; + //Set arrow annotation mode + TEST(f->setProperty(KEY_MODE, + TRANS(annotationModeStrings[ANNOTATION_ARROW]),needUp),"Set arrow mode Property"); + //Set position & target for arrow + const Point3D ARROW_ORIGIN(-1,-1,-1); + const Point3D ARROW_TARGET(1,1,1); + stream_cast(s,ARROW_ORIGIN); + TEST(f->setProperty(KEY_POSITION,s,needUp),"Set position prop"); + stream_cast(s,ARROW_TARGET); + TEST(f->setProperty(KEY_TARGET,s,needUp),"Set target prop"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + + delete f; + + + TEST(streamOut.size(),"stream size"); + + //Count the number of text object types + size_t vecCount,otherDrawCount; + vecCount=otherDrawCount=0; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_DRAW: + { + const DrawStreamData* d; + d= (const DrawStreamData*)streamOut[ui]; + for(unsigned int ui=0;uidrawables.size();ui++) + { + switch(d->drawables[ui]->getType()) + { + case DRAW_TYPE_VECTOR: + { + vecCount++; + const DrawVector *dv; + dv= (const DrawVector*)d->drawables[ui]; + bool testV; + testV=(dv->getOrigin() == ARROW_ORIGIN); + TEST(testV,"Origin test"); + break; + } + default: + otherDrawCount++; + break; + } + + } + break; + } + default: + ; + } + + } + + //We should have a line, one would hope + TEST(vecCount==1,"Number of lines"); + TEST(otherDrawCount==0,"Draw count"); + + for(unsigned int ui=0;ui streamIn,streamOut; + AnnotateFilter*f=new AnnotateFilter; + f->setCaching(false); + + bool needUp; std::string s; + //Set linear ruler mode + TEST(f->setProperty(KEY_MODE, + TRANS(annotationModeStrings[ANNOTATION_TEXT_WITH_ARROW]),needUp),"Set Property"); + //Set ruler position & length + const Point3D ARROW_ORIGIN(-1,-1,-1); + const Point3D ARROW_TARGET(1,1,1); + stream_cast(s,ARROW_ORIGIN); + TEST(f->setProperty(KEY_POSITION,s,needUp),"Set prop"); + stream_cast(s,ARROW_TARGET); + TEST(f->setProperty(KEY_TARGET,s,needUp),"Set prop"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + + delete f; + + + TEST(streamOut.size(),"stream size"); + + //Count the number of text object types + size_t vecCount,textCount,otherDrawCount; + vecCount=textCount=otherDrawCount=0; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_DRAW: + { + const DrawStreamData* d; + d= (const DrawStreamData*)streamOut[ui]; + for(unsigned int ui=0;uidrawables.size();ui++) + { + switch(d->drawables[ui]->getType()) + { + case DRAW_TYPE_VECTOR: + { + vecCount++; + const DrawVector *dv; + dv= (const DrawVector*)d->drawables[ui]; + bool testV; + testV=(dv->getOrigin() == ARROW_ORIGIN); + TEST(testV,"Origin test"); + break; + } + case DRAW_TYPE_GLTEXT: + textCount++; + break; + default: + otherDrawCount++; + break; + } + + } + break; + } + default: + ; + } + + } + + //We should have a line, one would hope + TEST(vecCount==1,"Number of lines"); + TEST(textCount==1,"Number of text objects"); + TEST(otherDrawCount==0,"No other draw items"); + + for(unsigned int ui=0;ui. +*/ +#ifndef ANNOTATION_H +#define ANNOTATION_H + +#include "../filter.h" +#include "../../common/translation.h" + +enum +{ + ANNOTATION_ARROW, + ANNOTATION_TEXT, + ANNOTATION_TEXT_WITH_ARROW, + ANNOTATION_ANGLE_MEASURE, + ANNOTATION_LINEAR_MEASURE, + ANNOTATION_MODE_END +}; + +//!Filter to place drawing objects to help annotate +// the 3D scene +class AnnotateFilter : public Filter +{ + private: + //what style of annotation are we using? + unsigned int annotationMode; + //Position of annotation, thing to point at and text up/across vectors + Point3D position, target, upVec,acrossVec; + //Positions for angle measurement + Point3D anglePos[3]; + //annotation text string + std::string annotateText; + //Text display style, arrow annotation size, handle size for angle spheres + float textSize,annotateSize,sphereAngleSize,lineSize; + + //Annotation colour + float r,g,b,a; + + //Disable/enable annotation + bool active; + + // Show included angle text + bool showAngleText; + + //Show reflexive angle, instead of included angle when using angle annot. + bool reflexAngle; + + //Angle format to use in 3D scene + unsigned int angleFormatPreDecimal,angleFormatPostDecimal; + + //Using fixed spacings or not + bool linearFixedTicks; + //Number of ticks to use in linear measure + unsigned int linearMeasureTicks; + + //Spacing to use between ticks if using fixed spacings + float linearMeasureSpacing; + + //Font-size for linear measure object + float fontSizeLinearMeasure; + + //Measure end-marker size + float linearMeasureMarkerSize; + public: + //!Constructor + AnnotateFilter(); + + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //!Apply filter to new data, updating cache as needed. Vector + // of returned pointers must be deleted manually, first checking + // ->cached. + unsigned int refresh(const std::vector &dataIn, + std::vector &dataOut, + ProgressData &progress, bool (*callback)(bool)); + //!Get (approx) number of bytes required for cache + size_t numBytesForCache(size_t nObjects) const; + + //!return type ID + unsigned int getType() const { return FILTER_TYPE_ANNOTATION;} + + //!Return filter type as std::string + std::string typeString() const { return std::string(TRANS("Annotation"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter, + //!needUpdate tells us if filter output changes due to property set + bool setProperty( unsigned int key, + const std::string &value, bool &needUpdate); + + + void setPropFromBinding( const SelectionBinding &b) ; + + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + /* Current supported formats are STATE_FORMAT_XML + */ + bool writeState(std::ostream &f, unsigned int format, + unsigned int depth) const; + + //!Read state from XML stream, using xml format + /* Current supported formats are STATE_FORMAT_XML + */ + bool readState(xmlNodePtr& n, const std::string &packDir=""); + + //!Get the bitmask encoded list of filterStreams that this filter blocks from propagation. + // i.e. if this filterstream is passed to refresh, it is not emitted. + // This MUST always be consistent with ::refresh for filters current state. + unsigned int getRefreshBlockMask() const; + + //!Get the bitmask encoded list of filterstreams that this filter emits from ::refresh. + // This MUST always be consistent with ::refresh for filters current state. + unsigned int getRefreshEmitMask() const; + + //!Get the refresh's ignore mask - filter streams that will not be considered + // as part of the computation + unsigned int getRefreshUseMask() const; + + //Can we be a useful filter, even if given no input specified by the Use mask? + virtual bool isUsefulAsAppend() const { return true;} +#ifdef DEBUG + bool runUnitTests(); +#endif +}; + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/boundingBox.cpp 3depict-0.0.13/src/backend/filters/boundingBox.cpp --- 3depict-0.0.12/src/backend/filters/boundingBox.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/boundingBox.cpp 2013-04-10 20:39:16.000000000 +0000 @@ -0,0 +1,1165 @@ +/* + * boundingBox.cpp - Place a bounding box around point datasets + * 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 . +*/ +#include "boundingBox.h" + +#include "filterCommon.h" + +enum +{ + KEY_VISIBLE=1, + KEY_COUNT_X, + KEY_COUNT_Y, + KEY_COUNT_Z, + KEY_FONTSIZE, + KEY_FONTCOLOUR, + KEY_FIXEDOUT, + KEY_LINECOLOUR, + KEY_LINEWIDTH, + KEY_SPACING_X, + KEY_SPACING_Y, + KEY_SPACING_Z, + KEY_STYLE +}; + +enum +{ + BOUNDINGBOX_ABORT_ERR, +}; + + +enum +{ + BOUND_STYLE_BOX_ONLY, + BOUND_STYLE_TICKS, + BOUND_STYLE_DIMENSION, + BOUND_STYLE_ENUM_END +}; + +const char *BOUND_STYLE[] = +{ + NTRANS("Box only"), + NTRANS("Tick"), + NTRANS("Dimension") +}; + + +//=== Bounding box filter == + + +BoundingBoxFilter::BoundingBoxFilter() : isVisible(true), boundStyle(BOUND_STYLE_TICKS), + fixedNumTicks(true), fontSize(5), rLine(0.0f), gLine(0.0f), bLine(1.0f), aLine(1.0f), + lineWidth(2.0f), threeDText(true) +{ + for(unsigned int ui=0;ui<3;ui++) + { + numTicks[ui]=12; + tickSpacing[ui]=5.0f; + } + + + cacheOK=false; + cache=false; +} + +Filter *BoundingBoxFilter::cloneUncached() const +{ + BoundingBoxFilter *p=new BoundingBoxFilter(); + p->fixedNumTicks=fixedNumTicks; + for(unsigned int ui=0;ui<3;ui++) + { + p->numTicks[ui]=numTicks[ui]; + p->tickSpacing[ui]=tickSpacing[ui]; + } + + p->isVisible=isVisible; + p->boundStyle=boundStyle; + + + p->rLine=rLine; + p->gLine=gLine; + p->bLine=bLine; + p->aLine=aLine; + p->threeDText=threeDText; + + p->lineWidth=lineWidth; + p->fontSize=fontSize; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +size_t BoundingBoxFilter::numBytesForCache(size_t nObjects) const +{ + //Say we don't know, we are not going to cache anyway. + return (size_t)-1; +} + +void BoundingBoxFilter::drawTicks(const BoundCube &bTotal, DrawStreamData *d) const +{ + + //Add the rectangle drawable + DrawRectPrism *dP = new DrawRectPrism; + dP->setAxisAligned(bTotal); + dP->setColour(rLine,gLine,bLine,aLine); + dP->setLineWidth(lineWidth); + d->drawables.push_back(dP); + + //Add the tick drawables + Point3D tickOrigin,tickEnd; + bTotal.getBounds(tickOrigin,tickEnd); + + float tmpTickSpacing[3]; + float tmpTickCount[3]; + if(fixedNumTicks) + { + for(unsigned int ui=0; ui<3;ui++) + { + ASSERT(numTicks[ui]); + tmpTickSpacing[ui]=( (tickEnd[ui] - tickOrigin[ui])/(float)(numTicks[ui]-1)); + tmpTickCount[ui]=numTicks[ui]; + } + } + else + { + for(unsigned int ui=0; ui<3;ui++) + { + ASSERT(numTicks[ui]); + tmpTickSpacing[ui]= tickSpacing[ui]; + tmpTickCount[ui]=(unsigned int)((tickEnd[ui] - tickOrigin[ui])/tickSpacing[ui])+1; + } + } + + //Draw the ticks on the box perimeter. + for(unsigned int ui=0;ui<3;ui++) + { + Point3D tickVector; + Point3D tickPosition; + Point3D textVector; + + tickPosition=tickOrigin; + switch(ui) + { + case 0: + tickVector=Point3D(0,-1,-1); + textVector=Point3D(0,1,0); + break; + case 1: + tickVector=Point3D(-1,0,-1); + textVector=Point3D(1,0,0); + break; + case 2: + tickVector=Point3D(-1,-1,0); + textVector=Point3D(1,1,0); + break; + } + + //TODO: This would be more efficient if we made some kind of + //"comb" class? + //Allow up to 128 chars + char buffer[128]; + for(unsigned int uj=0;ujsetDrawArrow(false); + dV->setOrigin(tickPosition); + dV->setVector(tickVector); + dV->setColour(rLine,gLine,bLine,aLine); + + d->drawables.push_back(dV); + + + //Don't draw the 0 value, as this gets repeated. + //we will handle this separately + if(uj) + { + DrawGLText *dT; + //Draw the tick text + if( threeDText) + dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); + else + dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_BITMAP); + float f; + f = tmpTickSpacing[ui]*uj; + snprintf(buffer,127,"%2.0f",f); + dT->setString(buffer); + dT->setSize(fontSize); + + dT->setColour(rLine,gLine,bLine,aLine); + dT->setOrigin(tickPosition + tickVector*2); + dT->setUp(Point3D(0,0,1)); + dT->setTextDir(textVector); + dT->setAlignment(DRAWTEXT_ALIGN_RIGHT); + + d->drawables.push_back(dT); + } + } + + } + + DrawGLText *dT; + if(threeDText) + dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); + else + dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_BITMAP); + //Handle "0" text value + dT->setString("0"); + + dT->setColour(rLine,gLine,bLine,aLine); + dT->setSize(fontSize); + dT->setOrigin(tickOrigin+ Point3D(-1,-1,-1)); + dT->setAlignment(DRAWTEXT_ALIGN_RIGHT); + dT->setUp(Point3D(0,0,1)); + dT->setTextDir(Point3D(-1,-1,0)); + d->drawables.push_back(dT); + +} + +void BoundingBoxFilter::drawDimension(const BoundCube &bTotal, DrawStreamData *d) const +{ + //Add the rectangle drawable + DrawRectPrism *dP = new DrawRectPrism; + dP->setAxisAligned(bTotal); + dP->setColour(rLine,gLine,bLine,aLine); + dP->setLineWidth(lineWidth); + d->drawables.push_back(dP); + + + + //Add the arrows from the start ot the end + //Create the position from which to draw the tick origins + Point3D tickOrigin,tickEnd; + bTotal.getBounds(tickOrigin,tickEnd); + + + + const float ARROW_SCALE_FACTOR =0.03f; + const float OFFSET=0.07f; + + Point3D halfPt; + halfPt=(tickEnd-tickOrigin)*0.5f + tickOrigin; + + + float maxLen; + { + Point3D delta; + delta=tickEnd-tickOrigin; + maxLen=std::max(std::max(delta[0],delta[1]),delta[2]); + } + + float offset; + offset=maxLen*OFFSET; + + Point3D centrePt[3]; + + centrePt[0] = Point3D(halfPt[0],tickOrigin[1]-offset,tickOrigin[2]-OFFSET); + centrePt[1] = Point3D(tickOrigin[0]-offset,halfPt[1],tickOrigin[2]-OFFSET); + centrePt[2] = Point3D(tickOrigin[0]-offset,tickOrigin[1] -OFFSET , halfPt[2]); + + + //Draw the arrows around the edge of the box + for(size_t ui=0;ui<3;ui++) + { + float len; + len=(tickEnd[ui]-tickOrigin[ui])*0.5f; + + for(unsigned int uj=0;uj<2;uj++) + { + DrawVector *dV; + dV= new DrawVector; + + dV->setColour(rLine,gLine,bLine,aLine); + dV->wantsLight=true; + dV->setOrigin(centrePt[ui]); + + switch(ui) + { + case 0: + dV->setVector(Point3D(2.0*len*(float)(uj-0.5f),0,0)); + break; + case 1: + dV->setVector(Point3D(0,2.0*len*(float)(uj-0.5f),0)); + break; + case 2: + dV->setVector(Point3D(0,0,2.0*len*(float)(uj-0.5f))); + break; + } + + + dV->setArrowSize(maxLen*ARROW_SCALE_FACTOR); + + d->drawables.push_back(dV); + } + + } + + + + + //Draw the values for the box dimensions, as text + char *buffer=new char[128]; + for(size_t ui=0;ui<3;ui++) + { + BoundCube textCube; + DrawGLText *dT; + dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); + + float len; + len=(tickEnd[ui]-tickOrigin[ui]); + + snprintf(buffer,127,"%5.1f",len); + dT->setString(buffer); + dT->setSize(fontSize); + + dT->setColour(rLine,gLine,bLine,aLine); + dT->setOrigin(centrePt[ui]); + switch(ui) + { + case 0: + + dT->setUp(Point3D(0,0,1)); + dT->setTextDir(Point3D(1,0,0)); + break; + case 1: + dT->setUp(Point3D(1,0,0)); + dT->setTextDir(Point3D(0,-1,0)); + break; + case 2: + dT->setUp(Point3D(0,1,0)); + dT->setTextDir(Point3D(0,0,1)); + break; + } + + dT->setAlignment(DRAWTEXT_ALIGN_CENTRE); + + d->drawables.push_back(dT); + } + + + +} + +unsigned int BoundingBoxFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + + if(!isVisible) + { + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + bThis=bTotal; + //Grab the first four points to define a volume. + //then expand that volume using the boundcube functions. + const IonStreamData *d =(const IonStreamData *) dataIn[ui]; + size_t dataPos=0; + unsigned int curProg=NUM_CALLBACK; + while(ptCount < 4 && dataPos < d->data.size()) + { + for(unsigned int ui=0; uidata.size();ui++) + { + p[ptCount]=d->data[ui].getPosRef(); + ptCount++; + dataPos=ui; + if(ptCount >=4) + break; + } + } + + //Ptcount will be 4 if we have >=4 points in dataset + if(ptCount < 4) + break; + bThis.setBounds(p,4); + //Expand the bounding volume +#ifdef _OPENMP + //Parallel version + unsigned int nT =omp_get_max_threads(); + + BoundCube *newBounds= new BoundCube[nT]; + for(unsigned int ui=0;uidata.size();ui++) + { + unsigned int thisT=omp_get_thread_num(); + //OpenMP does not allow exiting. Use spin instead + if(spin) + continue; + + if(!curProg--) + { + #pragma omp critical + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + } + + + if(thisT == 0) + { + if(!(*callback)(false)) + spin=true; + } + } + + newBounds[thisT].expand(d->data[ui].getPosRef()); + } + if(spin) + { + delete d; + delete[] newBounds; + return BOUNDINGBOX_ABORT_ERR; + } + + for(unsigned int ui=0;uidata.size();ui++) + { + bThis.expand(d->data[ui].getPosRef()); + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return BOUNDINGBOX_ABORT_ERR; + } + } + } +#endif + bTotal.expand(bThis); + break; + } + default: + break; + } + + //Copy the input data to the output + getOut.push_back(dataIn[ui]); + } + + //Append the bounding box if it is valid + if(bTotal.isValid()) + { + DrawStreamData *d = new DrawStreamData; + d->parent=this; + + switch(boundStyle) + { + case BOUND_STYLE_BOX_ONLY: + { + //Add the rectangle drawable + DrawRectPrism *dP = new DrawRectPrism; + dP->setAxisAligned(bTotal); + dP->setColour(rLine,gLine,bLine,aLine); + dP->setLineWidth(lineWidth); + d->drawables.push_back(dP); + break; + } + case BOUND_STYLE_TICKS: + drawTicks(bTotal,d); + break; + case BOUND_STYLE_DIMENSION: + drawDimension(bTotal,d); + break; + default: + ASSERT(false); + } + d->cached=0; + + getOut.push_back(d); + } + return 0; +} + + +void BoundingBoxFilter::getProperties(FilterPropGroup &propertyList) const +{ + FilterProperty p; + size_t curGroup=0; + + string tmpStr; + stream_cast(tmpStr,isVisible); + p.name=TRANS("Visible"); + p.data= tmpStr; + p.key=KEY_VISIBLE; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("If true, show box, otherwise hide box"); + propertyList.addProperty(p,curGroup); + + if(isVisible) + { + vector > choices; + for(size_t ui=0;ui=BOUND_STYLE_ENUM_END) + return false; + + if(ltmp == boundStyle) + needUpdate=false; + else + { + boundStyle=ltmp; + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_FIXEDOUT: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=fixedNumTicks; + fixedNumTicks=(stripped=="1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=fixedNumTicks) + needUpdate=true; + break; + } + case KEY_COUNT_X: + case KEY_COUNT_Y: + case KEY_COUNT_Z: + { + ASSERT(fixedNumTicks); + unsigned int newCount; + if(stream_cast(newCount,value)) + return false; + + //there is a start and an end tick, at least + if(newCount < 2) + return false; + + numTicks[key-KEY_COUNT_X]=newCount; + needUpdate=true; + break; + } + case KEY_LINECOLOUR: + { + unsigned char newR,newG,newB,newA; + + parseColString(value,newR,newG,newB,newA); + + if(newB != bLine || newR != rLine || + newG !=gLine || newA != aLine) + needUpdate=true; + + rLine=newR/255.0; + gLine=newG/255.0; + bLine=newB/255.0; + aLine=newA/255.0; + needUpdate=true; + break; + } + case KEY_LINEWIDTH: + { + float newWidth; + if(stream_cast(newWidth,value)) + return false; + + if(newWidth <= 0.0f) + return false; + + lineWidth=newWidth; + needUpdate=true; + break; + } + case KEY_SPACING_X: + case KEY_SPACING_Y: + case KEY_SPACING_Z: + { + ASSERT(!fixedNumTicks); + float newSpacing; + if(stream_cast(newSpacing,value)) + return false; + + if(newSpacing <= 0.0f) + return false; + + tickSpacing[key-KEY_SPACING_X]=newSpacing; + needUpdate=true; + break; + } + case KEY_FONTSIZE: + { + unsigned int newCount; + if(stream_cast(newCount,value)) + return false; + + fontSize=newCount; + needUpdate=true; + break; + } + default: + ASSERT(false); + } + return true; +} + + +std::string BoundingBoxFilter::getErrString(unsigned int code) const +{ + + //Currently the only error is aborting + return std::string("Aborted"); +} + +void BoundingBoxFilter::setPropFromBinding(const SelectionBinding &b) +{ + {ASSERT(false);} +} + +bool BoundingBoxFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << ""<"<" <" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool BoundingBoxFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + std::string tmpStr; + + //Retrieve visibility + //==== + if(XMLHelpFwdToElem(nodePtr,"visible")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + isVisible=false; + else if(tmpStr == "1") + isVisible=true; + else + return false; + + xmlFree(xmlString); + //==== + + //Retrieve box style + //==== + if(XMLHelpFwdToElem(nodePtr,"boundstyle")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(boundStyle,tmpStr)) + return false; + + xmlFree(xmlString); + //==== + + + //Retrieve fixed tick num + //==== + if(XMLHelpFwdToElem(nodePtr,"fixedticks")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + fixedNumTicks=false; + else if(tmpStr == "1") + fixedNumTicks=true; + else + return false; + + xmlFree(xmlString); + //==== + + //Retrieve num ticks + //==== + if(XMLHelpFwdToElem(nodePtr,"ticknum")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(numTicks[0],tmpStr)) + return false; + + xmlFree(xmlString); + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(numTicks[1],tmpStr)) + return false; + + xmlFree(xmlString); + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(numTicks[2],tmpStr)) + return false; + + xmlFree(xmlString); + //==== + + //Retrieve spacing + //==== + if(XMLHelpFwdToElem(nodePtr,"tickspacing")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(tickSpacing[0],tmpStr)) + return false; + + if(tickSpacing[0] < 0.0f) + return false; + + xmlFree(xmlString); + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(tickSpacing[1],tmpStr)) + return false; + if(tickSpacing[1] < 0.0f) + return false; + + xmlFree(xmlString); + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(tickSpacing[2],tmpStr)) + return false; + + if(tickSpacing[2] < 0.0f) + return false; + xmlFree(xmlString); + //==== + + //Retrieve line width + //==== + if(XMLHelpFwdToElem(nodePtr,"linewidth")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(lineWidth,tmpStr)) + return false; + + if(lineWidth < 0) + return false; + xmlFree(xmlString); + //==== + + //Retrieve font size + //==== + if(XMLHelpFwdToElem(nodePtr,"fontsize")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(fontSize,tmpStr)) + return false; + + xmlFree(xmlString); + //==== + + //Retrieve colour + //==== + if(XMLHelpFwdToElem(nodePtr,"colour")) + return false; + + if(!parseXMLColour(nodePtr,rLine,gLine,bLine,aLine)) + return false; + //==== + + return true; +} + +unsigned int BoundingBoxFilter::getRefreshBlockMask() const +{ + //Everything goes through this filter + return 0; +} + +unsigned int BoundingBoxFilter::getRefreshEmitMask() const +{ + if(isVisible) + return STREAM_TYPE_DRAW; + else + return 0; +} + +unsigned int BoundingBoxFilter::getRefreshUseMask() const +{ + if(isVisible) + return STREAM_TYPE_IONS; + else + return 0; +} + +#ifdef DEBUG +bool boxVolumeTest(); + +bool BoundingBoxFilter::runUnitTests() +{ + if(!boxVolumeTest()) + return false; + + return true; +} + + +bool boxVolumeTest() +{ + //Synthesise data + //--- + IonStreamData *d = new IonStreamData; + + vector streamIn,streamOut; + + IonHit h; + h.setMassToCharge(1); + + h.setPos(Point3D(0,0,1)); + d->data.push_back(h); + h.setPos(Point3D(0,1,0)); + d->data.push_back(h); + h.setPos(Point3D(1,0,0)); + d->data.push_back(h); + h.setPos(Point3D(0,0,0)); + d->data.push_back(h); + + streamIn.push_back(d); + //--- + + + //Set up and run filter + //--- + BoundingBoxFilter *b = new BoundingBoxFilter; + b->setCaching(false); + + bool needUp; + TEST(b->setProperty(KEY_VISIBLE,"1",needUp),"Set prop"); + + + ProgressData p; + TEST(!b->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + //--- + + //Run tests + //--- + BoundCube bc; + bool havePrismDrawable=false; + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_DRAW) + continue; + + DrawStreamData *drawData; + drawData=(DrawStreamData*)streamOut[ui]; + + for(unsigned int uj=0;ujdrawables.size(); uj++) + { + DrawableObj *draw; + draw= drawData->drawables[uj]; + + if(draw->getType() == DRAW_TYPE_RECTPRISM) + { + draw->getBoundingBox(bc); + + havePrismDrawable=true; + break; + } + } + + if(havePrismDrawable) + break; + + } + + + TEST(havePrismDrawable, "bounding box existance test"); + + TEST(fabs(bc.volume() - 1.0f) + < sqrt(std::numeric_limits::epsilon()), + "Bounding volume test"); + + //Cleanup the emitted pointers + for(unsigned int ui=0;ui. +*/ +#ifndef BOUNDINGBOX_H +#define BOUNDINGBOX_H + +#include "../filter.h" +#include "../../common/translation.h" + +//!Bounding box filter +class BoundingBoxFilter : public Filter +{ + private: + //!visibility + bool isVisible; + + //!visual representation mode + unsigned int boundStyle; + //!Should tick positions be computed using fixed tick counts or spacing? + bool fixedNumTicks; + //!Number of ticks (XYZ) if using fixed num ticks + unsigned int numTicks[3]; + //!Spacing of ticks (XYZ) if using fixed spacing ticks + float tickSpacing[3]; + //!Font size + unsigned int fontSize; + + //!Line colour + float rLine,gLine,bLine,aLine; + //!Line width + float lineWidth; + //!Use 3D text? + bool threeDText; + + + //!Draw tick-style bounding box and associated annotations + void drawTicks(const BoundCube &bTotal,DrawStreamData *d) const; + + + //!Draw "dimension" style bounding box and associated annotation + void drawDimension(const BoundCube &bTotal, DrawStreamData *d) const; + + public: + BoundingBoxFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //!Returns -1, as range file cache size is dependant upon input. + virtual size_t numBytesForCache(size_t nObjects) const; + //!Returns FILTER_TYPE_RANGEFILE + unsigned int getType() const { return FILTER_TYPE_BOUNDBOX;}; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + //!Force a re-read of the rangefile Return value is range file reading error code + unsigned int updateRng(); + virtual std::string typeString() const { return std::string(TRANS("Bound box"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Refresh ignore mask, for filter streams that will not be utilised in the computation (except for pass-through) + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + +#ifdef DEBUG + bool runUnitTests() ; +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/clusterAnalysis.cpp 3depict-0.0.13/src/backend/filters/clusterAnalysis.cpp --- 3depict-0.0.12/src/backend/filters/clusterAnalysis.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/clusterAnalysis.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -0,0 +1,3340 @@ +/* + * clusterAnalysis.cpp - Perform clustering data analysis on valued point clouds + * 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 . +*/ +#include "clusterAnalysis.h" + + + +#include "filterCommon.h" + + +#include + +#include + +#include "K3DTree-mk2.h" + + +enum +{ + KEY_CLUSTERANALYSIS_ALGORITHM, + KEY_CORECLASSIFYDIST, + KEY_CORECLASSIFYKNN, + KEY_LINKDIST, + KEY_BULKLINK, + KEY_ERODEDIST, + KEY_WANT_CLUSTERSIZEDIST, + KEY_WANT_LOGSIZEDIST, + KEY_WANT_COMPOSITIONDIST, + KEY_WANT_CLUSTERMORPHOLOGY, + KEY_NORMALISE_COMPOSITION, + KEY_CROP_SIZE, + KEY_SIZE_COUNT_BULK, + KEY_CROP_NMIN, + KEY_CROP_NMAX, + KEY_CORE_OFFSET=100000, + KEY_BULK_OFFSET=200000 +}; + +enum +{ + ABORT_ERR=1, + NOCORE_ERR, + NOBULK_ERR +}; + +enum +{ + CLUSTER_LINK_ERODE, + CLUSTER_ALGORITHM_ENUM_END, +}; + + +enum +{ + COMPOSITION_NONE, + COMPOSITION_UNNORMALISED, + COMPOSITION_NORMALISED +}; + +const char SIZE_DIST_DATALABEL[] =NTRANS("Size Distribution"); +const char CHEM_DIST_DATALABEL[] =NTRANS("Chemistry Distribution"); + +using std::vector; + +//Optimisation tuning value; +// number of points to expect in a KD query sphere before the bulk query pays off +// in terms of algorithm speed +const float SPHERE_PRESEARCH_CUTOFF = 75; + + +void makeFrequencyTable(const IonStreamData *i ,const RangeFile *r, + std::vector > &freqTable) +{ + ASSERT(r); + ASSERT(i); + + unsigned int numThreads; +#ifdef _OPENMP + numThreads=omp_get_max_threads(); +#else + numThreads=1; +#endif + vector ionHist; + ionHist.resize(numThreads); + + for(size_t ui=0;uigetNumIons()]; + for(size_t uj=0;ujgetNumIons();uj++) + ionHist[ui][uj]=0; + } + + +#pragma omp parallel for + for(size_t ui=0;uidata.size();ui++) + { +#ifdef _OPENMP + unsigned int threadNum=omp_get_thread_num(); +#endif + unsigned int rangeId; + rangeId= r->getIonID(i->data[ui].getMassToCharge()); + + if(rangeId!=(unsigned int)-1) + { +#ifdef _OPENMP + ionHist[threadNum][rangeId]++; +#else + ionHist[0][rangeId]++; +#endif + } + } + + + //we have to re-count the total, and tally the different threads + //in the histogram + for(size_t uj=0;ujgetNumIons();uj++) + { + for(size_t ui=1;uigetNumIons();uj++) + freqTable.push_back(make_pair(r->getName(uj),ionHist[0][uj])); + +} + +void makeCompositionTable(const IonStreamData *i ,const RangeFile *r, + std::vector > &compTable) +{ + std::vector > tab; + makeFrequencyTable(i,r,tab); + + compTable.resize(tab.size()); + size_t total=0; + for(unsigned int ui=0;ui &resultValues, vector &resultVectors) +{ + + //Although this function *mostly* works on arbitrary datasizes, the vector is of course + //fixed to being 3D.. + ASSERT(numCols == 3); + + gsl_matrix *m=gsl_matrix_alloc(numRows,numCols); + for(unsigned int ui=0;ui=0.0f); + resultValues.push_back(v); + } + + //Copy out the decomposed V matrix + resultVectors.resize(numCols); + for(size_t ui=0;ui &rangeEnabledMap) +{ + + //should be empty... + ASSERT(rangeEnabledMap.empty()); + + //"Lagging" counter to track the mapping from ionID->enabled Ion ID. + size_t count=0; + for(size_t ui=0;uirangeFile->getNumIons();ui++) + { + if(r->enabledIons[ui]) + { + //Create map entry + rangeEnabledMap[ui]=count; + count++; + } + } + + +} + +ClusterAnalysisFilter::ClusterAnalysisFilter() : algorithm(CLUSTER_LINK_ERODE), + coreDist(0.0f), coreKNN(1), linkDist(0.5f), bulkLink(1), dErosion(0.25), + wantCropSize(false), nMin(0),nMax(std::numeric_limits::max()), + sizeCountBulk(true),wantClusterSizeDist(false),logClusterSize(false), + wantClusterComposition(true),normaliseComposition(true), + wantClusterMorphology(false), haveRangeParent(false) + +{ + //haveRangeParent=false; //Initialiser sets this to false, as required by ::initFilter + + cacheOK=false; + + //By default, we should cache, but final decision is made higher up + cache=true; +#ifdef DEBUG + wantParanoidDebug=false; +#endif +} + + +Filter *ClusterAnalysisFilter::cloneUncached() const +{ + ClusterAnalysisFilter *p=new ClusterAnalysisFilter; + + p->algorithm=algorithm; + + p->coreDist=coreDist; + p->bulkLink=bulkLink; + p->linkDist=linkDist; + p->dErosion=dErosion; + + p->wantCropSize=wantCropSize; + p->nMin=nMin; + p->nMax=nMax; + p->sizeCountBulk=sizeCountBulk; + + p->wantClusterSizeDist = wantClusterSizeDist; + p->logClusterSize= logClusterSize; + + p->wantClusterComposition=wantClusterComposition; + p->normaliseComposition = normaliseComposition; + + p->haveRangeParent=false; //lets assume not, and this will be reset at ::initFilter time + + p->ionNames.resize(ionNames.size()); + std::copy(ionNames.begin(),ionNames.end(),p->ionNames.begin()); + p->ionCoreEnabled.resize(ionCoreEnabled.size()); + std::copy(ionCoreEnabled.begin(),ionCoreEnabled.end(),p->ionCoreEnabled.begin()); + p->ionBulkEnabled.resize(ionBulkEnabled.size()); + std::copy(ionBulkEnabled.begin(),ionBulkEnabled.end(),p->ionBulkEnabled.begin()); + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +void ClusterAnalysisFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + //Check for range file parent + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + { + const RangeStreamData *r; + r = (const RangeStreamData *)dataIn[ui]; + + bool different=false; + if(!haveRangeParent) + { + //well, things have may have changed, we didn't have a + //range parent before. Or, we could have been loaded in from + //a file. + + if(ionCoreEnabled.size() != r->rangeFile->getNumIons() || + ionBulkEnabled.size() != r->rangeFile->getNumIons()) + different=true; + else + { + //The ion lengths are the same; if so, we can just fill in the gaps + // -- the file does not store names; just sequence IDs. + ionNames.clear(); + ionNames.reserve(r->rangeFile->getNumRanges()); + for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) + { + if(r->enabledIons[uj]) + ionNames.push_back(r->rangeFile->getName(uj)); + } + } + } + else + { + //OK, last time we had a range parent. Check to see + //if the ion names are the same. If they are, keep the + //current bools, iff the ion names are all the same + unsigned int numEnabled=std::count(r->enabledIons.begin(), + r->enabledIons.end(),1); + if(ionNames.size() == numEnabled) + { + unsigned int pos=0; + for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) + { + //Only look at parent-enabled ranges + if(r->enabledIons[uj]) + { + if(r->rangeFile->getName(uj) != ionNames[pos]) + { + different=true; + break; + } + pos++; + } + } + } + else + different=true; + } + haveRangeParent=true; + + if(different) + { + //OK, its different. we will have to re-assign, + //but only allow the ranges enabled in the parent filter + // + + + vector oldIonNames; + oldIonNames.swap(ionNames); + + ionNames.reserve(r->rangeFile->getNumRanges()); + for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) + { + + if(r->enabledIons[uj]) + ionNames.push_back(r->rangeFile->getName(uj)); + } + + //Create new Core enabled/size enabled maps + //try to preserve selection using ion naming, if possible + //--- + vector oldCoreEnable,oldBulkEnable; + oldCoreEnable.swap(ionCoreEnabled); + oldBulkEnable.swap(ionBulkEnabled); + + ionCoreEnabled.resize(ionNames.size(),false); + ionBulkEnabled.resize(ionNames.size(),true); + + //TODO: Could replace double-search with keyed sort & match + for(size_t ui=0;ui &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + //By default, copy inputs to output, unless it is an ion or range stream type. + for(unsigned int ui=0;uigetStreamType(); + //Block ions moving through filter; we modify them. + // and also rangefiles, as we don't propagate these + if(type != STREAM_TYPE_IONS && type!=STREAM_TYPE_RANGE) + getOut.push_back(dataIn[ui]); + + } + + //use the cached copy if we have it. + if(cacheOK) + { + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *d; + d=((const IonStreamData *)dataIn[ui]); + totalDataSize+=d->data.size(); + } + break; + default: + break; + } + } + + //Nothing to do. + if(!totalDataSize) + return 0; + + if(!haveRangeParent) + { + consoleOutput.push_back(string(TRANS("No range data. Can't cluster."))); + return 0; + } + + + bool haveABulk,haveACore; + checkIonEnabled(haveACore,haveABulk); + //Check that the user has enabled something as core + if(!haveACore) + { + consoleOutput.push_back( + string(TRANS("No ranges selected for cluster \"core\". Cannot continue with clustering."))); + return NOCORE_ERR; + } + + + //Check that the user has enabled something as matrix/bulk. + if(!haveABulk ) + { + //TODO: Refactor - we are really asking if algorithm needs bulk + if(bulkLink >std::numeric_limits::epsilon()) + { + consoleOutput.push_back( + string(TRANS("No ranges selected for cluster \"bulk\". Cannot continue with clustering."))); + return NOBULK_ERR; + } + } + +#ifdef DEBUG + for(unsigned int ui=0;ui > clusteredCore,clusteredBulk; + + switch(algorithm) + { + case CLUSTER_LINK_ERODE: + { + unsigned int errCode; + errCode=refreshLinkClustering(dataIn,clusteredCore, + clusteredBulk,progress,callback); + + if(errCode) + return errCode; + break; + } + default: + ASSERT(false); + } + +#ifdef DEBUG + /* If you are paranoid about the quality of the output, + * This will enable running some sanity checks that do + * not use the data structure involved in the clustering; + * ie a secondary check. + * However this is far too slow to enable by default, even in debug mode + */ + if(wantParanoidDebug) + paranoidDebugAssert(clusteredCore,clusteredBulk); +#endif + if(wantCropSize) + stripClusterBySize(clusteredCore,clusteredBulk,callback,progress); + + bool haveBulk,haveCore; + haveBulk=clusteredBulk.size(); + haveCore=clusteredCore.size(); + + + if(!haveBulk && !haveCore) + return 0; + + //we can't have bulk, but no core... + ASSERT(!(haveBulk && !haveCore)); + + //------------- + + + //Report the results back to the user + //------------ + //Cluster reporting. + const RangeStreamData *r=0; + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + { + r = (const RangeStreamData *)dataIn[ui]; + break; + } + } + + size_t curPlotIndex=0; + //Generate size distribution if we need it. + if(wantClusterSizeDist) + { + PlotStreamData *d; + d=clusterSizeDistribution(clusteredCore,clusteredBulk); + + if(d) + { + d->index=curPlotIndex; + curPlotIndex++; + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + } + else + d->cached=0; + + getOut.push_back(d); + + } + + } + + //Generate composition distribution if we requested it + if(wantClusterComposition) + { + vector plots; + genCompositionVersusSize(clusteredCore,clusteredBulk,r->rangeFile,plots); + + for(unsigned int ui=0;uiindex=curPlotIndex; + curPlotIndex++; + + if(cache) + { + plots[ui]->cached=1; + filterOutputs.push_back(plots[ui]); + } + else + plots[ui]->cached=0; + + getOut.push_back(plots[ui]); + } + } + + if(wantClusterMorphology) + { + //Compute the singular values for each cluster + //which describe the cluster morphology, their basis vectors, and + //the mass centre for the clusters + + //The premise of this analysis technique is outlined in Sudbrack,2004 - to some extent. + // In that work, they have several methods of doing morphology analysis, including where they + // use a PCA which wraps up the SVD to do the calculations. + // Here we use the SVD, which is faster & more space efficient, as we don't form the covariance + // matrix, but work directly on our data. + + // Aside from a sqrt, we should get the same answer for the ellipsoidal fit. + // + // Showing SVD & PCA to be equivalent enough for our use: + // SVD : X=USV', PCA: XX'=WDW' ; + // + //PCA, sub-ing Xs SVD representation: + // XX' = (USV')(USV')' + // XX' = (USV')(VSU') + // XX' = US(V'V)SU' + // V is orthogonal, thus V'V =I + // as transpose of orthogonal is its own inverse. + // XX' = US^2U' + // + // In our case, X_i=P_i-P_bar, where P_i is the i-th point in the cluster + // + // Thus D=S^2 and, D, being diagonal implies S=D^0.5 + //Sudbrack, C. : Decomposition behavior in model Ni-Al-Cr-X superalloys: + // temporal evolution and compositional pathways on a nanoscale (Ph.D. Thesis, 2004) + //http://arc.nucapt.northwestern.edu/refbase/files/Sudbrack_Ph.D._thesis_2004_6MB.pdf + + //Singular values, + //Mass centres of clusters & Singular vectors + vector > singularVals; + vector > > singularVectors; + getSingularValues(clusteredCore,clusteredBulk, + singularVals,singularVectors); + + ASSERT(singularVals.size() == clusteredCore.size()); + ASSERT(singularVectors.size() == clusteredCore.size()); + + //Ok, so we have the singular values, now create a + //plot with the values in it + PlotStreamData *p = new PlotStreamData; + p->parent=this; + + p->plotMode=PLOT_MODE_1D; + p->plotStyle=PLOT_TRACE_POINTS; + p->dataLabel=TRANS("Morphology Plot"); + p->xLabel=TRANS("\\lambda_1:\\lambda_2 ratio"); + p->yLabel=TRANS("\\lambda_2:\\lambda_3 ratio"); + p->xyData.reserve(singularVals.size()); + //the Y label makes more sense than the plot label here. + p->useDataLabelAsYDescriptor=false; + + +#pragma omp parallel for + for(unsigned int ui=0; ui std::numeric_limits::epsilon()) + { + p->xyData.push_back(make_pair(singularVals[ui][0]/singularVals[ui][1], + singularVals[ui][1]/singularVals[ui][2])); + + } + } + + if(p->xyData.size()) + { + p->index=curPlotIndex; + curPlotIndex++; + p->autoSetHardBounds(); + + if(cache) + { + p->cached=1; + filterOutputs.push_back(p); + } + else + p->cached=0; + + getOut.push_back(p); + + } + else + { + consoleOutput.push_back(TRANS("No clusters had sufficient dimensionality to compute singular values")); + delete p; + } + + + DrawStreamData *singularVectorDraw = new DrawStreamData; + singularVectorDraw->parent=this; + singularVectorDraw->drawables.reserve(singularVectors.size()*3); + + //So the next thing we do, is create mini Axes for them at their respective coordinates + //the length of each part of the axis shows the primary directions + //for that part of the cluster + for(unsigned int ui=0;ui=singularVectors[ui].second.size()) + break; + + DrawVector *d; + d= new DrawVector; + d->setColour(uj ==0, uj == 1, uj ==2,1); + Point3D start,singVector; + + //make a little cross in free space + singVector=singularVectors[ui].second[uj]*singularVals[ui][uj]; + start=singularVectors[ui].first-singVector*0.5f; + + + //First in current singular pair is cluster origin + d->setOrigin(start); + //Second contains each individual thing + d->setVector(singVector*0.5f); + singularVectorDraw->drawables.push_back(d); + } + } + + if(cache) + { + WARN(false,"Drawable caching is broken now. Refusing to cache!"); + singularVectorDraw->cached=0; + } + else + singularVectorDraw->cached=0; + + getOut.push_back(singularVectorDraw); + } + + //Construct the output clustered data. + IonStreamData *i = new IonStreamData; + i->parent =this; + std::string sDebugConsole,stmp; + stream_cast(stmp,clusteredCore.size()); + + sDebugConsole=TRANS("Found :"); + sDebugConsole+=stmp; + sDebugConsole+= TRANS(" clusters"); + consoleOutput.push_back(sDebugConsole); + + size_t totalSize=0; + + #pragma omp parallel for reduction(+:totalSize) + for(size_t ui=0;uidata.resize(totalSize); + + + //copy across the core and bulk ions + //into the output + size_t copyPos=0; + for(size_t ui=0;uidata[copyPos]=clusteredCore[ui][uj]; + copyPos++; + } + } + clusteredCore.clear(); + + for(size_t ui=0;uidata[copyPos]=clusteredBulk[ui][uj]; + copyPos++; + } + } + clusteredBulk.clear(); + + //The result data is drawn grey... + i->r=0.5f; + i->g=0.5f; + i->b=0.5f; + i->a=1.0f; + + //Save the ion stream data. + if(cache) + { + i->cached=1; + filterOutputs.push_back(i); + cacheOK=true; + } + else + i->cached=0; + + getOut.push_back(i); + + + if(wantClusterComposition) + { + ASSERT(r); + + if(normaliseComposition) + { + vector > compTable; + makeCompositionTable(i,r->rangeFile,compTable); + + + if(haveBulk) + consoleOutput.push_back(TRANS("Compositions (fractional, core+bulk)")); + else if(haveCore) + consoleOutput.push_back(TRANS("Compositions (fractional, core only)")); + + std::string compString,tmp; + for(unsigned int ui=0;ui > freqTable; + makeFrequencyTable(i,r->rangeFile,freqTable); + + consoleOutput.push_back(TRANS("Frequencies (core+bulk)")); + + std::string freqString,tmp; + for(unsigned int ui=0;ui > choices; + tmpStr=TRANS("Core Link + Erode"); + choices.push_back(make_pair((unsigned int)CLUSTER_LINK_ERODE,tmpStr)); + + tmpStr= choiceString(choices,algorithm); + p.name=TRANS("Algorithm"); + p.data=tmpStr; + choices.clear(); + p.type=PROPERTY_TYPE_CHOICE; + p.helpText=TRANS("Cluster algorithm mode"); + p.key=KEY_CLUSTERANALYSIS_ALGORITHM; + propertyList.addProperty(p,curGroup); + + curGroup++; + + if(algorithm == CLUSTER_LINK_ERODE) + { + stream_cast(tmpStr,coreDist); + p.name=TRANS("Core Classify Dist"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Restrict only atoms by distance to be cluster sources"); + p.key=KEY_CORECLASSIFYDIST; + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,coreKNN); + p.name=TRANS("Classify Knn Max"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_INTEGER; + p.helpText=TRANS("Require that the kth NN (this number) is within the classify distance, to be a cluster source"); + p.key=KEY_CORECLASSIFYKNN; + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,linkDist); + p.name=TRANS("Core Link Dist"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Distance between clusters to allow linking"); + p.key=KEY_LINKDIST; + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,bulkLink); + p.name=TRANS("Bulk Link (Envelope) Dist"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Distance from core points that form cluster that is used to grab surrounding bulk points"); + p.key=KEY_BULKLINK; + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,dErosion); + p.name=TRANS("Erode Dist"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Distance from unclustered material in which bulk points are eroded from cluster"); + p.key=KEY_ERODEDIST; + propertyList.addProperty(p,curGroup); + } + + propertyList.setGroupTitle(curGroup,TRANS("Clustering Params")); + + curGroup++; + + if(bulkLink > 0.0f) + { + tmpStr=boolStrEnc(sizeCountBulk); + p.name=TRANS("Count bulk"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Include bulk ions in size distribution."); + p.key=KEY_SIZE_COUNT_BULK; + propertyList.addProperty(p,curGroup); + } + + tmpStr=boolStrEnc(wantCropSize); + p.name=TRANS("Size Cropping"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Perform removal of clusters based upon size distribution"); + p.key=KEY_CROP_SIZE; + propertyList.addProperty(p,curGroup); + + if(wantCropSize) + { + stream_cast(tmpStr,nMin); + p.name=TRANS("Min Size"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_INTEGER; + p.helpText=TRANS("Remove clusters below this size"); + p.key=KEY_CROP_NMIN; + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,nMax); + p.name=TRANS("Max Size"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_INTEGER; + p.helpText=TRANS("Remove clusters above this size"); + p.key=KEY_CROP_NMAX; + propertyList.addProperty(p,curGroup); + } + + tmpStr=boolStrEnc(wantClusterSizeDist); + p.name=TRANS("Size Distribution"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Show number of clusters as a function of cluster size"); + p.key=KEY_WANT_CLUSTERSIZEDIST; + propertyList.addProperty(p,curGroup); + if(wantClusterSizeDist) + { + tmpStr=boolStrEnc(logClusterSize); + p.name=TRANS("Log Scale"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Use logarithmic scale for size distribution"); + p.key=KEY_WANT_LOGSIZEDIST; + propertyList.addProperty(p,curGroup); + } + + + /* + tmpStr=boolStrEnc(wantClusterMorphology); + p.name=TRANS("Morphology Dist."); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Create a plot showing cluster aspect ratio data"); + p.key=KEY_WANT_CLUSTERMORPHOLOGY; + propertyList.addProperty(p,curGroup); + */ + tmpStr=boolStrEnc(wantClusterComposition); + p.name=TRANS("Chemistry Dist."); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Create a plot showing chemistry for each cluster size"); + p.key=KEY_WANT_COMPOSITIONDIST; + propertyList.addProperty(p,curGroup); + + if(wantClusterComposition) + { + tmpStr=boolStrEnc(normaliseComposition); + p.name=TRANS("Normalise"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Convert cluster counts to composition"); + p.key=KEY_NORMALISE_COMPOSITION; + propertyList.addProperty(p,curGroup); + } + + + propertyList.setGroupTitle(curGroup,TRANS("Postprocess")); + + curGroup++; + + if(haveRangeParent) + { + //Offset markers are used elsewhere. Must be in sync with + //this code + ASSERT(ionCoreEnabled.size() == ionBulkEnabled.size()); + ASSERT(ionCoreEnabled.size() == ionNames.size()) + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + //OK, is this the plot? + //We should match the title we used to generate it + PlotStreamData *p; + p=(PlotStreamData*)filterOutputs[ui]; + + if(p->dataLabel.substr(strlen(SIZE_DIST_DATALABEL)) ==SIZE_DIST_DATALABEL ) + { + //Yup, this is it.kill the distribution + std::swap(filterOutputs[ui],filterOutputs.back()); + filterOutputs.pop_back(); + + //Now, note we DONT break + //here; as there is more than one + } + + } + } + } + else + { + //OK, we don't have one and we would like one. + // We have to compute this. Wipe cache and start over + clearCache(); + } + needUpdate=true; + } + break; + } + case KEY_WANT_LOGSIZEDIST: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=logClusterSize; + + logClusterSize=(stripped == "1"); + + //If the result is different + //we need to alter the output + if(lastVal!=logClusterSize) + { + //Scan through the cached output, and modify + //the size distribution. Having to recalc this + //just for a log/non-log change + //is a real pain -- so lets be smart and avoid this! + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + //OK, is this the plot? + //We should match the title we used to generate it + PlotStreamData *p; + p=(PlotStreamData*)filterOutputs[ui]; + + if(p->dataLabel ==SIZE_DIST_DATALABEL ) + { + //Yup, this is it. Set the log status + //and finish up + p->logarithmic=logClusterSize; + break; + } + + } + } + + + + needUpdate=true; + } + + break; + } + case KEY_WANT_COMPOSITIONDIST: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=wantClusterComposition; + wantClusterComposition=(stripped=="1"); + + //if the result is different, e + //remove the filter elements we no longer want. + if(lastVal!=wantClusterComposition) + { + //If we don't want the cluster composition + //just kill it from the cache and request an update + if(!wantClusterComposition) + { + for(size_t ui=filterOutputs.size();ui;) + { + ui--; + if(filterOutputs[ui]->getStreamType() == STREAM_TYPE_PLOT) + { + //OK, is this the plot? + //We should match the title we used to generate it + PlotStreamData *p; + p=(PlotStreamData*)filterOutputs[ui]; + + if(p->dataLabel.substr(0,strlen(CHEM_DIST_DATALABEL)) ==CHEM_DIST_DATALABEL ) + { + //Yup, this is it.kill the distribution + std::swap(filterOutputs[ui],filterOutputs.back()); + filterOutputs.pop_back(); + + //Now, note we DONT break + //here; as there is more than one + } + + } + } + } + else + { + //OK, we don't have one and we would like one. + // We have to compute this. Wipe cache and start over + clearCache(); + } + needUpdate=true; + } + + break; + } + case KEY_NORMALISE_COMPOSITION: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=normaliseComposition; + normaliseComposition=(stripped == "1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=normaliseComposition) + { + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_CROP_SIZE: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=wantCropSize; + wantCropSize=(stripped == "1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=wantCropSize) + { + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_CROP_NMIN: + { + size_t ltmp; + if(stream_cast(ltmp,value)) + return false; + + if( ltmp > nMax) + return false; + + nMin=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case KEY_CROP_NMAX: + { + size_t ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp == 0) + ltmp = std::numeric_limits::max(); + + if( ltmp < nMin) + return false; + + nMax=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case KEY_SIZE_COUNT_BULK: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=sizeCountBulk; + if(stripped=="1") + sizeCountBulk=true; + else + sizeCountBulk=false; + + //if the result is different, the + //cache should be invalidated + if(lastVal!=sizeCountBulk) + { + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_WANT_CLUSTERMORPHOLOGY: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=wantClusterMorphology; + wantClusterMorphology=(stripped=="1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=wantClusterMorphology) + { + needUpdate=true; + clearCache(); + } + + break; + } + default: + { + ASSERT( key >=KEY_CORE_OFFSET); + //Set value is dictated by getProperties routine + //and is the vector push back value + if(key =KEY_CORE_OFFSET) + { + bool b; + if(stream_cast(b,value)) + return false; + //Core ions; convert key value to array offset + key-=KEY_CORE_OFFSET; + + //no need to update + if(ionCoreEnabled[key] == b) + return false; + + ionCoreEnabled[key]=b; + + //Check if we need to also need to disable + //ion bulk to preserve mutual exclusiveness. + if(ionBulkEnabled[key] == b && b) + ionBulkEnabled[key]=0; + + clearCache(); + needUpdate=true; + } + else if(key >=KEY_BULK_OFFSET) + { + bool b; + if(stream_cast(b,value)) + return false; + //Core ions; convert key value to array offset + key-=KEY_BULK_OFFSET; + + //no need to update + if(ionBulkEnabled[key] == b) + return false; + + ionBulkEnabled[key]=b; + + //Check if we need to also need to disable + //ion core to preserve mutual exclusiveness + if(ionCoreEnabled[key] == b && b) + ionCoreEnabled[key]=0; + + clearCache(); + needUpdate=true; + + } + else + { + ASSERT(false); + } + } + } + + + return true; +} + +bool ClusterAnalysisFilter::writeState(std::ostream &f,unsigned int format, + unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + //Core-linkage algorithm parameters + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + //Cropping control + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + //Postprocessing + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + + + f << tabs(depth+1) << "" << endl; + writeIonsEnabledXML(f,"core",ionCoreEnabled,ionNames,depth+2); + writeIonsEnabledXML(f,"bulk",ionCoreEnabled,ionNames,depth+2); + f << tabs(depth+1) << "" << endl; + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +size_t ClusterAnalysisFilter::numBytesForCache(size_t nObjects) const +{ + return (size_t)nObjects*IONDATA_SIZE; +} + +bool ClusterAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &packDir) +{ + using std::string; + + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Retrieve algorithm + //====== + if(!XMLGetNextElemAttrib(nodePtr,algorithm,"algorithm","value")) + return false; + if(algorithm >=CLUSTER_ALGORITHM_ENUM_END) + return false; + //=== + + //Retrieve parameter distances + //=== + switch(algorithm) + { + case CLUSTER_LINK_ERODE: + { + if(!XMLGetNextElemAttrib(nodePtr,coreDist,"coredist","value")) + return false; + if(coreDist<0) + return false; + if(!XMLGetNextElemAttrib(nodePtr,coreKNN,"coringknn","value")) + return false; + if(!coreKNN) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,linkDist,"linkdist","value")) + return false; + if(linkDist<=0) + return false; + if(!XMLGetNextElemAttrib(nodePtr,bulkLink,"bulklink","value")) + return false; + if(bulkLink<0) + return false; + if(!XMLGetNextElemAttrib(nodePtr,dErosion,"derosion","value")) + return false; + if(dErosion<0) + return false; + break; + } + default: + { + ASSERT(false); + return false; + } + } + //=== + + //Retrieve cropping info + //=== + xmlNodePtr tmpPtr; + tmpPtr=nodePtr; + + if(!XMLGetNextElemAttrib(nodePtr,wantCropSize,"wantcropsize","value")) + return false; + nodePtr=tmpPtr; + + if(!XMLGetNextElemAttrib(nodePtr,nMin,"nmin","value")) + return false; + nodePtr=tmpPtr; + if(!XMLGetNextElemAttrib(nodePtr,nMax,"nmax","value")) + return false; + nodePtr=tmpPtr; + + if(!XMLGetNextElemAttrib(nodePtr,wantClusterSizeDist,"wantclustersizedist","value")) + return false; + nodePtr=tmpPtr; + if(!XMLGetNextElemAttrib(nodePtr,logClusterSize,"wantclustersizedist","logarithmic")) + return false; + nodePtr=tmpPtr; + if(!XMLGetNextElemAttrib(nodePtr,sizeCountBulk,"wantclustersizedist","sizecountbulk")) + return false; + + tmpPtr=nodePtr; + if(!XMLGetNextElemAttrib(nodePtr,wantClusterComposition,"wantclustercomposition","value")) + return false; + nodePtr=tmpPtr; + if(!XMLGetNextElemAttrib(nodePtr,normaliseComposition,"wantclustercomposition","normalise")) + return false; + + + nodePtr=tmpPtr; + if(!XMLGetNextElemAttrib(nodePtr,wantClusterMorphology,"wantclustermorphology","value")) + return false; + //=== + + + //erase current enabled list. + ionCoreEnabled.clear(); + ionBulkEnabled.clear(); + + //Retrieve enabled selections + if(XMLHelpFwdToElem(nodePtr,"enabledions")) + return false; + + //Jump to ion sequence (/ level) + nodePtr=nodePtr->xmlChildrenNode; + + if(XMLHelpFwdToElem(nodePtr,"core")) + return false; + //Jump to level + tmpPtr=nodePtr->xmlChildrenNode; + + while(!XMLHelpFwdToElem(tmpPtr,"ion")) + { + int enabled; + if(!XMLGetAttrib(tmpPtr,enabled,"enabled")) + return false; + + ionCoreEnabled.push_back(enabled); + } + + if(XMLHelpFwdToElem(nodePtr,"bulk")) + return false; + tmpPtr=nodePtr->xmlChildrenNode; + + while(!XMLHelpFwdToElem(tmpPtr,"ion")) + { + int enabled; + if(!XMLGetAttrib(tmpPtr,enabled,"enabled")) + return false; + + ionBulkEnabled.push_back(enabled); + } + + return true; +} + +unsigned int ClusterAnalysisFilter::getRefreshBlockMask() const +{ + //Anything but ions can go through this filter. + return STREAM_TYPE_IONS; +} + +unsigned int ClusterAnalysisFilter::getRefreshEmitMask() const +{ + if(wantClusterSizeDist || wantClusterComposition || wantClusterMorphology) + return STREAM_TYPE_IONS | STREAM_TYPE_PLOT | STREAM_TYPE_DRAW; + else + return STREAM_TYPE_IONS; +} + +unsigned int ClusterAnalysisFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; +} + +std::string ClusterAnalysisFilter::getErrString(unsigned int i) const +{ + switch(i) + { + case ABORT_ERR: + return std::string(TRANS("Clustering aborted")); + case NOCORE_ERR: + return std::string(TRANS("No core ions for cluster")); + case NOBULK_ERR: + return std::string(TRANS("No bulk ions for cluster")); + default: + ASSERT(false); + } +} + +void ClusterAnalysisFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + +unsigned int ClusterAnalysisFilter::refreshLinkClustering(const std::vector &dataIn, + std::vector< std::vector > &clusteredCore, + std::vector > &clusteredBulk,ProgressData &progress, + bool (*callback)(bool)) +{ + + //Clustering algorithm, as per + //Stephenson, L. T.; et al + //Microscopy and Microanalysis, 2007, 13, 448-463 + // + //See also + //Vaumousse & Cerezo, + //Ultramicroscopy 95 (2003) 215–22 + + //Basic steps. Optional steps are denoted with a * + // + //1*) Core classification; work only on core ions (bulk is ignored) + // - Each "core" ion has sphere of specified size placed around it, + // if ion's kth-NN is within a given radius, then it is used as + // core, otherwise it is rejected to "bulk" + // + //2) Cluster Construction: A "backbone" is constructed using + // the core ions (after classification). + // - Each ion has a sphere placed around it of fixed size; if it contacts + // another ion, then these are considered as part of the same cluster. + // + //3*) Bulk inclusion step + // - For each cluster, every ion has a sphere placed around it. Bulk + // ions that lie within this union of spheres are assigned to the cluster + // This assignment is unambiguous *iff* this radius is smaller than that + // for the cluster construction step + // + //4*) Bulk Erosion step + // - Each unclustered bulk ion has a sphere placed around it. This sphere + // strips out ions from the cluster. This is only done once (ie, not iterative) + // + // In the implementation, there are more steps, due to data structure construction + // and other computational concerns + + bool needCoring=coreDist> std::numeric_limits::epsilon(); + bool needBulkLink=bulkLink > std::numeric_limits::epsilon(); + bool needErosion=dErosion> std::numeric_limits::epsilon() && needBulkLink; + unsigned int numClusterSteps=4; + if(needBulkLink) + numClusterSteps+=2; + if(needErosion) + numClusterSteps++; + if(needCoring) + numClusterSteps++; + + + + //Quick sanity check + if(needBulkLink) + { + //It is mildly dodgy to use a "bulk" distance larger than your core distance + //with relative dodgyness, depending upon cluster number density. + // + //This is because bulk components can "bridge", and assignment to the core + //clusters will depend upon the order in which the ions are traversed. + //At this point we should warn the user that this is the case, and suggest to them + //that we hope they know what they are doing. + + + if(bulkLink > linkDist/2.0) + { + consoleOutput.push_back(""); + consoleOutput.push_back(TRANS(" --------------------------- Parameter selection notice ------------- ") ); + consoleOutput.push_back(TRANS("You have specified a bulk distance larger than half your link distance.") ); + consoleOutput.push_back(TRANS("You can do this; thats OK, but the output is no longer independent of the computational process;") ); + consoleOutput.push_back(TRANS("This will be a problem in the case where two or more clusters can equally lay claim to a \"bulk\" ion. ") ); + consoleOutput.push_back(TRANS(" If your inter-cluster distance is sufficiently large (larger than your bulk linking distance), then you can get away with this.") ); + consoleOutput.push_back(TRANS(" In theory it is possible to \"join\" the clusters, but this has not been implemented for speed reasons.")); + consoleOutput.push_back(TRANS("If you want this, please contact the author, or just use the source to add this in yourself.") ); + consoleOutput.push_back(TRANS("---------------------------------------------------------------------- ") ); + consoleOutput.push_back(""); + } + + } + + //Collate the ions into "core", and "bulk" ions, based upon our ranging data + //---------- + progress.step=1; + progress.filterProgress=0; + progress.stepName=TRANS("Collate"); + progress.maxStep=numClusterSteps; + if(!(*callback)(true)) + return ABORT_ERR; + + vector coreIons,bulkIons; + createRangedIons(dataIn,coreIons,bulkIons,progress,callback); + + if(coreIons.empty()) + return 0; + //---------- + + K3DTreeMk2 coreTree,bulkTree; + BoundCube bCore,bBulk; + + //Build the core KD tree + //---------- + progress.step++; + progress.filterProgress=0; + progress.stepName=TRANS("Build Core"); + if(!(*callback)(true)) + return ABORT_ERR; + + //Build the core tree (eg, solute ions) + coreTree.setCallback(callback); + coreTree.setProgressPointer(&(progress.filterProgress)); + coreTree.resetPts(coreIons,false); + coreTree.build(); + + coreTree.getBoundCube(bCore); + //---------- + + if(needCoring) + { + //Perform Clustering Stage (1) : clustering classification + //== + progress.step++; + progress.stepName=TRANS("Classify Core"); + if(!(*callback)(true)) + return ABORT_ERR; + + vector coreOK; + ASSERT(coreIons.size() == coreTree.size()); + coreOK.resize(coreTree.size()); + float coreDistSqr=coreDist*coreDist; + + //TODO: the trees internal Tags prevent us from parallelising this. + // :(. If we could pass a tag map to the tree, this would solve the problem + for(size_t ui=0;ui tagsToClear; + + //Don't match ourselves -- to do this we must "tag" this tree node before we start + p=coreTree.getPt(ui); + coreTree.tag(ui); + tagsToClear.push_back(ui); + + k=1; + + //Loop through this ions NNs, seeing if the kth NN is within a given radius + do + { + pNN=coreTree.findNearestUntagged(*p,bCore,true); + tagsToClear.push_back(pNN); + k++; + + }while( pNN !=(size_t)-1 && ksqrDist(*(coreTree.getPt(pNN))); + coreOK[coreTree.getOrigIndex(ui)] = nnSqrDist < coreDistSqr; + } + + + //reset the tags, so we can find near NNs + coreTree.clearTags(tagsToClear); + tagsToClear.clear(); + + if(!(ui%PROGRESS_REDUCE)) + { + progress.filterProgress= (unsigned int)(((float)ui/(float)coreTree.size())*100.0f); + if(!(*callback)(false)) + return ABORT_ERR; + } + } + + + for(size_t ui=coreOK.size();ui;) + { + ui--; + + if(!coreOK[ui]) + { + //We have to convert the core ion to a bulk ion + //as it is rejected. + bulkIons.push_back(coreIons[ui]); + coreIons[ui]=coreIons.back(); + coreIons.pop_back(); + } + } + + //Re-Build the core KD tree + coreTree.setCallback(callback); + coreTree.setProgressPointer(&(progress.filterProgress)); + coreTree.resetPts(coreIons,false); + coreTree.build(); + + coreTree.getBoundCube(bCore); + //== + } + + + //Build the bulk tree (eg matrix ions.), as needed + if(needBulkLink) + { + progress.step++; + progress.stepName=TRANS("Build Bulk"); + if(!(*callback)(true)) + return ABORT_ERR; + bulkTree.setCallback(callback); + bulkTree.setProgressPointer(&(progress.filterProgress)); + bulkTree.resetPts(bulkIons,false); + bulkTree.build(); + } + //---------- + + + //Step 2 in the Process : Cluster Construction + //==== + //Loop over the solutes in the material, + //running searches from each solute. Group them using a queue + //that keeps on adding newly found solutes until it can find no more + //within a given radius. This becomes one cluster. + + //Update progress stuff + progress.step++; + progress.stepName=TRANS("Core"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + + vector > allCoreClusters,allBulkClusters; + const float linkDistSqr=linkDist*linkDist; + + size_t progressCount=0; + + //When this queue is exhausted, move to the next cluster + for(size_t ui=0;ui soluteCluster,dummy; + //Queue for atoms in this cluster waiting to be checked + //for their NNs. + std::queue thisClusterQueue; + + + //This solute is already clustered. move along. + if(coreTree.getTag(ui)) + continue; + coreTree.tag(ui); + + + + size_t clustIdx; + thisClusterQueue.push(ui); + soluteCluster.push_back(ui); + do + { + curPt=thisClusterQueue.front(); + const Point3D *thisPt; + thisPt=coreTree.getPt(curPt); + curDistSqr=0; + + + + //Now loop over this solute's NNs not found by prev. method + while(true) + { + ASSERT(curPt < coreTree.size()); + //Find the next point that we have not yet retrieved + //the find will tag the point, so we won't see it again + ASSERT(bCore.isValid()); + clustIdx=coreTree.findNearestUntagged( + *thisPt,bCore, true); + + + ASSERT(clustIdx == (size_t)-1 || coreTree.getTag(clustIdx)); + if(clustIdx != (size_t)-1) + { + curDistSqr=coreTree.getPt(clustIdx)->sqrDist( + *(coreTree.getPt(curPt)) ); + + } + + //Point out of clustering range, or no more points + if(clustIdx == (size_t)-1 || curDistSqr > linkDistSqr) + { + //If the point was not tagged, + //Un-tag the point; as it was too far away + if(clustIdx !=(size_t)-1) + coreTree.tag(clustIdx,false); + + thisClusterQueue.pop(); + break; + } + else + { + //Record it as part of the cluster + thisClusterQueue.push(clustIdx); + soluteCluster.push_back(clustIdx); + } + + + progressCount++; + if(!(progressCount%PROGRESS_REDUCE)) + { + //Progress may be a little non-linear if cluster sizes are not random + progress.filterProgress= (unsigned int)(((float)ui/(float)coreTree.size())*100.0f); + if(!(*callback)(false)) + return ABORT_ERR; + } + } + + + } // Keep looping whilst we have coreTree to cluster. + while(!thisClusterQueue.empty() && clustIdx !=(size_t)-1); + + + if(soluteCluster.size()) + { + //Record the solute cluster in the total array + allCoreClusters.push_back(dummy); + allCoreClusters.back().swap(soluteCluster); + soluteCluster.clear(); + } + } + + //==== + + //update progress + if(!(*callback)(false)) + return ABORT_ERR; + + //NOTE : Speedup trick. If we know the cluster size at this point + // and we know we don't want to count the bulk, we can strip out clusters + // now, as we are going to do that anyway as soon as we return from our cluster + // computation. + // The advantage to doing it now is that we can (potentially) drop lots of clusters + // from or analysis before we do the following steps, saving lots of time + if(!sizeCountBulk && (nMin > 0 || nMax <(size_t)-1) && wantCropSize ) + { + for(size_t ui=0;ui nMax) + { + allCoreClusters.back().swap(allCoreClusters[ui]); + allCoreClusters.pop_back(); + } + else + ui++; + + } + } + +#ifdef DEBUG + size_t coreClusterBeforeCount=allCoreClusters.size(); +#endif + //Step 3 in the Process : Bulk inclusion : AKA envelope + //==== + //If there is no bulk link step, we don't need to do that., + //or any of the following stages + if(needBulkLink) + { + + //Update progress stuff + progress.step++; + progress.stepName=TRANS("Bulk"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + if(bulkTree.size()) + { + bulkTree.getBoundCube(bBulk); + + //Compute the expected number of points that we would encapsulate + //if we were to place a sphere of size bulkLink in the KD domain. + // This allows us to choose whether to use a bulk "grab" approach, or not. + bool expectedPtsInSearchEnough; + expectedPtsInSearchEnough=((float)bulkTree.size())/bBulk.volume()*4.0/3.0*M_PI*pow(bulkLink,3.0f)> SPHERE_PRESEARCH_CUTOFF; + + //So-called "envelope" step. + float bulkLinkSqr=bulkLink*bulkLink; + size_t prog=PROGRESS_REDUCE; + //Now do the same thing with the matrix, but use the clusters as the "seed" + //positions + for(size_t ui=0;ui thisBulkCluster,dummy; + for(size_t uj=0;uj > blocks; + bulkTree.getTreesInSphere(*curPt,bulkLinkSqr,bBulk,blocks); + + for(size_t uj=0; ujsqrDist(*curPt); + } + + //Point out of clustering range, or no more points + if(bulkTreeIdx == (size_t)-1 || curDistSqr > bulkLinkSqr ) + { + //Un-tag the point; as it was too far away + if(bulkTreeIdx !=(size_t)-1) + bulkTree.tag(bulkTreeIdx,false); + break; + } + else + { + //Record it as part of the cluster + thisBulkCluster.push_back(bulkTreeIdx); + } + + prog--; + if(!prog) + { + prog=PROGRESS_REDUCE; + //Progress may be a little non-linear if cluster sizes are not random + progress.filterProgress= (unsigned int)(((float)ui/(float)allCoreClusters.size())*100.0f); + if(!(*callback)(false)) + return ABORT_ERR; + + } + } + + + + } + + + allBulkClusters.push_back(dummy); + allBulkClusters.back().swap(thisBulkCluster); + thisBulkCluster.clear(); + } + } + } + //==== + + +#ifdef DEBUG + size_t bulkClusterBeforeCount=allBulkClusters.size(); +#endif + //Step 4 in the Process : Bulk erosion + //==== + //Check if we need the erosion step + if(needErosion) + { + //Update progress stuff + progress.step++; + progress.stepName=TRANS("Erode"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + //Now perform the "erosion" step, where we strip off previously + //tagged matrix, if it is within a given distance of some untagged + //matrix + size_t numCounted=0; + bool spin=false; + + const float dErosionSqr=dErosion*dErosion; + #pragma omp parallel for + for(size_t ui=0;uisqrDist( + *(bulkTree.getPt(nnId)) ); + if( curDistSqr < dErosionSqr) + { + //Bulk is to be eroded. Swap it with the vector tail + //and pop it into oblivion. + std::swap(allBulkClusters[ui][uj], + allBulkClusters[ui].back()); + allBulkClusters[ui].pop_back(); + //Purposely do NOT advance the iterator, as we have + //new data at our current position (or we have hit end of + //array) + } + else + uj++; + + } + else + uj++; + + } + + if(!(ui%PROGRESS_REDUCE)) + { + #pragma omp critical + { + numCounted+=PROGRESS_REDUCE; + //Progress may be a little non-linear if cluster sizes are not random + progress.filterProgress= (unsigned int)(((float)numCounted/(float)allBulkClusters.size())*100.0f); + if(!(*callback)(false)) + spin=true; + } + + } + + } + + if(spin) + return ABORT_ERR; + } + //=== + + progress.step++; + progress.stepName=TRANS("Re-Collate"); + progress.filterProgress=0; + + //update progress + if(!(*callback)(true)) + return ABORT_ERR; + clusteredCore.resize(allCoreClusters.size()); + clusteredBulk.resize(allBulkClusters.size()); + + ASSERT(coreClusterBeforeCount == allCoreClusters.size()); //Must be equal, independant of erosion/bulk link steps + ASSERT(bulkClusterBeforeCount >= allBulkClusters.size()); //Must be <= after (optional) erosion step + + + //Use a no-barrier construct, to avoid the + //flush wait in the middle + #pragma omp parallel + { + #pragma omp for + for(size_t ui=0;ui > &core, const std::vector > &bulk) const +{ + for(size_t ui=0;ui &dataIn,vector &core, + vector &bulk, ProgressData &p, bool (*callback)(bool)) const +{ + + //TODO: Progress reporting and callback + ASSERT(haveRangeParent); + const RangeStreamData *r=0; + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + { + r = (const RangeStreamData *)dataIn[ui]; + break; + } + } + + ASSERT(r); + ASSERT(r->rangeFile->getNumIons() >=ionCoreEnabled.size()); + ASSERT(r->rangeFile->getNumIons() >=ionBulkEnabled.size()); + + //Maps the ionID for ranges in the PARENT rangeStreamData, to + //array offsets in the ionEnabled vectors. + // For example if ions 1 2 and 4 are enabled in the PARENT + // then this maps to offsets 1 2 and 3 in the ion(Core/Bulk)Enabled vectors + map rangeEnabledMap; + buildRangeEnabledMap(r,rangeEnabledMap); + ASSERT(rangeEnabledMap.size() == ionCoreEnabled.size()); + + bool needBulk = bulkLink > std::numeric_limits::epsilon(); + + if(needBulk) + { + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + const IonStreamData *d; + d=(const IonStreamData *)dataIn[ui]; + #pragma omp parallel for + for(size_t ui=0;uidata.size();ui++) + { + unsigned int ionId; + ionId=r->rangeFile->getIonID(d->data[ui].getMassToCharge()); + if(ionId!=(unsigned int)-1) + { + if( ionCoreEnabled[rangeEnabledMap[ionId]]) + { + #pragma omp critical + core.push_back(d->data[ui]); + } + else if(ionBulkEnabled[rangeEnabledMap[ionId]]) //mutually exclusive with core (both cannot be true) + { + #pragma omp critical + bulk.push_back(d->data[ui]); + } + } + } + } + + + } + } + else + { +#pragma omp parallel for + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + const IonStreamData *d; + d=(const IonStreamData *)dataIn[ui]; + for(size_t ui=0;uidata.size();ui++) + { + unsigned int ionId; + ionId=r->rangeFile->getIonID(d->data[ui].getMassToCharge()); + if(ionId!=(unsigned int)-1 && ionCoreEnabled[rangeEnabledMap[ionId]]) + { + #pragma omp critical + core.push_back(d->data[ui]); + } + } + } + } + } + +} + +PlotStreamData* ClusterAnalysisFilter::clusterSizeDistribution(const vector > &core, + const vector > &bulk) const +{ + //each cluster is represented by one entry in core and bulk + ASSERT(bulk.size() == core.size() || bulk.empty()); + + //Map that maps input number to frequency + map countMap; + size_t maxSize=0; + if(sizeCountBulk && bulk.size()) + { + ASSERT(bulk.size() == core.size()); + for(size_t ui=0;uiparent=this; + dist->r=1; + dist->g=0; + dist->b=0; + + + dist->xLabel=TRANS("Cluster Size"); + dist->yLabel=TRANS("Frequency"); + + dist->dataLabel=SIZE_DIST_DATALABEL; + dist->logarithmic=logClusterSize; + + dist->plotStyle=PLOT_TRACE_STEM; + dist->plotMode=PLOT_MODE_1D; + dist->xyData.resize(countMap.size()); + std::copy(countMap.begin(),countMap.end(),dist->xyData.begin()); + + return dist; +} + + +bool ClusterAnalysisFilter::stripClusterBySize(vector > &clusteredCore, + vector > &clusteredBulk, + bool (*callback)(bool),ProgressData &progress) const + +{ + + //TODO: Parallelise? Could create a vector of bools and then + // spin through, find the ones we want to kill, then do a cull. + // Progress reporting would be a bit more difficult. + + if(clusteredBulk.size() && sizeCountBulk) + { + //should be the same numbers of bulk as core + ASSERT(clusteredBulk.size() == clusteredCore.size()); + for(size_t ui=clusteredCore.size();ui;) + { + ui--; + //Count both bulk and core, and operate on both. + size_t count; + count =clusteredCore[ui].size() + clusteredBulk[ui].size() ; + + if(count < nMin || count > nMax) + { + clusteredCore[ui].swap(clusteredCore.back()); + clusteredCore.pop_back(); + clusteredBulk[ui].swap(clusteredBulk.back()); + clusteredBulk.pop_back(); + } + if(!(ui%PROGRESS_REDUCE) && clusteredCore.size()) + { + progress.filterProgress= (unsigned int)(((float)ui/(float)clusteredCore.size()+1)*100.0f); + + if(!(*callback)(false)) + return ABORT_ERR; + } + } + } + else if(sizeCountBulk) + { + //OK, we don't have any bulk, but we wanted it.. Just work on core. + for(size_t ui=clusteredCore.size();ui;) + { + ui--; + + if(clusteredCore[ui].size() < nMin || clusteredCore[ui].size() > nMax) + { + clusteredCore[ui].swap(clusteredCore.back()); + clusteredCore.pop_back(); + } + if(!(ui%PROGRESS_REDUCE) ) + { + progress.filterProgress= (unsigned int)(((float)ui/(float)clusteredCore.size()+1)*100.0f); + + if(!(*callback)(false)) + return ABORT_ERR; + } + } + } + else + { + //OK, we have bulk, but we just want to count core; + //but operate on both + for(size_t ui=clusteredCore.size();ui;) + { + ui--; + + if(clusteredCore[ui].size() < nMin || clusteredCore[ui].size() > nMax) + { + clusteredCore[ui].swap(clusteredCore.back()); + clusteredCore.pop_back(); + clusteredBulk[ui].swap(clusteredBulk.back()); + clusteredBulk.pop_back(); + } + if(!(ui%PROGRESS_REDUCE) ) + { + progress.filterProgress= (unsigned int)(((float)ui/(float)clusteredCore.size()+1)*100.0f); + + if(!(*callback)(false)) + return ABORT_ERR; + } + } + + } + + return true; +} + +void ClusterAnalysisFilter::genCompositionVersusSize(const vector > &clusteredCore, + const vector > &clusteredBulk, const RangeFile *rng,vector &plots) const +{ + ASSERT(rng && haveRangeParent) + + //Frequency of ions, as a function of composition. + //The inner vector is the the array of frequencies + //for this particular sie for each ion (ie, the array is of size rng->getNumIons) + map > countMap; + + bool needCountBulk=clusteredBulk.size() && sizeCountBulk; + + + vector ionFreq; + ionFreq.resize(rng->getNumIons(),0); + //Create the frequency table, per ion + //------- + //TODO: Below, there is a multi-threaded version. When we are happy with the single-threaded code + // try implementing the multi-threaded routine. + //Count the cluster elements, then increment the frequency table + if(needCountBulk) + { + ASSERT(clusteredBulk.size() == clusteredCore.size()); + + //Create entries of zero vectors for ion counting + for(size_t ui=0;uigetIonID(clusteredCore[ui][uj].getMassToCharge()); + countMap[curSize][offset]++; + } + + for(size_t uj=0;ujgetIonID(clusteredBulk[ui][uj].getMassToCharge()); + countMap[curSize][offset]++; + } + } + } + else + { + //Create entries of zero vectors for ion counting + for(size_t ui=0;uigetIonID(clusteredCore[ui][uj].getMassToCharge()); + + //this should not happen, as to cluster the ion,it must be ranged + ASSERT(offset!=(size_t)-1); + + countMap[curSize][offset]++; + } + } + } + //------- + + //Now that we have the freq table; we need to discard any elements that are not + //completely empty across the map. + // + // A vector that tells us if a given ionID is zero for all map entries. I.e. not in cluster + vector isZero; + isZero.resize(rng->getNumIons(),true); + + for(map >::iterator + it=countMap.begin(); it!=countMap.end();++it) + { + for(size_t ui=0;uisecond.size();ui++) + { + if(it->second[ui]) + isZero[ui]=false; + } + } + + + + //Ok now we know which frequency values are non-zero. Good! + // We need to build the plots, and their respective XY data, + // also we should normalise the compositions (if needed). + plots.reserve(rng->getNumIons()); + for(size_t ui=0;uigetNumIons();ui++) + { + //we don't need to plot this, + //as we didn't have any clustered ions of this type + if(isZero[ui]) + continue; + + //Make a new plot + PlotStreamData *p; + p=new PlotStreamData; + p->parent=this; + p->plotMode=PLOT_MODE_1D; + + RGBf ionColour; + ionColour=rng->getColour(ui); + + //Colour it as per the range file + p->r=ionColour.red; + p->g=ionColour.green; + p->b=ionColour.blue; + + p->xLabel=TRANS("Cluster Size"); + if(normaliseComposition) + p->yLabel=TRANS("Composition"); + else + p->yLabel=TRANS("Frequency"); + + p->dataLabel=string(CHEM_DIST_DATALABEL) + string(":") + rng->getName(ui); + p->logarithmic=logClusterSize && !normaliseComposition; + + p->plotStyle=PLOT_TRACE_STEM; + + p->xyData.resize(countMap.size()); + + size_t offset; + offset=0; + //set the data from our particular ion + for(map > ::iterator it=countMap.begin();it!=countMap.end();++it) + { + p->xyData[offset].first=it->first; + p->xyData[offset].second=it->second[ui]; + + //if we need to normalise compositions, we have to normalise over all + //ion types for this cluster size (ie the sum of this vector) + if(normaliseComposition) + { + size_t sum=0; + for(size_t uk=0; uksecond.size();uk++) + sum+=it->second[uk]; + p->xyData[offset].second /=(float)sum; + } + offset++; + } + + plots.push_back(p); + } + + +} + +void ClusterAnalysisFilter::getSingularValues(const vector > &clusteredCore, + const vector > &clusteredBulk, vector > &singularValues, + vector > > &singularVectors) const +{ + const unsigned int DIMENSION=3; + + float *data=0; + size_t dataSize=0; + if(clusteredBulk.size()) + { + ASSERT(clusteredCore.size() == clusteredBulk.size()); +//#pragma omp parallel for shared(singularValues,clusteredCore,clusteredBulk) private(data,dataSize) + for(unsigned int ui=0;ui curSingularVals; + vector curSingularBases; + + curSingularVals.clear(); + curSingularBases.clear(); + //For this cluster, compute its singular values amplitudes + // (ignore direction) + size_t numEntries = clusteredCore[ui].size() + clusteredBulk[ui].size(); + + + //Check to see if we have sufficient data to compute an SVD + if(numEntries <=DIMENSION ) + { +#pragma omp critical + { + singularValues.push_back(curSingularVals); + singularVectors.push_back(make_pair(Point3D(0,0,0),curSingularBases)); + } + continue; + } + + //Allocate space, by growing as needed + if(numEntries*DIMENSION > dataSize) + { + //TODO: Is it faster to pre-compute the maximum cluster size? + // then determine the cluster backbone from that? + // Should we be using realloc? + if(data) + delete[] data; + data = new float[numEntries*DIMENSION]; + dataSize=numEntries*DIMENSION; + } + + //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]); + + Point3D clusterCentre; + clusterCentre= centroid[0]+centroid[1]; + clusterCentre*=1.0f/(float)(clusteredCore[ui].size()+clusteredBulk[ui].size()); + + //Fill the data array + float *p; + p=data; + for(size_t uj=0;uj curSingularVals; + vector curSingularBases; + + curSingularVals.clear(); + curSingularBases.clear(); + //For this cluster, compute its singular values amplitudes + // (ignore direction) + size_t numEntries = clusteredCore[ui].size(); + + + //Check to see if we have sufficient data to compute an SVD + if(numEntries <=DIMENSION ) + { +#pragma omp critical + { + singularValues.push_back(curSingularVals); + singularVectors.push_back(make_pair(Point3D(0,0,0),curSingularBases)); + } + continue; + } + //Compute the cluster's centre of mass (assuming unit mass per object) + Point3D centroid; + getPointSum(clusteredCore[ui],centroid); + centroid*=1.0f/(float)(clusteredCore[ui].size()); + //Allocate space, by growing as needed + if(numEntries*DIMENSION > dataSize) + { + //TODO: Is it faster to pre-compute the maximum cluster size? + // then determine the cluster backbone from that? + // Should we be using realloc? + if(data) + delete[] data; + data = new float[numEntries*DIMENSION]; + dataSize=numEntries*DIMENSION; + } + + //Fill the data array + for(size_t uj=0;uj + +//Cluster Ids for generating cluster test datasets with genCluster +enum +{ + CLUSTER_UNITTEST_ISOLATED_WITH_BULK, + CLUSTER_UNITTEST_ISOLATED, + CLUSTER_UNITTEST_END +}; + +//Cluster sizes generated by genCluster +const unsigned int CLUSTER_SIZES[]= { 15, 9}; + +//Create a synthetic dataset of points for cluster +IonStreamData *genCluster(unsigned int datasetID); + +//Test several isolated clusters +bool isolatedClusterTest(); + +//Test the core mode of the core-link clustering algorithm +bool coreClusterTest(); + +//Unit tests +bool ClusterAnalysisFilter::runUnitTests() +{ + if(!isolatedClusterTest()) + return false; + + if(!coreClusterTest()) + return false; + return true; +} + + +IonStreamData *genCluster(unsigned int id) +{ + IonStreamData*d = new IonStreamData; + d->parent=0; + + IonHit a; + switch(id) + { + case CLUSTER_UNITTEST_ISOLATED_WITH_BULK: + { + //Create a "cloud" of bulk, isolated from the + // particle + a.setMassToCharge(1); + a.setPos(Point3D(2,2,4)); + d->data.push_back(a); + a.setPos(Point3D(4,0,1)); + d->data.push_back(a); + a.setPos(Point3D(-3,1,1)); + d->data.push_back(a); + a.setPos(Point3D(-2,1,2)); + d->data.push_back(a); + a.setPos(Point3D(-2,-1,2)); + d->data.push_back(a); + a.setPos(Point3D(-2,1,-2)); + d->data.push_back(a); + //Fall through; add in the core + //from the other test + } + case CLUSTER_UNITTEST_ISOLATED: + { + a.setMassToCharge(1); + + //Create a little network of points + //each at most 1 + //unit distance from another + a.setPos(Point3D(0,0,0)); + d->data.push_back(a); + a.setPos(Point3D(0,0,1)); + d->data.push_back(a); + a.setPos(Point3D(0,1,1)); + d->data.push_back(a); + a.setPos(Point3D(0,1,2)); + d->data.push_back(a); + a.setPos(Point3D(1,1,2)); + d->data.push_back(a); + a.setPos(Point3D(2,1,2)); + d->data.push_back(a); + a.setPos(Point3D(2,1,1)); + d->data.push_back(a); + a.setPos(Point3D(2,1,0)); + d->data.push_back(a); + a.setPos(Point3D(2,2,0)); + d->data.push_back(a); + break; + } + default: + ASSERT(false); + } + + ASSERT(CLUSTER_SIZES[id] == d->data.size()); + ASSERT(d->data.size()); + return d; +} + + +IonStreamData *genCoreTestCluster() +{ + IonStreamData* d = new IonStreamData; + d->parent=0; + + IonHit a; + a.setMassToCharge(1); + //Create two small groupings of points, + //with one group of 3 linked by unit distance + // then a second group of two further away + // unit distance apart, + // with one in between, spaced evenly between the two + a.setPos(Point3D(0,0,0)); + d->data.push_back(a); + a.setPos(Point3D(0,1,0)); + d->data.push_back(a); + a.setPos(Point3D(1,0,0)); + d->data.push_back(a); + + a.setPos(Point3D(0,0,2)); + d->data.push_back(a); + + a.setPos(Point3D(0,0,4)); + d->data.push_back(a); + a.setPos(Point3D(0,-1,4)); + d->data.push_back(a); + + return d; +} +//Test the "core-link + erode" algorithm +// - no core classification +// +bool isolatedClusterTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + //Create a range file with two + //range datasets, A and B + RangeFile r; + RGBf filler; + filler.red=filler.green=filler.blue=0.5f; + + unsigned int ionA,ionB; + std::string shortName,longName; + shortName="A"; longName="AType"; + ionA=r.addIon(shortName,longName,filler); + shortName="B"; longName="BType"; + ionB=r.addIon(shortName,longName,filler); + + r.addRange(0.5,1.5,ionA); + r.addRange(1.5,2.5,ionB); + + //Build a rangestream data + RangeStreamData *rng = new RangeStreamData; + rng->rangeFile=&r; + rng->parent=0; + rng->enabledIons.resize(r.getNumIons(),1); + rng->enabledRanges.resize(r.getNumRanges(),1); + + //Create a cluster analysis filter + ClusterAnalysisFilter *f=new ClusterAnalysisFilter; + f->setCaching(false); + f->wantParanoidDebug=true; + + + streamIn.push_back(rng); + f->initFilter(streamIn,streamOut); + streamOut.clear(); + + //Enable A as core, and B as bulk + bool needUp; + TEST(f->setProperty(KEY_CORE_OFFSET,"1",needUp),"Set prop"); + + TEST(f->setProperty(KEY_CORECLASSIFYDIST,"0",needUp),"Set prop"); + TEST(f->setProperty(KEY_LINKDIST,"1.1",needUp),"Set prop"); + TEST(f->setProperty(KEY_BULKLINK,"1.1",needUp),"Set prop"); + TEST(f->setProperty(KEY_ERODEDIST,"0",needUp),"Set prop"); + + //stop the plots + TEST(f->setProperty(KEY_WANT_CLUSTERSIZEDIST,"0",needUp),"Set prop"); + TEST(f->setProperty(KEY_WANT_COMPOSITIONDIST,"0",needUp),"Set prop"); + + for(unsigned int ui=0;uirefresh(streamIn,streamOut,p,dummyCallback)),"Refresh err code"); + + //Kill the input ion stream, and remove old pointer + delete d; + streamIn.pop_back(); + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + //Use an auto_ptr so if the test fails, we still free ram + { + auto_ptr outD((const IonStreamData*)streamOut[0]); + TEST(outD->data.size() == CLUSTER_SIZES[ui],"Cluster size"); + + switch(ui) + { + case CLUSTER_UNITTEST_ISOLATED: + { + for(unsigned int ui=0;uidata.size();ui++) + { + TEST(r.getIonID(outD->data[ui].getMassToCharge()) + == ionA,"cluster ranging"); + } + break; + } + case CLUSTER_UNITTEST_ISOLATED_WITH_BULK: + { + //Check bulk contains bulk or core + for(unsigned int ui=0;uidata.size();ui++) + { + unsigned int idIon; + idIon=r.getIonID(outD->data[ui].getMassToCharge()); + TEST( idIon== ionB || idIon == ionA,"cluster ranging "); + } + + break; + } + default: + ASSERT(false); + } + + } + + + streamOut.clear(); + + } + + delete rng; + delete f; + return true; +} + +bool coreClusterTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + //Create a range file with two + //range datasets, A and B + RangeFile r; + RGBf filler; + filler.red=filler.green=filler.blue=0.5f; + + unsigned int ionA,ionB; + std::string shortName,longName; + shortName="A"; longName="AType"; + ionA=r.addIon(shortName,longName,filler); + shortName="B"; longName="BType"; + ionB=r.addIon(shortName,longName,filler); + + r.addRange(0.5,1.5,ionA); + r.addRange(1.5,2.5,ionB); + + //Build a rangestream data + RangeStreamData *rng = new RangeStreamData; + rng->rangeFile=&r; + rng->parent=0; + rng->enabledIons.resize(r.getNumIons(),1); + rng->enabledRanges.resize(r.getNumRanges(),1); + + //Create a cluster analysis filter + ClusterAnalysisFilter *f=new ClusterAnalysisFilter; + f->setCaching(false); + f->wantParanoidDebug=true; + + + streamIn.push_back(rng); + f->initFilter(streamIn,streamOut); + streamOut.clear(); + + //Enable A as core + bool needUp; + TEST(f->setProperty(KEY_CORE_OFFSET,"1",needUp),"Set core range"); + + TEST(f->setProperty(KEY_CORECLASSIFYDIST,"1.1",needUp),"Set core classification dist"); + TEST(f->setProperty(KEY_CORECLASSIFYKNN,"1",needUp),"Set core classfication kNN"); + TEST(f->setProperty(KEY_LINKDIST,"2.0",needUp),"set link distance"); + TEST(f->setProperty(KEY_BULKLINK,"0",needUp),"set bulk distance"); + TEST(f->setProperty(KEY_ERODEDIST,"0",needUp),"set erode distance"); + + //stop the plots + TEST(f->setProperty(KEY_WANT_CLUSTERSIZEDIST,"0",needUp),"Set prop"); + TEST(f->setProperty(KEY_WANT_COMPOSITIONDIST,"0",needUp),"Set prop"); + + IonStreamData *ionData = genCoreTestCluster(); + + streamIn.push_back(ionData); + + //Do the refresh + ProgressData p; + TEST(!(f->refresh(streamIn,streamOut,p,dummyCallback)),"Refresh err code"); + delete f; + delete ionData; + delete rng; + + TEST(streamOut.size() == 1,"stream count"); + + const IonStreamData *outD=(const IonStreamData*)streamOut[0];; + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + TEST(outD->data.size() == 5,"Total Cluster size"); + + delete outD; + + + return true; +} + + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/clusterAnalysis.h 3depict-0.0.13/src/backend/filters/clusterAnalysis.h --- 3depict-0.0.12/src/backend/filters/clusterAnalysis.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/clusterAnalysis.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,167 @@ +/* + * clusterAnalysis.h - Cluster analysis on valued point clouds + * 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 . +*/ +#ifndef CLUSTERANALYSIS_H +#define CLUSTERANALYSIS_H +#include "../filter.h" +#include "../../common/translation.h" + +#include + +//!Cluster analysis filter +class ClusterAnalysisFilter : public Filter +{ + private: + //Clustering algorithm to use + unsigned int algorithm; + + //Algorithm parameters + //--- + //Core-linkage "core" classification distance + float coreDist; + //Coring kNN maximum + unsigned int coreKNN; + //Link distance for core + float linkDist; + //Link distance for bulk + float bulkLink; + //Erosion distance for bulk from nonclustered bulk + float dErosion; + //--- + + //post processing options + //Minimum/max number of "core" entires to qualify as, + //well, a meaningful cluster + bool wantCropSize; + size_t nMin,nMax; + bool sizeCountBulk; + + bool wantClusterSizeDist,logClusterSize; + + //Do we want the composition data for the cluster + bool wantClusterComposition, normaliseComposition; + + //Do we want a morphological analysis + bool wantClusterMorphology; + + //!Do we have range data to use + bool haveRangeParent; + //!The names of the incoming ions + std::vector ionNames; + + //!Which ions are core/builk for a particular incoming range? + std::vector ionCoreEnabled,ionBulkEnabled; + + //Do cluster refresh using Link Algorithm (Core + max sep) + unsigned int refreshLinkClustering(const std::vector &dataIn, + std::vector< std::vector > &clusteredCore, + std::vector > &clusteredBulk,ProgressData &progress, + bool (*callback)(bool)); + + + //Helper function to create core and bulk vectors of ions from input ionstreams + void createRangedIons(const std::vector &dataIn, + std::vector &core,std::vector &bulk, + ProgressData &p,bool (*callback)(bool)) const; + + + //Check to see if there are any core or bulk ions enabled respectively. + void checkIonEnabled(bool &core, bool &bulk) const; + + static void buildRangeEnabledMap(const RangeStreamData *r, + map &rangeEnabledMap); + + //Strip out clusters with a given number of elements + bool stripClusterBySize(vector > &clusteredCore, + vector > &clusteredBulk, + bool (*callback)(bool), ProgressData &p) const; + //Build a plot that is the cluster size distribution as a function of cluster size + PlotStreamData *clusterSizeDistribution(const vector > &solutes, + const vector > &matrix) const; + + + //Build plots that are the cluster size distribution as + // a function of cluster size, specific to each ion type. + void genCompositionVersusSize(const vector > &clusteredCore, + const vector > &clusteredBulk, const RangeFile *rng, + vector &plots) const; + +#ifdef DEBUG + bool paranoidDebugAssert(const std::vector > &core, + const std::vector > &bulk) const; +#endif +#ifdef DEBUG + public: +#endif + //COmpute the singular values that area associated with each cluster + void getSingularValues(const vector > &clusteredCore, + const vector > &clusteredBulk, vector > &singularValues, + vector > > &singularVectors) const; + public: + ClusterAnalysisFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //!Initialise filter prior to tree propagation + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + + //!Returns -1, as range file cache size is dependant upon input. + virtual size_t numBytesForCache(size_t nObjects) const; + //!Returns FILTER_TYPE_SPATIAL_ANALYSIS + unsigned int getType() const { return FILTER_TYPE_CLUSTER_ANALYSIS;}; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + //!Get the type string for this filter + virtual std::string typeString() const { return std::string(TRANS("Cluster Analysis"));}; + + std::string getErrString(unsigned int i) const; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshUseMask() const; + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + +#ifdef DEBUG + bool wantParanoidDebug; + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/compositionProfile.cpp 3depict-0.0.13/src/backend/filters/compositionProfile.cpp --- 3depict-0.0.12/src/backend/filters/compositionProfile.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/compositionProfile.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -0,0 +1,1859 @@ +/* + * compositionProfile.cpp - Compute composition profiles from valued point clouds + * 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 . +*/ +#include "compositionProfile.h" +#include "../plot.h" + +#include "filterCommon.h" +#include "geometryHelpers.h" + + +//!Possible primitive types for composition profiles +enum +{ + PRIMITIVE_CYLINDER, + PRIMITIVE_SPHERE, + PRIMITIVE_END, //Not actually a primitive, just end of enum +}; + +//!Error codes +enum +{ + ERR_NUMBINS=1, + ERR_MEMALLOC, + ERR_ABORT +}; + +const char *PRIMITIVE_NAME[]={ + NTRANS("Cylinder"), + NTRANS("Sphere") +}; + +const float DEFAULT_RADIUS = 10.0f; + + +CompositionProfileFilter::CompositionProfileFilter() : primitiveType(PRIMITIVE_CYLINDER), + showPrimitive(true), lockAxisMag(false),normalise(true), fixedBins(0), + nBins(1000), binWidth(0.5f), r(0.0f),g(0.0f),b(1.0f),a(1.0f), plotStyle(0) +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(PRIMITIVE_NAME) == PRIMITIVE_END); + + errMode.mode=PLOT_ERROR_NONE; + errMode.movingAverageNum=4; + + vectorParams.push_back(Point3D(0.0,0.0,0.0)); + vectorParams.push_back(Point3D(0,20.0,0.0)); + scalarParams.push_back(DEFAULT_RADIUS); + + haveRangeParent=false; +} + + +void CompositionProfileFilter::binIon(unsigned int targetBin, const RangeStreamData* rng, + const map &ionIDMapping, + vector > &frequencyTable, float massToCharge) +{ + //if we have no range data, then simply increment its position in a 1D table + //which will later be used as "count" data (like some kind of density plot) + if(!rng) + { + ASSERT(frequencyTable.size() == 1); + //There is a really annoying numerical boundary case + //that makes the target bin equate to the table size. + //disallow this. + if(targetBin < frequencyTable[0].size()) + frequencyTable[0][targetBin]++; + return; + } + + + //We have range data, we need to use it to classify the ion and then increment + //the appropriate position in the table + unsigned int rangeID = rng->rangeFile->getRangeID(massToCharge); + + if(rangeID != (unsigned int)(-1) && rng->enabledRanges[rangeID]) + { + unsigned int ionID=rng->rangeFile->getIonID(rangeID); + unsigned int pos; + pos = ionIDMapping.find(ionID)->second; + frequencyTable[pos][targetBin]++; + } +} + + +Filter *CompositionProfileFilter::cloneUncached() const +{ + CompositionProfileFilter *p = new CompositionProfileFilter(); + + p->primitiveType=primitiveType; + p->showPrimitive=showPrimitive; + p->vectorParams.resize(vectorParams.size()); + p->scalarParams.resize(scalarParams.size()); + + std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin()); + std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin()); + + p->normalise=normalise; + p->fixedBins=fixedBins; + p->lockAxisMag=lockAxisMag; + + p->binWidth=binWidth; + p->nBins = nBins; + p->r=r; + p->g=g; + p->b=b; + p->a=a; + p->plotStyle=plotStyle; + p->errMode=errMode; + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +void CompositionProfileFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + //Check for range file parent + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + { + haveRangeParent=true; + return; + } + } + haveRangeParent=false; +} + +unsigned int CompositionProfileFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, + bool (*callback)(bool)) +{ + //Clear selection devices + clearDevices(); + + if(showPrimitive) + { + //TODO: This is a near-copy of ionClip.cpp - refactor + //construct a new primitive, do not cache + DrawStreamData *drawData=new DrawStreamData; + drawData->parent=this; + switch(primitiveType) + { + case PRIMITIVE_CYLINDER: + { + //Origin + normal + ASSERT(vectorParams.size() == 2); + //Add drawable components + DrawCylinder *dC = new DrawCylinder; + dC->setOrigin(vectorParams[0]); + dC->setRadius(scalarParams[0]); + dC->setColour(0.5,0.5,0.5,0.3); + dC->setSlices(40); + dC->setLength(sqrt(vectorParams[1].sqrMag())*2.0f); + dC->setDirection(vectorParams[1]); + dC->wantsLight=true; + drawData->drawables.push_back(dC); + + + //Set up selection "device" for user interaction + //==== + //The object is selectable + dC->canSelect=true; + //Start and end radii must be the same (not a + //tapered cylinder) + dC->lockRadii(); + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding b; + //Bind the drawable object to the properties we wish + //to be able to modify + + //Bind left + command button to move + b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_CYLINDER_BIND_ORIGIN, + BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + //Bind left + shift to change orientation + b.setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_CYLINDER_BIND_DIRECTION, + BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); + if(lockAxisMag) + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); + else + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); + s->addBinding(b); + + //Bind right button to changing position + b.setBinding(SELECT_BUTTON_RIGHT,0,DRAW_CYLINDER_BIND_ORIGIN, + BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + //Bind middle button to changing orientation + b.setBinding(SELECT_BUTTON_MIDDLE,0,DRAW_CYLINDER_BIND_DIRECTION, + BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); + if(lockAxisMag) + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); + else + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); + s->addBinding(b); + + //Bind left button to changing radius + b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_CYLINDER_BIND_RADIUS, + BINDING_CYLINDER_RADIUS,dC->getRadius(),dC); + b.setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + b.setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(b); + + devices.push_back(s); + //===== + + break; + } + case PRIMITIVE_SPHERE: + { + //Add drawable components + DrawSphere *dS = new DrawSphere; + dS->setOrigin(vectorParams[0]); + dS->setRadius(scalarParams[0]); + //FIXME: Alpha blending is all screwed up. May require more + //advanced drawing in scene. (front-back drawing). + //I have set alpha=1 for now. + dS->setColour(0.5,0.5,0.5,1.0); + dS->setLatSegments(40); + dS->setLongSegments(40); + dS->wantsLight=true; + drawData->drawables.push_back(dS); + + //Set up selection "device" for user interaction + //Note the order of s->addBinding is critical, + //as bindings are selected by first match. + //==== + //The object is selectable + dS->canSelect=true; + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding b[3]; + + //Apple doesn't have right click, so we need + //to hook up an additional system for them. + //Don't use ifdefs, as this would be useful for + //normal laptops and the like. + b[0].setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_SPHERE_BIND_ORIGIN, + BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); + b[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b[0]); + + //Bind the drawable object to the properties we wish + //to be able to modify + b[1].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_RADIUS, + BINDING_SPHERE_RADIUS,dS->getRadius(),dS); + b[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + b[1].setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(b[1]); + + b[2].setBinding(SELECT_BUTTON_RIGHT,0,DRAW_SPHERE_BIND_ORIGIN, + BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); + b[2].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b[2]); + + devices.push_back(s); + //===== + break; + } + default: + ASSERT(false); + } + drawData->cached=0; + getOut.push_back(drawData); + } + + + //use the cached copy of the data if we have it. + if(cacheOK) + { + //propagate our cached plot data. + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_PLOT); + + //Propagate all the incoming data (including ions) + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) + getOut.push_back(dataIn[ui]); + } + + return 0; + } + + //Ion Frequencies (composition specific if rangefile present) + vector > ionFrequencies; + + RangeStreamData *rngData=0; + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + { + rngData =((RangeStreamData *)dataIn[ui]); + break; + } + } + + float length; + unsigned int numBins, errCode; + errCode=getBinData(numBins,length); + if(errCode) + return errCode; + + //Indirection vector to convert ionFrequencies position to ionID mapping. + //Should only be used in conjunction with rngData == true + std::map ionIDMapping,inverseIDMapping; + //Allocate space for the frequency table + if(rngData) + { + ASSERT(rngData->rangeFile); + unsigned int enabledCount=0; + for(unsigned int ui=0;uirangeFile->getNumIons();ui++) + { + //TODO: Might be nice to detect if an ions ranges + //are all, disabled then if they are, enter this "if" + //anyway + if(rngData->enabledIons[ui]) + { + //Keep the forwards mapping for binning + ionIDMapping.insert(make_pair(ui,enabledCount)); + //Keep the inverse mapping for labelling + inverseIDMapping.insert(make_pair(enabledCount,ui)); + enabledCount++; + } + + + + } + + //Nothing to do. + if(!enabledCount) + return 0; + + try + { + ionFrequencies.resize(enabledCount); + //Allocate and Initialise all elements to zero + #pragma omp parallel for + for(unsigned int ui=0;ui primitiveMap; + primitiveMap[PRIMITIVE_CYLINDER] = CROP_CYLINDER_INSIDE; + primitiveMap[PRIMITIVE_SPHERE] = CROP_SPHERE_INSIDE; + + CropHelper dataMapping(callback,&progress.filterProgress, + totalSize,primitiveMap[primitiveType], vectorParams,scalarParams ); + dataMapping.setMapMaxima(numBins); + + unsigned int curProg=NUM_CALLBACK; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + //Process ion streams + for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); + it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) + { + unsigned int targetBin; + targetBin=dataMapping.mapIon1D(*it); + + //Keep ion if inside cylinder + if(targetBin!=(unsigned int)-1) + { + //Push data into the correct bin. + // based upon eg ranging information and target 1D bin + binIon(targetBin,rngData,ionIDMapping,ionFrequencies, + it->getMassToCharge()); + } + + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + curProg=NUM_CALLBACK; + if(!(*callback)(false)) + return ERR_ABORT; + } + } + + break; + } + default: + //Do not propagate other types. + break; + } + + } + + PlotStreamData *plotData[ionFrequencies.size()]; + float normFactor=1.0f; + for(unsigned int ui=0;uiindex=ui; + plotData[ui]->parent=this; + plotData[ui]->xLabel= TRANS("Distance"); + plotData[ui]->errDat=errMode; + if(normalise) + { + //If we have composition, normalise against + //sum composition = 1 otherwise use volume of bin + //as normalisation factor + if(rngData) + plotData[ui]->yLabel= TRANS("Fraction"); + else + plotData[ui]->yLabel= TRANS("Density (\\#.len^3)"); + } + else + plotData[ui]->yLabel= TRANS("Count"); + + //Give the plot a title like TRANS("Myplot:Mg" (if have range) or "MyPlot") (no range) + if(rngData) + { + unsigned int thisIonID; + thisIonID = inverseIDMapping.find(ui)->second; + plotData[ui]->dataLabel = getUserString() + string(":") + + rngData->rangeFile->getName(thisIonID); + + + //Set the plot colour to the ion colour + RGBf col; + col=rngData->rangeFile->getColour(thisIonID); + + plotData[ui]->r =col.red; + plotData[ui]->g =col.green; + plotData[ui]->b =col.blue; + + } + else + { + //If it only has one component, then + //it's not really a composition profile is it? + plotData[ui]->dataLabel= TRANS("Freq. Profile"); + plotData[ui]->r = r; + plotData[ui]->g = g; + plotData[ui]->b = b; + plotData[ui]->a = a; + } + + plotData[ui]->xyData.resize(ionFrequencies[ui].size()); + + //Density profiles (non-ranged plots) have a fixed normalisation factor + if(!rngData && normalise) + { + switch(primitiveType) + { + case PRIMITIVE_CYLINDER: + if(fixedBins) + normFactor = 1.0/(M_PI*scalarParams[0]*scalarParams[0]*(length/(float)numBins)); + else + normFactor = 1.0/(M_PI*scalarParams[0]*scalarParams[0]*binWidth); + break; + case PRIMITIVE_SPHERE: + break; + default: + ASSERT(false); + } + } + + //Go through each bin, then perform the appropriate normalisation + for(unsigned int uj=0;ujxyData[uj] = std::make_pair(xPos,normFactor*(float)ionFrequencies[ui][uj]); + } + else + { + //This is a frequency profile (factor ==1), or density profile + + //Update the normalisation factor, if required + if(normalise) + { + switch(primitiveType) + { + case PRIMITIVE_SPHERE: + normFactor=1.0/(xPos*xPos); + break; + case PRIMITIVE_CYLINDER: + break; + default: + ASSERT(false); + } + } + + plotData[ui]->xyData[uj] = std::make_pair( + xPos,normFactor*(float)ionFrequencies[ui][uj]); + + } + } + + if(cache) + { + plotData[ui]->cached=1; + filterOutputs.push_back(plotData[ui]); + } + else + plotData[ui]->cached=0; + + plotData[ui]->plotStyle = plotStyle; + plotData[ui]->plotMode=PLOT_MODE_1D; + getOut.push_back(plotData[ui]); + } + + cacheOK=cache; + return 0; +} + +std::string CompositionProfileFilter::getErrString(unsigned int code) const +{ + switch(code) + { + case ERR_NUMBINS: + return std::string(TRANS("Too many bins in comp. profile.")); + case ERR_MEMALLOC: + return std::string(TRANS("Not enough memory for comp. profile.")); + case ERR_ABORT: + return std::string(TRANS("Aborted composition prof.")); + } + return std::string("BUG: (CompositionProfileFilter::getErrString) Shouldn't see this!"); +} + +bool CompositionProfileFilter::setProperty( unsigned int key, + const std::string &value, bool &needUpdate) +{ + + + switch(key) + { + case COMPOSITION_KEY_BINWIDTH: + { + float newBinWidth; + if(stream_cast(newBinWidth,value)) + return false; + + if(newBinWidth < sqrt(std::numeric_limits::epsilon())) + return false; + + binWidth=newBinWidth; + clearCache(); + needUpdate=true; + break; + } + case COMPOSITION_KEY_FIXEDBINS: + { + unsigned int valueInt; + if(stream_cast(valueInt,value)) + return false; + + if(valueInt ==0 || valueInt == 1) + { + if(fixedBins!= (bool)valueInt) + { + needUpdate=true; + fixedBins=valueInt; + } + else + needUpdate=false; + } + else + return false; + clearCache(); + needUpdate=true; + break; + } + case COMPOSITION_KEY_NORMAL: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(primitiveType == PRIMITIVE_CYLINDER) + { + if(lockAxisMag && + newPt.sqrMag() > sqrt(std::numeric_limits::epsilon())) + { + newPt.normalise(); + newPt*=sqrt(vectorParams[1].sqrMag()); + } + } + + if(!(vectorParams[1] == newPt )) + { + vectorParams[1] = newPt; + needUpdate=true; + clearCache(); + } + return true; + } + case COMPOSITION_KEY_NUMBINS: + { + unsigned int newNumBins; + if(stream_cast(newNumBins,value)) + return false; + + //zero bins disallowed + if(!newNumBins) + return false; + + nBins=newNumBins; + + clearCache(); + needUpdate=true; + break; + } + case COMPOSITION_KEY_ORIGIN: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(vectorParams[0] == newPt )) + { + vectorParams[0] = newPt; + needUpdate=true; + clearCache(); + } + + return true; + } + case COMPOSITION_KEY_PRIMITIVETYPE: + { + unsigned int newPrimitive; + newPrimitive=getPrimitiveId(value); + if(newPrimitive >= PRIMITIVE_END) + return false; + + //set the new primitive type + primitiveType=newPrimitive; + + //set up the values for the new primitive type, + // preserving data where possible + switch(primitiveType) + { + case PRIMITIVE_CYLINDER: + { + if(vectorParams.size() != 2) + { + if(vectorParams.size() <2 ) + { + vectorParams.clear(); + vectorParams.push_back(Point3D(0,0,0)); + vectorParams.push_back(Point3D(0,20,0)); + } + else + vectorParams.resize(2); + } + + if(scalarParams.size() != 1) + { + if (scalarParams.size() > 1) + { + scalarParams.clear(); + scalarParams.push_back(DEFAULT_RADIUS); + } + else + scalarParams.resize(1); + } + break; + } + case PRIMITIVE_SPHERE: + { + if(vectorParams.size() !=1) + { + if(vectorParams.size() >1) + vectorParams.resize(1); + else + vectorParams.push_back(Point3D(0,0,0)); + } + + if(scalarParams.size() !=1) + { + if(scalarParams.size() > 1) + scalarParams.resize(1); + else + scalarParams.push_back(DEFAULT_RADIUS); + } + break; + } + + default: + ASSERT(false); + } + + clearCache(); + needUpdate=true; + return true; + } + case COMPOSITION_KEY_RADIUS: + { + float newRad; + if(stream_cast(newRad,value)) + return false; + + if(scalarParams[0] != newRad ) + { + scalarParams[0] = newRad; + needUpdate=true; + clearCache(); + } + return true; + } + case COMPOSITION_KEY_SHOWPRIMITIVE: + { + unsigned int valueInt; + if(stream_cast(valueInt,value)) + return false; + + if(valueInt ==0 || valueInt == 1) + { + if(showPrimitive!= (bool)valueInt) + { + needUpdate=true; + showPrimitive=valueInt; + } + else + needUpdate=false; + } + else + return false; + break; + } + + case COMPOSITION_KEY_NORMALISE: + { + unsigned int valueInt; + if(stream_cast(valueInt,value)) + return false; + + if(!(valueInt ==0 || valueInt == 1)) + return false; + + if(normalise!= (bool)valueInt) + { + needUpdate=true; + normalise=valueInt; + } + else + needUpdate=false; + + clearCache(); + needUpdate=true; + break; + } + case COMPOSITION_KEY_LOCKAXISMAG: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + lockAxisMag=(stripped=="1"); + + needUpdate=true; + + break; + } + + case COMPOSITION_KEY_PLOTTYPE: + { + unsigned int tmpPlotType; + + tmpPlotType=plotID(value); + + if(tmpPlotType >= PLOT_TRACE_ENDOFENUM) + return false; + + plotStyle = tmpPlotType; + needUpdate=true; + break; + } + case COMPOSITION_KEY_COLOUR: + { + unsigned char newR,newG,newB,newA; + parseColString(value,newR,newG,newB,newA); + + r=((float)newR)/255.0f; + g=((float)newG)/255.0f; + b=((float)newB)/255.0f; + a=1.0; + + needUpdate=true; + break; + } + case COMPOSITION_KEY_ERRMODE: + { + unsigned int tmpMode; + tmpMode=plotErrmodeID(value); + + if(tmpMode >= PLOT_ERROR_ENDOFENUM) + return false; + + errMode.mode= tmpMode; + needUpdate=true; + + break; + } + case COMPOSITION_KEY_AVGWINSIZE: + { + unsigned int tmpNum; + stream_cast(tmpNum,value); + if(tmpNum<=1) + return 1; + + errMode.movingAverageNum=tmpNum; + needUpdate=true; + break; + } + default: + ASSERT(false); + } + + if(needUpdate) + clearCache(); + + return true; +} + +void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) const +{ + string str,tmpStr; + FilterProperty p; + size_t curGroup=0; + + //Allow primitive selection if we have more than one primitive + if(PRIMITIVE_END > 1) + { + //Choices for primitive type + vector > choices; + for(unsigned int ui=0;ui > choices; + + + tmpStr=plotString(PLOT_TRACE_LINES); + choices.push_back(make_pair((unsigned int) PLOT_TRACE_LINES,tmpStr)); + tmpStr=plotString(PLOT_TRACE_BARS); + choices.push_back(make_pair((unsigned int)PLOT_TRACE_BARS,tmpStr)); + tmpStr=plotString(PLOT_TRACE_STEPS); + choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEPS,tmpStr)); + tmpStr=plotString(PLOT_TRACE_STEM); + choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEM,tmpStr)); + + tmpStr= choiceString(choices,plotStyle); + p.name=TRANS("Plot Type"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_CHOICE; + p.helpText=TRANS("Visual style for plot"); + p.key=COMPOSITION_KEY_PLOTTYPE; + propertyList.addProperty(p,curGroup); + //Convert the colour to a hex string + if(!haveRangeParent) + { + string thisCol; + genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0), + (unsigned char)(b*255.0),(unsigned char)(a*255.0),thisCol); + + p.name=TRANS("Colour"); + p.data=thisCol; + p.type=PROPERTY_TYPE_COLOUR; + p.helpText=TRANS("Colour of plot"); + p.key=COMPOSITION_KEY_COLOUR; + propertyList.addProperty(p,curGroup); + } + + + propertyList.setGroupTitle(curGroup,TRANS("Appearance")); + curGroup++; + + choices.clear(); + tmpStr=plotErrmodeString(PLOT_ERROR_NONE); + choices.push_back(make_pair((unsigned int) PLOT_ERROR_NONE,tmpStr)); + tmpStr=plotErrmodeString(PLOT_ERROR_MOVING_AVERAGE); + choices.push_back(make_pair((unsigned int) PLOT_ERROR_MOVING_AVERAGE,tmpStr)); + + tmpStr= choiceString(choices,errMode.mode); + p.name=TRANS("Err. Estimator"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_CHOICE; + p.helpText=TRANS("Method of estimating error associated with each bin"); + p.key=COMPOSITION_KEY_ERRMODE; + propertyList.addProperty(p,curGroup); + + if(errMode.mode == PLOT_ERROR_MOVING_AVERAGE) + { + stream_cast(tmpStr,errMode.movingAverageNum); + p.name=TRANS("Avg. Window"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_INTEGER; + p.helpText=TRANS("Number of bins to include in moving average filter"); + p.key=COMPOSITION_KEY_AVGWINSIZE; + propertyList.addProperty(p,curGroup); + } + propertyList.setGroupTitle(curGroup,TRANS("Error analysis")); +} + +unsigned int CompositionProfileFilter::getBinData(unsigned int &numBins, float &length) const +{ + //Number of bins, having determined if we are using + //fixed bin count or not + switch(primitiveType) + { + case PRIMITIVE_SPHERE: + //radius of sphere + length=scalarParams[0]; + break; + case PRIMITIVE_CYLINDER: + //length of cylinder, full axis length + length=sqrt(vectorParams[1].sqrMag()); + break; + default: + ASSERT(false); + } + + if(fixedBins) + numBins=nBins; + else + { + switch(primitiveType) + { + case PRIMITIVE_CYLINDER: + case PRIMITIVE_SPHERE: + { + + ASSERT(binWidth > std::numeric_limits::epsilon()); + + //Check for possible overflow + if(length/binWidth > (float)std::numeric_limits::max()) + return ERR_NUMBINS; + + numBins=(unsigned int)(length/binWidth); + break; + } + default: + ASSERT(false); + } + + } + + return 0; +} + +//!Get approx number of bytes for caching output +size_t CompositionProfileFilter::numBytesForCache(size_t nObjects) const +{ + float length; + unsigned int errCode, numBins; + errCode=getBinData(numBins,length); + + if(errCode) + return (unsigned int)-1; + + return (numBins*2*sizeof(float)); +} + +bool CompositionProfileFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + for(unsigned int ui=0; ui" << endl; + } + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + for(unsigned int ui=0; ui" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" <" << endl; + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + + +void CompositionProfileFilter::setUserString(const std::string &str) +{ + if(userString != str) + { + userString=str; + clearCache(); + } +} + +bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + std::string tmpStr; + //Retrieve primitive type + //==== + if(XMLHelpFwdToElem(nodePtr,"primitivetype")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(primitiveType,tmpStr)) + return false; + + if(primitiveType >= PRIMITIVE_END) + return false; + xmlFree(xmlString); + //==== + + //Retrieve primitive visibility + //==== + if(XMLHelpFwdToElem(nodePtr,"showprimitive")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + showPrimitive=false; + else if(tmpStr == "1") + showPrimitive=true; + else + return false; + + xmlFree(xmlString); + //==== + + //Retrieve axis lock mode + //==== + if(XMLHelpFwdToElem(nodePtr,"lockaxismag")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + lockAxisMag=false; + else if(tmpStr == "1") + lockAxisMag=true; + else + return false; + + xmlFree(xmlString); + //==== + + //Retreive vector parameters + //=== + if(XMLHelpFwdToElem(nodePtr,"vectorparams")) + return false; + xmlNodePtr tmpNode=nodePtr; + + nodePtr=nodePtr->xmlChildrenNode; + + vectorParams.clear(); + while(!XMLHelpFwdToElem(nodePtr,"point3d")) + { + float x,y,z; + //--Get X value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(x,tmpStr)) + return false; + + //--Get Z value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(y,tmpStr)) + return false; + + //--Get Y value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(z,tmpStr)) + return false; + + vectorParams.push_back(Point3D(x,y,z)); + } + //=== + + nodePtr=tmpNode; + //Retreive scalar parameters + //=== + if(XMLHelpFwdToElem(nodePtr,"scalarparams")) + return false; + + tmpNode=nodePtr; + nodePtr=nodePtr->xmlChildrenNode; + + scalarParams.clear(); + while(!XMLHelpFwdToElem(nodePtr,"scalar")) + { + float v; + //Get value + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(v,tmpStr)) + return false; + scalarParams.push_back(v); + } + //=== + + //Check the scalar params match the selected primitive + switch(primitiveType) + { + case PRIMITIVE_CYLINDER: + if(vectorParams.size() != 2 || scalarParams.size() !=1) + return false; + break; + case PRIMITIVE_SPHERE: + if(vectorParams.size() != 1 || scalarParams.size() !=1) + return false; + break; + + default: + ASSERT(false); + return false; + } + + nodePtr=tmpNode; + + //Retrieve normalisation on/off + //==== + if(XMLHelpFwdToElem(nodePtr,"normalise")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + normalise=false; + else if(tmpStr == "1") + normalise=true; + else + return false; + + xmlFree(xmlString); + //==== + + //Retrieve fixed bins on/off + //==== + if(XMLHelpFwdToElem(nodePtr,"fixedbins")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + fixedBins=false; + else if(tmpStr == "1") + fixedBins=true; + else + return false; + + + xmlFree(xmlString); + //==== + + //Retrieve num bins + //==== + if(XMLHelpFwdToElem(nodePtr,"nbins")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(nBins,tmpStr)) + return false; + + xmlFree(xmlString); + //==== + + //Retrieve bin width + //==== + if(XMLHelpFwdToElem(nodePtr,"binwidth")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(binWidth,tmpStr)) + return false; + + xmlFree(xmlString); + //==== + + //Retrieve colour + //==== + if(XMLHelpFwdToElem(nodePtr,"colour")) + return false; + if(!parseXMLColour(nodePtr,r,g,b,a)) + return false; + //==== + + //Retrieve plot type + //==== + if(XMLHelpFwdToElem(nodePtr,"plottype")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(plotStyle,tmpStr)) + return false; + + if(plotStyle >= PLOT_TRACE_ENDOFENUM) + return false; + xmlFree(xmlString); + //==== + + return true; +} + +unsigned int CompositionProfileFilter::getRefreshBlockMask() const +{ + //Absolutely anything can go through this filter. + return 0; +} + +unsigned int CompositionProfileFilter::getRefreshEmitMask() const +{ + if(showPrimitive) + return STREAM_TYPE_PLOT | STREAM_TYPE_DRAW; + else + return STREAM_TYPE_PLOT; +} + +unsigned int CompositionProfileFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; +} + +void CompositionProfileFilter::setPropFromBinding(const SelectionBinding &b) +{ + switch(b.getID()) + { + case BINDING_CYLINDER_RADIUS: + case BINDING_SPHERE_RADIUS: + b.getValue(scalarParams[0]); + break; + case BINDING_CYLINDER_ORIGIN: + case BINDING_SPHERE_ORIGIN: + b.getValue(vectorParams[0]); + break; + case BINDING_CYLINDER_DIRECTION: + b.getValue(vectorParams[1]); + break; + default: + ASSERT(false); + } + + clearCache(); +} + +unsigned int CompositionProfileFilter::getPrimitiveId(const std::string &primitiveName) const +{ + for(size_t ui=0;ui > &compositionData, + vector &h); +IonStreamData *synthLinearProfile(const Point3D &start, const Point3D &end, + float radialSpread,unsigned int numPts); + +bool CompositionProfileFilter::runUnitTests() +{ + if(!testDensityCylinder()) + return false; + + if(!testCompositionCylinder()) + return false; + + return true; +} + +bool testCompositionCylinder() +{ + IonStreamData *d; + const size_t NUM_PTS=10000; + + //Create a cylinder of data, forming a linear profile + Point3D startPt(-1.0f,-1.0f,-1.0f),endPt(1.0f,1.0f,1.0f); + d= synthLinearProfile(startPt,endPt, + 0.5f, NUM_PTS); + + //Generate two compositions for the test dataset + { + vector > vecCompositions; + vecCompositions.push_back(make_pair(2.0f,0.5f)); + vecCompositions.push_back(make_pair(3.0f,0.5f)); + synthComposition(vecCompositions,d->data); + } + + //Build a faux rangestream + RangeStreamData *rngStream; + rngStream = new RangeStreamData; + rngStream->rangeFile = new RangeFile; + + RGBf rgb; rgb.red=rgb.green=rgb.blue=1.0f; + + unsigned int aIon,bIon; + std::string tmpStr; + tmpStr="A"; + aIon=rngStream->rangeFile->addIon(tmpStr,tmpStr,rgb); + tmpStr="B"; + bIon=rngStream->rangeFile->addIon(tmpStr,tmpStr,rgb); + rngStream->rangeFile->addRange(1.5,2.5,aIon); + rngStream->rangeFile->addRange(2.5,3.5,bIon); + rngStream->enabledIons.resize(2,true); + rngStream->enabledRanges.resize(2,true); + + //Construct the composition filter + CompositionProfileFilter *f = new CompositionProfileFilter; + + //Build some points to pass to the filter + vector streamIn,streamOut; + + bool needUp; std::string s; + stream_cast(s,Point3D((startPt+endPt)*0.5f)); + TEST(f->setProperty(COMPOSITION_KEY_ORIGIN,s,needUp),"set origin"); + + stream_cast(s,Point3D((endPt-startPt)*0.5f)); + TEST(f->setProperty(COMPOSITION_KEY_NORMAL,s,needUp),"set direction"); + TEST(f->setProperty(COMPOSITION_KEY_SHOWPRIMITIVE,"1",needUp),"Set cylinder visibility"); + TEST(f->setProperty(COMPOSITION_KEY_NORMALISE,"1",needUp),"Disable normalisation"); + TEST(f->setProperty(COMPOSITION_KEY_RADIUS,"5",needUp),"Set radius"); + + //Inform the filter about the range stream + streamIn.push_back(rngStream); + f->initFilter(streamIn,streamOut); + + streamIn.push_back(d); + f->setCaching(false); + + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + + TEST(streamOut.size() == 3, "output stream count"); + + delete d; + + std::map countMap; + countMap[STREAM_TYPE_PLOT] = 0; + countMap[STREAM_TYPE_DRAW] = 0; + + for(unsigned int ui=0;uigetStreamType()) != countMap.end()); + countMap[streamOut[ui]->getStreamType()]++; + } + + TEST(countMap[STREAM_TYPE_PLOT] == 2,"Plot count"); + TEST(countMap[STREAM_TYPE_DRAW] == 1,"Draw count"); + + const PlotStreamData* plotData=0; + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + plotData = (const PlotStreamData *)streamOut[ui]; + break; + } + } + + TEST(plotData->xyData.size(),"Plot data size"); + + for(size_t ui=0;uixyData.size(); ui++) + { + TEST(plotData->xyData[ui].second <= 1.0f && + plotData->xyData[ui].second >=0.0f,"normalised data range test"); + } + + for(unsigned int ui=0;uirangeFile; + delete rngStream; + + return true; +} + +bool testDensityCylinder() +{ + IonStreamData *d; + const size_t NUM_PTS=10000; + + //Create a cylinder of data, forming a linear profile + Point3D startPt(-1.0f,-1.0f,-1.0f),endPt(1.0f,1.0f,1.0f); + d= synthLinearProfile(startPt,endPt, + 0.5f, NUM_PTS); + + //Generate two compositions for the test dataset + { + vector > vecCompositions; + vecCompositions.push_back(make_pair(2.0f,0.5f)); + vecCompositions.push_back(make_pair(3.0f,0.5f)); + synthComposition(vecCompositions,d->data); + } + + CompositionProfileFilter *f = new CompositionProfileFilter; + f->setCaching(false); + + //Build some points to pass to the filter + vector streamIn,streamOut; + streamIn.push_back(d); + + bool needUp; std::string s; + stream_cast(s,Point3D((startPt+endPt)*0.5f)); + TEST(f->setProperty(COMPOSITION_KEY_ORIGIN,s,needUp),"set origin"); + + stream_cast(s,Point3D((endPt-startPt))); + TEST(f->setProperty(COMPOSITION_KEY_NORMAL,s,needUp),"set direction"); + + TEST(f->setProperty(COMPOSITION_KEY_SHOWPRIMITIVE,"1",needUp),"Set cylinder visibility"); + + TEST(f->setProperty(COMPOSITION_KEY_NORMALISE,"0",needUp),"Disable normalisation"); + TEST(f->setProperty(COMPOSITION_KEY_RADIUS,"5",needUp),"Set radius"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + delete f; + delete d; + + + TEST(streamOut.size() == 2, "output stream count"); + + std::map countMap; + countMap[STREAM_TYPE_PLOT] = 0; + countMap[STREAM_TYPE_DRAW] = 0; + + for(unsigned int ui=0;uigetStreamType()) != countMap.end()); + countMap[streamOut[ui]->getStreamType()]++; + } + + TEST(countMap[STREAM_TYPE_PLOT] == 1,"Plot count"); + TEST(countMap[STREAM_TYPE_DRAW] == 1,"Draw count"); + + + const PlotStreamData* plotData=0; + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + plotData = (const PlotStreamData *)streamOut[ui]; + break; + } + } + + float sum=0; + for(size_t ui=0;uixyData.size(); ui++) + sum+=plotData->xyData[ui].second; + + + TEST(sum > NUM_PTS/1.2f,"Number points roughly OK"); + TEST(sum <= NUM_PTS,"No overcounting"); + + for(unsigned int ui=0;ui > &compositionData, + vector &h) +{ + float fractionSum=0; + for(size_t ui=0;ui > ionCuts; + ionCuts.resize(compositionData.size()); + //ionCuts.resize[compositionData.size()]; + float runningSum=0; + for(size_t ui=0;ui=ionCuts[uj].second) + { + newMass=ionCuts[uj].first; + haveSetMass=true; + break; + } + } + }while(!haveSetMass); + + + h[ui].setMassToCharge(newMass); + } +} + + +//Create a line of points of fixed mass (1), with a top-hat radial spread function +// so we end up with a cylinder of unit mass data along some start-end axis +//you must free the returned value by calling "delete" +IonStreamData *synthLinearProfile(const Point3D &start, const Point3D &end, + float radialSpread,unsigned int numPts) +{ + + ASSERT((start-end).sqrMag() > std::numeric_limits::epsilon()); + IonStreamData *d = new IonStreamData; + + IonHit h; + h.setMassToCharge(1.0f); + + Point3D delta; + delta=(end-start)*1.0f/(float)numPts; + + RandNumGen rngAxial; + rngAxial.initTimer(); + + Point3D unitDelta; + unitDelta=delta; + unitDelta.normalise(); + + + d->data.resize(numPts); + for(size_t ui=0;ui::epsilon() && + randomVector.angle(delta) < std::numeric_limits::epsilon()); + + + randomVector=randomVector.crossProd(unitDelta); + randomVector.normalise(); + + //create the point + Point3D pt; + pt=delta*(float)ui + start; //true location + pt+=randomVector*radialSpread; + h.setPos(pt); + d->data[ui] =h; + } + + return d; +} +#endif diff -Nru 3depict-0.0.12/src/backend/filters/compositionProfile.h 3depict-0.0.13/src/backend/filters/compositionProfile.h --- 3depict-0.0.12/src/backend/filters/compositionProfile.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/compositionProfile.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * compositionProfile.h - Composition profiles of 3D point clouds + * 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 . +*/ +#ifndef COMPPROFILE_H +#define COMPPROFILE_H +#include "../filter.h" +#include "../../common/translation.h" + +#include + +enum +{ + COMPOSITION_KEY_BINWIDTH=1, + COMPOSITION_KEY_FIXEDBINS, + COMPOSITION_KEY_NORMAL, + COMPOSITION_KEY_NUMBINS, + COMPOSITION_KEY_ORIGIN, + COMPOSITION_KEY_PLOTTYPE, + COMPOSITION_KEY_PRIMITIVETYPE, + COMPOSITION_KEY_RADIUS, + COMPOSITION_KEY_SHOWPRIMITIVE, + COMPOSITION_KEY_NORMALISE, + COMPOSITION_KEY_COLOUR, + COMPOSITION_KEY_ERRMODE, + COMPOSITION_KEY_AVGWINSIZE, + COMPOSITION_KEY_LOCKAXISMAG +}; +//!Filter that does composition profiles for various primitives +class CompositionProfileFilter : public Filter +{ + private: + + //!Number explaining basic primitive type + /* Possible Modes: + * Cylindrical (origin + axis + length) + */ + unsigned int primitiveType; + //!Whether to show the primitive or not + bool showPrimitive; + //Lock the primitive axis during for cylinder? + bool lockAxisMag; + //!Vector parameters for different primitives + vector vectorParams; + //!Scalar parameters for different primitives + vector scalarParams; + + //!Frequency or percentile mode (0 - frequency; 1-normalised (ion freq)) + bool normalise; + //!Use fixed bins? + bool fixedBins; + + //!number of bins (if using fixed bins) + unsigned int nBins; + //!Width of each bin (if using fixed width) + float binWidth; + + //Plotting stuff + //Vector of spectra. Each spectra is comprised of a sorted Y data + std::vector< std::vector > spectraCache; + float r,g,b,a; + unsigned int plotStyle; + + PLOT_ERROR errMode; + + //!Do we have a range file above us in our filter tree? This is set by ::initFilter + bool haveRangeParent; + + //!internal function for binning an ion dependant upon range data + static void binIon(unsigned int targetBin, const RangeStreamData* rng, const std::map &ionIDMapping, + vector > &frequencyTable, float massToCharge); + + unsigned int getPrimitiveId(const std::string &s) const; + + //obtain the size of each bin, and number of bins required for profile + unsigned int getBinData(unsigned int &numBins, float &binLength) const; + + public: + CompositionProfileFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + //!Returns FILTER_TYPE_COMPOSITION + unsigned int getType() const { return FILTER_TYPE_COMPOSITION;}; + + //!Get approx number of bytes for caching output + size_t numBytesForCache(size_t nObjects) const; + + + //!Initialise filter, check for upstream range + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + //!update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + virtual std::string typeString() const { return std::string(TRANS("Comp. Prof."));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter. Returns true if prop set OK + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that may be utilised in computation during ::refresh + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding + void setPropFromBinding(const SelectionBinding &b) ; + + void setUserString(const std::string &s); + +#ifdef DEBUG + bool runUnitTests() ; +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/dataLoad.cpp 3depict-0.0.13/src/backend/filters/dataLoad.cpp --- 3depict-0.0.12/src/backend/filters/dataLoad.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/dataLoad.cpp 2013-04-05 21:37:53.000000000 +0000 @@ -0,0 +1,1328 @@ +/* + * dataLoad.cpp - filter to load datasets from various source + * 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 . +*/ +#include "dataLoad.h" + +//Needed for modification time +#include +#include +#include "../../wxcommon.h" + +#include "filterCommon.h" + + +//Default number of ions to load +const size_t MAX_IONS_LOAD_DEFAULT=5*1024*1024/(4*sizeof(float)); //5 MB worth. + +// Tp prevent the dropdown lists from getting too unwieldy, set an artificial maximum +const unsigned int MAX_NUM_FILE_COLS=5000; + +//Allowable text file deliminators +const char *TEXT_DELIMINATORS = "\t ,"; + +//Supported data types +enum +{ + FILEDATA_TYPE_POS, + FILEDATA_TYPE_TEXT, + FILEDATA_TYPE_ENUM_END, // Not a data type, just end of enum +}; + +const char *AVAILABLE_FILEDATA_TYPES[] = { NTRANS("POS Data"), + NTRANS("Text Data"), + }; +const char *DEFAULT_LABEL="Mass-to-Charge (amu/e)"; + +// == Pos load filter == +DataLoadFilter::DataLoadFilter() : fileType(FILEDATA_TYPE_POS), doSample(true), maxIons(MAX_IONS_LOAD_DEFAULT), + r(1.0f),g(0.0f),b(0.0f),a(1.0f),ionSize(2.0f), numColumns(4), enabled(true), + volumeRestrict(false), monitorTimestamp(-1),monitorSize((size_t)-1),wantMonitor(false), + valueLabel(TRANS(DEFAULT_LABEL)) +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(AVAILABLE_FILEDATA_TYPES) == FILEDATA_TYPE_ENUM_END); + cache=true; + + bound.setInverseLimits(); + + for (unsigned int i = 0; i < numColumns; i++) { + index[i] = i; + } + +} + +Filter *DataLoadFilter::cloneUncached() const +{ + DataLoadFilter *p=new DataLoadFilter; + p->ionFilename=ionFilename; + p->doSample=doSample; + p->maxIons=maxIons; + p->ionSize=ionSize; + p->fileType=fileType; + p->guessType=guessType; + //Colours + p->r=r; + p->g=g; + p->b=b; + p->a=a; + p->fileType=fileType; + //Bounding volume + p->bound.setBounds(bound); + p->volumeRestrict=volumeRestrict; + p->numColumns=numColumns; + p->enabled=enabled; + + for(size_t ui=0;uiindex[ui]=index[ui]; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->enabled=enabled; + p->userString=userString; + + p->wantMonitor=wantMonitor; + // this is for a pos file + memcpy(p->index, index, sizeof(int) * 4); + p->numColumns=numColumns; + + return p; +} + + +void DataLoadFilter::setFileMode(unsigned int fileMode) +{ + switch(fileMode) + { + case DATALOAD_TEXT_FILE: + fileType=FILEDATA_TYPE_TEXT; + break; + case DATALOAD_FLOAT_FILE: + fileType=FILEDATA_TYPE_POS; + break; + default: + ASSERT(false); + } +} + + +void DataLoadFilter::setFilename(const char *name) +{ + ionFilename = name; + guessNumColumns(); +} + +void DataLoadFilter::setFilename(const std::string &name) +{ + ionFilename = name; + guessNumColumns(); +} + +void DataLoadFilter::guessNumColumns() +{ + //Test the extension to determine what we will do + string extension; + if(ionFilename.size() > 4) + extension = ionFilename.substr ( ionFilename.size() - 4, 4 ); + + //Set extension to lowercase version + for(size_t ui=0;ui &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + errStr=""; + //use the cached copy if we have it. + if(cacheOK) + { + bool doUseCache=true; + //If we are monitoring the file, + //the cache is only valid if we have + //the same timestamp as on the file. + if(wantMonitor) + { + if(!wxFile::Exists(wxStr(ionFilename))) + { + monitorTimestamp=-1; + monitorSize=-1; + doUseCache=false; + clearCache(); + } + else + { + //How can we have a valid cache if we don't + //have a valid load time? + ASSERT(monitorTimestamp!=-1 && monitorSize!=(size_t)-1); + + + size_t fileSizeVal; + getFilesize(ionFilename.c_str(),fileSizeVal); + if(wxFileModificationTime(wxStr(ionFilename)) ==monitorTimestamp + || fileSizeVal!= monitorSize) + { + doUseCache=false; + clearCache(); + } + } + } + + //Use the cache if it is still OK, otherwise use + //the full function + if(doUseCache) + { + ASSERT(filterOutputs.size()); + for(unsigned int ui=0;uiparent=this; + + unsigned int uiErr; + switch(fileType) + { + case FILEDATA_TYPE_POS: + { + if(doSample) + { + //Load the pos file, limiting how much you pull from it + if((uiErr = LimitLoadPosFile(numColumns, INDEX_LENGTH, index, ionData->data, ionFilename.c_str(), + maxIons,progress.filterProgress,callback,strongRandom))) + { + consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); + delete ionData; + errStr=TRANS(POS_ERR_STRINGS[uiErr]); + return uiErr; + } + } + else + { + if((uiErr = GenericLoadFloatFile(numColumns, INDEX_LENGTH, index, ionData->data, ionFilename.c_str(), + progress.filterProgress,callback))) + { + consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); + delete ionData; + errStr=TRANS(POS_ERR_STRINGS[uiErr]); + return uiErr; + } + } + break; + } + case FILEDATA_TYPE_TEXT: + { + + + if(doSample) + { + //TODO: Migrate to using a generic text data loading routine + // rather than an IonHit specific one, to avoid need for separate error strings + //Load the data from a text file + if((uiErr = limitLoadTextFile(INDEX_LENGTH,index,ionData->data, ionFilename.c_str(),TEXT_DELIMINATORS, + maxIons,progress.filterProgress,callback,strongRandom))) + { + consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); + delete ionData; + errStr=ION_TEXT_ERR_STRINGS[uiErr]; + return uiErr; + } + } + else + { + vector > outDat; + vector headerData; + if((uiErr=loadTextData(ionFilename.c_str(),outDat,headerData,TEXT_DELIMINATORS))) + { + consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); + delete ionData; + errStr=TEXT_LOAD_ERR_STRINGS[uiErr]; + return uiErr; + } + + + + if(outDat.size() !=4) + { + std::string sizeStr; + stream_cast(sizeStr,outDat.size()); + + consoleOutput.push_back( + string(TRANS("Data file contained incorrect number of columns -- should be 4, was ")) + sizeStr ); + + errStr=TEXT_LOAD_ERR_STRINGS[ERR_FILE_FORMAT]; + return ERR_FILE_FORMAT; + } + + + ASSERT(outDat[0].size() == outDat[1].size() && + outDat[1].size() == outDat[2].size() + && outDat[2].size() == outDat[3].size()); + + ionData->data.resize(outDat[0].size()); + #pragma omp parallel for + for(unsigned int ui=0;uidata[ui].setPos(outDat[0][ui],outDat[1][ui],outDat[2][ui]); + ionData->data[ui].setMassToCharge(outDat[3][ui]); + } + } + + + break; + } + + default: + ASSERT(false); + } + + + ionData->r = r; + ionData->g = g; + ionData->b = b; + ionData->a = a; + ionData->ionSize=ionSize; + ionData->valueType=valueLabel; + + + if(ionData->data.empty()) + { + //Shouldn't get here... + ASSERT(false); + delete ionData; + return 0; + } + + + BoundCube dataCube; + dataCube = getIonDataLimits(ionData->data); + + if(dataCube.isNumericallyBig()) + { + consoleOutput.push_back( + TRANS("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")); + } + + string s; + stream_cast(s,ionData->data.size()); + consoleOutput.push_back( string(TRANS("Loaded ") + s + TRANS(" Points")) ); + if(cache) + { + ionData->cached=1; + filterOutputs.push_back(ionData); + cacheOK=true; + } + else + ionData->cached=0; + + for(unsigned int ui=0;ui > choices; + + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + IonStreamData *i; + i=(IonStreamData *)filterOutputs[ui]; + i->r=r; + i->g=g; + i->b=b; + i->a=a; + } + } + + } + needUpdate=true; + } + + + break; + } + case DATALOAD_KEY_IONSIZE: + { + float ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp < 0) + return false; + + ionSize=ltmp; + + //Check the cache, updating it if needed + if(cacheOK) + { + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + IonStreamData *i; + i=(IonStreamData *)filterOutputs[ui]; + i->ionSize=ionSize; + } + } + } + needUpdate=true; + + break; + } + case DATALOAD_KEY_VALUELABEL: + { + if(value !=valueLabel) + { + valueLabel=value; + needUpdate=true; + + //Check the cache, updating it if needed + if(cacheOK) + { + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + IonStreamData *i; + i=(IonStreamData *)filterOutputs[ui]; + i->valueType=valueLabel; + } + } + } + + } + + break; + } + case DATALOAD_KEY_SELECTED_COLUMN0: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp >= numColumns) + return false; + + index[0]=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case DATALOAD_KEY_SELECTED_COLUMN1: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp >= numColumns) + return false; + + index[1]=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case DATALOAD_KEY_SELECTED_COLUMN2: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp >= numColumns) + return false; + + index[2]=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case DATALOAD_KEY_SELECTED_COLUMN3: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp >= numColumns) + return false; + + index[3]=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case DATALOAD_KEY_NUMBER_OF_COLUMNS: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp >= MAX_NUM_FILE_COLS) + return false; + + numColumns=ltmp; + for (unsigned int i = 0; i < INDEX_LENGTH; i++) { + index[i] = (index[i] < numColumns? index[i]: numColumns - 1); + } + needUpdate=true; + clearCache(); + + break; + } + default: + ASSERT(false); + break; + } + return true; +} + +bool DataLoadFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Retrieve file name + if(XMLHelpFwdToElem(nodePtr,"file")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); + if(!xmlString) + return false; + ionFilename=(char *)xmlString; + xmlFree(xmlString); + + //retrieve file type (text,pos etc), if needed; default to pos. + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"type"); + if(xmlString) + { + int type; + if(stream_cast(type,xmlString)) + return false; + + if(fileType >=FILEDATA_TYPE_ENUM_END) + return false; + fileType=type; + xmlFree(xmlString); + } + else + fileType=FILEDATA_TYPE_POS; + + + //Override the string, as needed + if( (stateFileDir.size()) && + (ionFilename.size() > 2 && ionFilename.substr(0,2) == "./") ) + { + ionFilename=stateFileDir + ionFilename.substr(2); + } + + //Filenames need to be converted from unix format (which I make canonical on disk) into native format + ionFilename=convertFileStringToNative(ionFilename); + + //Retrieve number of columns + if(!XMLGetNextElemAttrib(nodePtr,numColumns,"columns","value")) + return false; + if(numColumns >= MAX_NUM_FILE_COLS) + return false; + + //Retrieve index + if(XMLHelpFwdToElem(nodePtr,"xyzm")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values"); + if(!xmlString) + return false; + std::vector v; + splitStrsRef((char *)xmlString,',',v); + for (unsigned int i = 0; i < INDEX_LENGTH && i < v.size(); i++) + { + if(stream_cast(index[i],v[i])) + return false; + + if(index[i] >=numColumns) + return false; + } + xmlFree(xmlString); + + //Retrieve enabled/disabled + //-- + unsigned int tmpVal; + if(!XMLGetNextElemAttrib(nodePtr,tmpVal,"enabled","value")) + return false; + enabled=tmpVal; + //-- + + //Retrieve monitor mode + //-- + xmlNodePtr nodeTmp; + nodeTmp=nodePtr; + if(XMLGetNextElemAttrib(nodePtr,tmpVal,"monitor","value")) + wantMonitor=tmpVal; + else + { + nodePtr=nodeTmp; + wantMonitor=false; + } + //-- + + //Retrieve value type string (eg mass-to-charge, + // or whatever the data type is) + //-- + nodeTmp=nodePtr; + if(XMLHelpFwdToElem(nodePtr,"valuetype")) + { + nodePtr=nodeTmp; + valueLabel=TRANS(DEFAULT_LABEL); + } + else + { + xmlChar *xmlString; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + valueLabel=(char *)xmlString; + xmlFree(xmlString); + + } + + //-- + + + //Get sampling enabled/disabled + //--- + //TODO: Remove me: + // Note, in 3Depict-0.0.10 and lower, we did not have this option, + // so some statefiles will exist without this. In the case it is not + // found, we need to make it up + { + nodeTmp=nodePtr; + bool needSampleState=false; + if(!XMLGetNextElemAttrib(nodePtr,doSample,"dosample","value")) + { + nodePtr=nodeTmp; + needSampleState=true; + } + //--- + + //Get max Ions + //-- + //TODO: Forbid zero values - don't do it now, as we previously used this + // for disabling sampling, so some users' XML files will still have this + if(!XMLGetNextElemAttrib(nodePtr,maxIons,"maxions","value")) + return false; + + if(needSampleState) + doSample=maxIons; + + //FIXME: Compatibility hack. User preferences from 3Depict <=0.0.10 + + // could cause == 0 maxIons, causing an assertion error in + // ::refresh() due to no ions. Override this. + // In the future, we should reject this as invalid, however + // it was valid for 3Depict <= 0.0.10 + if(!maxIons) + maxIons=MAX_IONS_LOAD_DEFAULT; + //-- + } + //Retrieve colour + //==== + if(XMLHelpFwdToElem(nodePtr,"colour")) + return false; + + if(!parseXMLColour(nodePtr,r,g,b,a)) + return false; + //==== + + //Retrieve drawing size value + //-- + if(!XMLGetNextElemAttrib(nodePtr,ionSize,"ionsize","value")) + return false; + //check positive or zero + if(ionSize <=0) + return false; + //-- + + + return true; +} + +unsigned int DataLoadFilter::getRefreshBlockMask() const +{ + return 0; +} + +unsigned int DataLoadFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_IONS; +} + +unsigned int DataLoadFilter::getRefreshUseMask() const +{ + return 0; +} + +std::string DataLoadFilter::getErrString(unsigned int code) const +{ + ASSERT(errStr.size()); + return errStr; +} + +void DataLoadFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + +bool DataLoadFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << ""<< endl; + f << tabs(depth+1) << ""<< endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" <" << endl; + f << tabs(depth) << "" << endl; + break; + } + default: + //Shouldn't get here, unhandled format string + ASSERT(false); + return false; + } + + return true; + +} + +bool DataLoadFilter::writePackageState(std::ostream &f, unsigned int format, + const std::vector &valueOverrides, unsigned int depth) const +{ + ASSERT(valueOverrides.size() == 1); + + //Temporarily modify the state of the filter, then call writestate + string tmpIonFilename=ionFilename; + + + //override const -- naughty, but we know what we are doing... + const_cast(this)->ionFilename=valueOverrides[0]; + bool result; + result=writeState(f,format,depth); + + const_cast(this)->ionFilename=tmpIonFilename; + + return result; +} + +void DataLoadFilter::getStateOverrides(std::vector &externalAttribs) const +{ + externalAttribs.push_back(ionFilename); + +} + +bool DataLoadFilter::monitorNeedsRefresh() const +{ + //We can only actually effect an update if the + // filter is enabled (and we actually want to monitor). + // otherwise, we don't need to refresh + if(enabled && wantMonitor) + { + //Check to see that the file exists, if + // not fall back to the cache. + if(!wxFile::Exists(wxStr(ionFilename))) + return cacheOK; + + + size_t sizeVal; + getFilesize(ionFilename.c_str(),sizeVal); + if(sizeVal != monitorSize) + return true; + + return( wxFileModificationTime(wxStr(ionFilename)) + !=monitorTimestamp); + + + } + + + return false; +} + + +#ifdef DEBUG + + +bool posFileTest(); +bool textFileTest(); + + +bool DataLoadFilter::runUnitTests() +{ + if(!posFileTest()) + return false; + + if(!textFileTest()) + return false; + + return true; +} + +bool posFileTest() +{ + //Synthesise data, then *save* it. + + const unsigned int NUM_PTS=133; + vector hits; + hits.resize(NUM_PTS); + for(unsigned int ui=0; uisetCaching(false); + + bool needUp; + TEST(d->setProperty(DATALOAD_KEY_FILE,posName,needUp),"Set prop"); + TEST(d->setProperty(DATALOAD_KEY_SAMPLE,"0",needUp),"Set prop"); + //--------- + + vector streamIn,streamOut; + ProgressData prog; + TEST(!d->refresh(streamIn,streamOut,prog,dummyCallback),"Refresh error code"); + delete d; + + + TEST(streamOut.size() == 1, "Stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "Stream type"); + + TEST(streamOut[0]->getNumBasicObjects() == hits.size(), "Stream count"); + + +#if defined(__LINUX__) || defined(__APPLE__) + //Hackish method to delete file + std::string s; + s=string("rm -f ") + string(posName); + system(s.c_str()); +#endif + + delete streamOut[0]; + return true; +} + +bool textFileTest() +{ + //write some random data + // with a fixed seed value + RandNumGen r; + r.initialise(232635); + const unsigned int NUM_PTS=1000; + + //TODO: do better than this + const char *FILENAME="test-3mdfuneaascn.txt"; + //see if we can open the file for input. If so, it must exist, + //and thus we don't want to overwite it, as it may contain useful data. + std::ifstream inFile(FILENAME); + if(inFile) + { + std::string s; + s="Unwilling to execute file test, will not overwrite file :"; + s+=FILENAME; + s+=". Test is indeterminate"; + WARN(false,s.c_str()); + + return true; + } + + std::ofstream outFile(FILENAME); + + if(!outFile) + { + WARN(false,"Unable to create test output file. Unit test was indeterminate. Requires write access to excution path"); + return true; + } + + vector hitVec; + hitVec.resize(NUM_PTS); + + //Write out the file + outFile << "x y\tz\tValues" << endl; + for(unsigned int ui=0;uisetCaching(false); + + bool needUp; + TEST(d->setProperty(DATALOAD_KEY_FILE,FILENAME,needUp),"Set prop"); + TEST(d->setProperty(DATALOAD_KEY_SAMPLE,"0",needUp),"Set prop"); //load all data + //Load data as text file + TEST(d->setProperty(DATALOAD_KEY_FILETYPE, + AVAILABLE_FILEDATA_TYPES[FILEDATA_TYPE_TEXT],needUp),"Set prop"); + //--------- + + + vector streamIn,streamOut; + ProgressData prog; + TEST(!d->refresh(streamIn,streamOut,prog,dummyCallback),"Refresh error code"); + delete d; + + + TEST(streamOut.size() == 1, "Stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "Stream type"); + + TEST(streamOut[0]->getNumBasicObjects() == NUM_PTS,"Stream count"); + +#if defined(__LINUX__) || defined(__APPLE__) + //Hackish mathod to delete file + std::string s; + s=string("rm -f ") + string(FILENAME); + system(s.c_str()); +#endif + + delete streamOut[0]; + return true; +} + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/dataLoad.h 3depict-0.0.13/src/backend/filters/dataLoad.h --- 3depict-0.0.12/src/backend/filters/dataLoad.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/dataLoad.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,184 @@ +/* + * dataLoad.h - Load data from various file sources + * 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 . +*/ +#ifndef DATALOAD_H +#define DATALOAD_H + +#include "../filter.h" + +#include "../../common/translation.h" + +enum +{ + DATALOAD_FLOAT_FILE, + DATALOAD_TEXT_FILE +}; + +enum +{ + DATALOAD_KEY_FILE, + DATALOAD_KEY_FILETYPE, + DATALOAD_KEY_SAMPLE, + DATALOAD_KEY_SIZE, + DATALOAD_KEY_COLOUR, + DATALOAD_KEY_IONSIZE, + DATALOAD_KEY_ENABLED, + DATALOAD_KEY_VALUELABEL, + DATALOAD_KEY_SELECTED_COLUMN0, + DATALOAD_KEY_SELECTED_COLUMN1, + DATALOAD_KEY_SELECTED_COLUMN2, + DATALOAD_KEY_SELECTED_COLUMN3, + DATALOAD_KEY_NUMBER_OF_COLUMNS, + DATALOAD_KEY_MONITOR +}; + +class DataLoadFilter:public Filter +{ + protected: + //!filename from which the ions are being loaded + std::string ionFilename; + + //!Type of file to open + unsigned int fileType; + + //!Try our best to guess the file type? + bool guessType; + + + //!Whether to randomly sample dataset during load or not + bool doSample; + + //!Maximum number of ions to load, if performing sampling + size_t maxIons; + + //!Default ion colour vars + float r,g,b,a; + + //!Default ion size (view size) + float ionSize; + + //!Number of columns & type of file + unsigned int numColumns; + + static const unsigned int INDEX_LENGTH = 4; + //!index of columns into pos file, if pos data is visualised as a set of float record presented as a table (one line per record) + unsigned int index[INDEX_LENGTH];//x,y,z,value + + //!Is pos load enabled? + bool enabled; + + //!Volume restricted load? + bool volumeRestrict; + + //!volume restriction bounds, not sorted + BoundCube bound; + + //Epoch timestamp for the mointored file. -1 if invalid + time_t monitorTimestamp; + + //File size for monitored file + size_t monitorSize; + + //Do we want to be monitoring + //the timestamp of the file + bool wantMonitor; + + //!string to use in error situation, set during ::refresh + std::string errStr; + + //!String to use to set the value type + std::string valueLabel; + public: + DataLoadFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + //!Set the source string + void setFilename(const char *name); + void setFilename(const std::string &name); + void guessNumColumns(); + + //!Set the filter to either use text or pos as requested, + // this does not require exposing the file parameter key + void setFileMode(unsigned int mode); + + //!Get filter type (returns FILTER_TYPE_DATALOAD) + unsigned int getType() const { return FILTER_TYPE_DATALOAD;}; + + //!Get (approx) number of bytes required for cache + virtual size_t numBytesForCache(size_t nOBjects) const; + + //!Refresh object data + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + void updatePosData(); + + virtual std::string typeString() const { return std::string(TRANS("Pos Data"));} + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty( unsigned int key, const std::string &value, bool &needUpdate); + + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + + //!write an overridden filename version of the state + virtual bool writePackageState(std::ostream &f, unsigned int format, + const std::vector &valueOverrides,unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the block mask for this filter (bitmaks of streams blocked from propagation during ::refresh) + virtual unsigned int getRefreshBlockMask() const; + //!Get the refresh mask for this filter (bitmaks of streams emitted during ::refresh) + virtual unsigned int getRefreshEmitMask() const; + + //!Get the refresh use mask for this filter (bitmaks of streams possibly used during ::refresh) + virtual unsigned int getRefreshUseMask() const; + + //!Pos filter has state overrides + virtual void getStateOverrides(std::vector &overrides) const; + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + + //!Get the label for the chosen value column + std::string getValueLabel(); + + //!Return if we need monitoring or not + virtual bool monitorNeedsRefresh() const; + + //Are we a pure data source - i.e. can function with no input + virtual bool isPureDataSource() const { return true;}; + + //Can we be a useful filter, even if given no input specified by the Use mask? + virtual bool isUsefulAsAppend() const { return true;} + +#ifdef DEBUG + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/externalProgram.cpp 3depict-0.0.13/src/backend/filters/externalProgram.cpp --- 3depict-0.0.12/src/backend/filters/externalProgram.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/externalProgram.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,900 @@ +/* + * externalProgram.cpp - Call out external programs as a datasource/sink + * 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 . +*/ +#include "externalProgram.h" +#include "../../wxcommon.h" + +#include "filterCommon.h" + +#include +#include + +enum +{ + KEY_COMMAND, + KEY_WORKDIR, + KEY_ALWAYSCACHE, + KEY_CLEANUPINPUT +}; + +//!Error codes +enum +{ + COMMANDLINE_FAIL=1, + SETWORKDIR_FAIL, + WRITEPOS_FAIL, + WRITEPLOT_FAIL, + MAKEDIR_FAIL, + PLOTCOLUMNS_FAIL, + READPLOT_FAIL, + READPOS_FAIL, + SUBSTITUTE_FAIL, + COMMAND_FAIL, +}; + +//=== External program filter === +ExternalProgramFilter::ExternalProgramFilter() : alwaysCache(false), + cleanInput(true) +{ + cacheOK=false; + cache=false; +} + +Filter *ExternalProgramFilter::cloneUncached() const +{ + ExternalProgramFilter *p=new ExternalProgramFilter(); + + //Copy the values + p->workingDir=workingDir; + p->commandLine=commandLine; + p->alwaysCache=alwaysCache; + p->cleanInput=cleanInput; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +size_t ExternalProgramFilter::numBytesForCache(size_t nObjects) const +{ + if(alwaysCache) + return 0; + else + return (size_t)-1; //Say we don't know, we are not going to cache anyway. +} + +unsigned int ExternalProgramFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + //use the cached copy if we have it. + if(cacheOK) + { + for(unsigned int ui=0;ui commandLineSplit; + + splitStrsRef(commandLine.c_str(),' ',commandLineSplit); + //Nothing to do + if(commandLineSplit.empty()) + return 0; + + vector ionOutputNames,plotOutputNames; + + //Compute the bounding box of the incoming streams + string s; + wxString tempDir; + if(workingDir.size()) + tempDir=(wxStr(workingDir) +wxT("/inputData")); + else + tempDir=(wxT("inputData")); + + + //Create a temporary dir + if(!wxDirExists(tempDir) ) + { + //Audacity claims that this can return false even on + //success (NoiseRemoval.cpp, line 148). + //I was having problems with this function too; + //so use their workaround + wxMkdir(tempDir); + + if(!wxDirExists(tempDir) ) + return MAKEDIR_FAIL; + + } + + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *i; + i = (const IonStreamData * )(dataIn[ui]); + + if(i->data.empty()) + break; + //Save the data to a file + wxString tmpStr; + + tmpStr=wxFileName::CreateTempFileName(tempDir+ wxT("/pointdata")); + //wxwidgets has no suffix option... annoying. + wxRemoveFile(tmpStr); + + s = stlStr(tmpStr); + s+=".pos"; + if(IonVectorToPos(i->data,s)) + { + //Uh-oh problem. Clean up and exit + return WRITEPOS_FAIL; + } + + ionOutputNames.push_back(s); + break; + } + case STREAM_TYPE_PLOT: + { + const PlotStreamData *i; + i = (const PlotStreamData * )(dataIn[ui]); + + if(i->xyData.empty()) + break; + //Save the data to a file + wxString tmpStr; + + tmpStr=wxFileName::CreateTempFileName(tempDir + wxT("/plot")); + //wxwidgets has no suffix option... annoying. + wxRemoveFile(tmpStr); + s = stlStr(tmpStr); + s+= ".xy"; + if(!writeTextFile(s.c_str(),i->xyData)) + { + //Uh-oh problem. Clean up and exit + return WRITEPLOT_FAIL; + } + + plotOutputNames.push_back(s); + break; + } + default: + break; + } + } + + //Nothing to do. + if(plotOutputNames.empty() && + ionOutputNames.empty()) + return 0; + + + //Construct the command, using substitution + string command; + unsigned int ionOutputPos,plotOutputPos; + ionOutputPos=plotOutputPos=0; + command = commandLineSplit[0]; + for(unsigned int ui=1;uiGetAllFiles(wxStr(workingDir),a,_("*.pos"),wxDIR_FILES); + else + dir->GetAllFiles(wxGetCwd(),a,_("*.pos"),wxDIR_FILES); + + + //read the output files, which is assumed to be any "pos" file + //in the working dir + for(unsigned int ui=0;uiCount(); ui++) + { + wxULongLong size; + size = wxFileName::GetSize((*a)[ui]); + + if( (size !=0) && size!=wxInvalidSize) + { + //Load up the pos file + + string sTmp; + wxString wxTmpStr; + wxTmpStr=(*a)[ui]; + sTmp = stlStr(wxTmpStr); + unsigned int dummy; + IonStreamData *d = new IonStreamData(); + d->parent=this; + //TODO: some kind of secondary file for specification of + //ion attribs? + d->r = 1.0; + d->g=0; + d->b=0; + d->a=1.0; + d->ionSize = 2.0; + + unsigned int index2[] = { + 0, 1, 2, 3 + }; + if(GenericLoadFloatFile(4, 4, index2, d->data,sTmp.c_str(),dummy,dummyCallback)) + return READPOS_FAIL; + + + if(alwaysCache) + { + d->cached=1; + filterOutputs.push_back(d); + } + else + d->cached=0; + getOut.push_back(d); + } + } + + a->Clear(); + if(workingDir.size()) + dir->GetAllFiles(wxStr(workingDir),a,_("*.xy"),wxDIR_FILES); + else + dir->GetAllFiles(wxGetCwd(),a,_("*.xy"),wxDIR_FILES); + + //read the output files, which is assumed to be any "pos" file + //in the working dir + for(unsigned int ui=0;uiCount(); ui++) + { + wxULongLong size; + size = wxFileName::GetSize((*a)[ui]); + + if( (size !=0) && size!=wxInvalidSize) + { + string sTmp; + wxString wxTmpStr; + wxTmpStr=(*a)[ui]; + sTmp = stlStr(wxTmpStr); + + vector > dataVec; + + vector header; + + //Possible delimiters to try when loading file + //try each in turn + const char *delimString ="\t, "; + if(!loadTextData(sTmp.c_str(),dataVec,header,delimString)) + return READPLOT_FAIL; + + //Check that the input has the correct size + for(unsigned int uj=0;ujparent=this; + d->r = 0.0; + d->g=1.0; + d->b=0; + d->a=1.0; + + + //set the title to the filename (trim the .xy extension + //and the working directory name) + string tmpFilename; + tmpFilename=sTmp.substr(workingDir.size(),sTmp.size()- + workingDir.size()-3); + + d->dataLabel=getUserString() + string(":") + onlyFilename(tmpFilename); + + if(applyLabels) + { + + //set the xy-labels to the column headers + d->xLabel=header[uj]; + d->yLabel=header[uj+1]; + } + else + { + d->xLabel="x"; + d->yLabel="y"; + } + + d->xyData.resize(dataVec[uj].size()); + + ASSERT(dataVec[uj].size() == dataVec[uj+1].size()); + for(unsigned int uk=0;ukxyData[uk]=make_pair(dataVec[uj][uk], + dataVec[uj+1][uk]); + } + + if(alwaysCache) + { + d->cached=1; + filterOutputs.push_back(d); + } + else + d->cached=0; + + getOut.push_back(d); + } + } + } + + if(alwaysCache) + cacheOK=true; + + delete dir; + delete a; + + return 0; +} + + +void ExternalProgramFilter::getProperties(FilterPropGroup &propertyList) const +{ + std::string tmpStr; + size_t curGroup=0; + FilterProperty p; + + p.name=TRANS("Command"); + p.data= commandLine; + p.type=PROPERTY_TYPE_STRING; + p.helpText=TRANS("Full command to send to operating system. See manual for escape sequence meanings"); + p.key=KEY_COMMAND; + propertyList.addProperty(p,curGroup); + + p.name=TRANS("Work Dir"); + p.data= workingDir; + p.type=PROPERTY_TYPE_STRING; + p.helpText=TRANS("Directory to run the command in"); + p.key=KEY_WORKDIR; + propertyList.addProperty(p,curGroup); + + + if(cleanInput) + tmpStr="1"; + else + tmpStr="0"; + + p.name=TRANS("Cleanup input"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Erase input files when command completed"); + p.key=KEY_CLEANUPINPUT; + propertyList.addProperty(p,curGroup); + + if(alwaysCache) + tmpStr="1"; + else + tmpStr="0"; + + p.name=TRANS("Cache"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Assume program does not alter its output, unless inputs from 3Depict are altered"); + p.key=KEY_ALWAYSCACHE; + propertyList.addProperty(p,curGroup); + +} + +bool ExternalProgramFilter::setProperty( unsigned int key, + const std::string &value, bool &needUpdate) +{ + needUpdate=false; + switch(key) + { + case KEY_COMMAND: + { + if(commandLine!=value) + { + commandLine=value; + needUpdate=true; + clearCache(); + } + break; + } + case KEY_WORKDIR: + { + if(workingDir!=value) + { + //Check the directory exists + if(!wxDirExists(wxStr(value))) + return false; + + workingDir=value; + needUpdate=true; + clearCache(); + } + break; + } + case KEY_ALWAYSCACHE: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + if(stripped=="1") + alwaysCache=true; + else + { + alwaysCache=false; + + //If we need to generate a cache, do so + //otherwise, trash it + clearCache(); + } + + needUpdate=true; + break; + } + case KEY_CLEANUPINPUT: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + cleanInput=(stripped=="1"); + needUpdate=true; + break; + } + default: + ASSERT(false); + + } + + return true; +} + + +std::string ExternalProgramFilter::getErrString(unsigned int code) const +{ + + switch(code) + { + case COMMANDLINE_FAIL: + return std::string(TRANS("Error processing command line")); + case SETWORKDIR_FAIL: + return std::string(TRANS("Unable to set working directory")); + case WRITEPOS_FAIL: + return std::string(TRANS("Error saving posfile result for external program")); + case WRITEPLOT_FAIL: + return std::string(TRANS("Error saving plot result for externalprogram")); + case MAKEDIR_FAIL: + return std::string(TRANS("Error creating temporary directory")); + case PLOTCOLUMNS_FAIL: + return std::string(TRANS("Detected unusable number of columns in plot")); + case READPLOT_FAIL: + return std::string(TRANS("Unable to parse plot result from external program")); + case READPOS_FAIL: + return std::string(TRANS("Unable to load ions from external program")); + case SUBSTITUTE_FAIL: + return std::string(TRANS("Unable to perform commandline substitution")); + case COMMAND_FAIL: + return std::string(TRANS("Error executing external program")); + default: + //Currently the only error is aborting + return std::string("Bug: write me (externalProgramfilter)."); + } +} + +void ExternalProgramFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + +bool ExternalProgramFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth) << "" << endl; + break; + + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool ExternalProgramFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + + //Retrieve command + if(XMLHelpFwdToElem(nodePtr,"commandline")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); + if(!xmlString) + return false; + commandLine=(char *)xmlString; + xmlFree(xmlString); + + //Retrieve working dir + if(XMLHelpFwdToElem(nodePtr,"workingdir")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); + if(!xmlString) + return false; + workingDir=(char *)xmlString; + xmlFree(xmlString); + + + //get should cache + string tmpStr; + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"alwayscache","value")) + return false; + + if(tmpStr == "1") + alwaysCache=true; + else if(tmpStr== "0") + alwaysCache=false; + else + return false; + + //check readable + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"cleaninput","value")) + return false; + + if(tmpStr == "1") + cleanInput=true; + else if(tmpStr== "0") + cleanInput=false; + else + return false; + + return true; +} + +unsigned int ExternalProgramFilter::getRefreshBlockMask() const +{ + //Absolutely nothing can go through this filter. + return 0; +} + +unsigned int ExternalProgramFilter::getRefreshEmitMask() const +{ + //Can only generate ion streams and plot streams + return STREAM_TYPE_IONS | STREAM_TYPE_PLOT; +} + +unsigned int ExternalProgramFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS | STREAM_TYPE_PLOT; +} + +#ifdef DEBUG +#include + +bool echoTest() +{ + ExternalProgramFilter* f = new ExternalProgramFilter; + f->setCaching(false); + + int errCode; +#if !defined(__WIN32__) && !defined(__WIN64__) + errCode=system("echo testing... > /dev/null"); +#else + errCode=system("echo testing... > NUL"); +#endif + if(errCode) + { + WARN(false,"Unable to perform echo test on this system -- echo missing?"); + return true; + } + + bool needUp; + string s; + + wxString tmpFilename; + tmpFilename=wxFileName::CreateTempFileName(wxT("")); + s = string(" echo test > ") + stlStr(tmpFilename); + TEST(f->setProperty(KEY_COMMAND,s,needUp),"Set prop"); + + //Simulate some data to send to the filter + vector streamIn,streamOut; + ProgressData p; + f->refresh(streamIn,streamOut,p,dummyCallback); + + + s=stlStr(tmpFilename); + ifstream file(s.c_str()); + + TEST(file,"echo retrieval"); + + + wxRemoveFile(tmpFilename); + + delete f; + + return true; +} + +IonStreamData* createTestPosData(unsigned int numPts) +{ + IonStreamData* d= new IonStreamData; + + d->data.resize(numPts); + for(unsigned int ui=0;uidata[ui].setPos(ui,ui,ui); + d->data[ui].setMassToCharge(ui); + } + + return d; +} + +bool posTest() +{ + const unsigned int NUM_PTS=100; + auto_ptr someData; + someData.reset(createTestPosData(NUM_PTS)); + + ExternalProgramFilter* f = new ExternalProgramFilter; + f->setCaching(false); + + bool needUp; + string s; + + wxString tmpFilename,tmpDir; + tmpDir=wxFileName::GetTempDir(); + + +#if defined(__WIN32__) || defined(__WIN64__) + tmpDir=tmpDir + wxT("\\3Depict\\"); + +#else + tmpDir=tmpDir + wxT("/3Depict/"); +#endif + wxMkdir(tmpDir); + + tmpFilename=wxFileName::CreateTempFileName(tmpDir+ wxT("unittest-")); + wxRemoveFile(tmpFilename); + tmpFilename+=wxT(".pos"); + s ="mv \%i " + stlStr(tmpFilename); + + ASSERT(tmpFilename.size()); + + TEST(f->setProperty(KEY_COMMAND,s,needUp),"Set prop"); + TEST(f->setProperty(KEY_WORKDIR,stlStr(tmpDir),needUp),"Set prop"); + //Simulate some data to send to the filter + vector streamIn,streamOut; + streamIn.push_back(someData.get()); + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + + //Should have exactly one stream, which is an ion stream + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + + TEST(streamOut[0]->getNumBasicObjects() ==NUM_PTS,"Number of ions"); + const IonStreamData* out =(IonStreamData*) streamOut[0]; + + for(unsigned int ui=0;uidata.size();ui++) + { + TEST(out->data[ui].getPos() == someData->data[ui].getPos(),"position"); + TEST(out->data[ui].getMassToCharge() == + someData->data[ui].getMassToCharge(),"position"); + } + + + + wxRemoveFile(tmpFilename); + wxRmdir(tmpDir+wxT("inputData")); + wxRmdir(tmpDir); + + delete streamOut[0]; + + delete f; + + return true; +} + + +bool ExternalProgramFilter::runUnitTests() +{ + if(!echoTest()) + return false; + + if(!posTest()) + return false; + + return true; +} + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/externalProgram.h 3depict-0.0.13/src/backend/filters/externalProgram.h --- 3depict-0.0.12/src/backend/filters/externalProgram.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/externalProgram.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * externalProgram.h - Call out external programs as data sources/sinks + * 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 . +*/ +#ifndef EXTERNALPROGRAM_H +#define EXTERNALPROGRAM_H + +#include "../filter.h" +#include "../../common/translation.h" +//!External program filter +class ExternalProgramFilter : public Filter +{ + + //!The command line strings; prior to expansion + std::string commandLine; + + //!Working directory for program + std::string workingDir; + + //!Always cache output from program + bool alwaysCache; + //!Erase generated input files for ext. program after running? + bool cleanInput; + + public: + //!As this launches external programs, this could be misused. + bool canBeHazardous() const {return true;} + + ExternalProgramFilter(); + virtual ~ExternalProgramFilter(){}; + + Filter *cloneUncached() const; + //!Returns cache size as a function fo input + virtual size_t numBytesForCache(size_t nObjects) const; + + //!Returns FILTER_TYPE_EXTERNALPROC + unsigned int getType() const { return FILTER_TYPE_EXTERNALPROC;}; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + virtual std::string typeString() const { return std::string(TRANS("Ext. Program"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types possibly used during ::refresh + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + +#ifdef DEBUG + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/filterCommon.cpp 3depict-0.0.13/src/backend/filters/filterCommon.cpp --- 3depict-0.0.12/src/backend/filters/filterCommon.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/filterCommon.cpp 2013-03-22 21:31:09.000000000 +0000 @@ -0,0 +1,662 @@ +/* + * filterCommon.cpp - Helper routines for filter classes + * 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 . +*/ + +#include "filterCommon.h" + + + + +//TODO: Work out where the payoff for this is +//grab size when doing convex hull calculations +const unsigned int HULL_GRAB_SIZE=4096; + +using std::ostream; +using std::vector; +using std::endl; +using std::string; + +//Wrapper for qhull single-pass run +unsigned int doHull(unsigned int bufferSize, double *buffer, + vector &resHull, Point3D &midPoint); + +void writeVectorsXML(ostream &f,const char *containerName, + const vector &vectorParams, unsigned int depth) +{ + f << tabs(depth+1) << "<" << containerName << ">" << endl; + for(unsigned int ui=0; ui" << endl; + } + f << tabs(depth+1) << "" << endl; +} + +void writeIonsEnabledXML(ostream &f, const char *containerName, + const vector &enabledState, const vector &names, + unsigned int depth) +{ + f << tabs(depth) << "<" << containerName << ">" << endl; + for(size_t ui=0;ui" << std::endl; + } + f << tabs(depth) << "" << endl; +} + +bool readVectorsXML(xmlNodePtr nodePtr, std::vector &vectorParams) +{ + nodePtr=nodePtr->xmlChildrenNode; + vectorParams.clear(); + + while(!XMLHelpFwdToElem(nodePtr,"point3d")) + { + std::string tmpStr; + xmlChar* xmlString; + float x,y,z; + //--Get X value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(x,tmpStr)) + return false; + + //--Get Z value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(y,tmpStr)) + return false; + + //--Get Y value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(z,tmpStr)) + return false; + + vectorParams.push_back(Point3D(x,y,z)); + } + + return true; +} + +bool parseXMLColour(xmlNodePtr &nodePtr, float &r,float&g,float&b,float&a) +{ + xmlChar *xmlString; + std::string tmpStr; + //--red-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"r"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(r,tmpStr)) + return false; + + //disallow negative or values gt 1. + if(r < 0.0f || r > 1.0f) + return false; + xmlFree(xmlString); + + + //--green-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"g"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(g,tmpStr)) + { + xmlFree(xmlString); + return false; + } + + xmlFree(xmlString); + + //disallow negative or values gt 1. + if(g < 0.0f || g > 1.0f) + return false; + + //--blue-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"b"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(b,tmpStr)) + { + xmlFree(xmlString); + return false; + } + xmlFree(xmlString); + + //disallow negative or values gt 1. + if(b < 0.0f || b > 1.0f) + return false; + + //--Alpha-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"a"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(a,tmpStr)) + { + xmlFree(xmlString); + return false; + } + xmlFree(xmlString); + + //disallow negative or values gt 1. + if(a < 0.0f || a > 1.0f) + return false; + + return true; +} + +const RangeFile *getRangeFile(const std::vector &dataIn) +{ + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + return ((const RangeStreamData*)(dataIn[ui]))->rangeFile; + } + + ASSERT(false); +} + +unsigned int getIonstreamIonID(const IonStreamData *d, const RangeFile *r) +{ + if(d->data.empty()) + return (unsigned int)-1; + + unsigned int tentativeRange; + + tentativeRange=r->getIonID(d->data[0].getMassToCharge()); + + + //TODO: Currently, we have no choice but to brute force it. + //In the future, it might be worth storing some data inside the IonStreamData itself + //and to use that first, rather than try to brute force the result +#ifdef _OPENMP + bool spin=false; + #pragma omp parallel for shared(spin) + for(size_t ui=1;uidata.size();ui++) + { + if(spin) + continue; + if(r->getIonID(d->data[ui].getMassToCharge()) !=tentativeRange) + spin=true; + } + + //Not a range + if(spin) + return (unsigned int)-1; + +#else + for(size_t ui=1;uidata.size();ui++) + { + if(r->getIonID(d->data[ui].getMassToCharge()) !=tentativeRange) + return (unsigned int)-1; + } +#endif + + return tentativeRange; +} + +//!Extend a point data vector using some ion data +unsigned int extendPointVector(std::vector &dest, const std::vector &vIonData, + bool (*callback)(bool),unsigned int &progress, size_t offset) +{ + unsigned int curProg=NUM_CALLBACK; + unsigned int n =offset; +#ifdef _OPENMP + //Parallel version + bool spin=false; + #pragma omp parallel for shared(spin) + for(size_t ui=0;ui &data, unsigned int *progress, + bool (*callback)(bool),std::vector &curHull, bool freeHull) +{ + + size_t numPts; + numPts=numElements(data,STREAM_TYPE_IONS); + //Easy case of no data + if(numPts < 4) + return 0; + + double *buffer; + double *tmp; + //Use malloc so we can re-alloc + buffer =(double*) malloc(HULL_GRAB_SIZE*3*sizeof(double)); + + if(!buffer) + return HULL_ERR_NO_MEM; + + size_t bufferOffset=0; + + //Do the convex hull in steps for two reasons + // 1) qhull chokes on large data + // 2) we need to run the callback every now and again, so we have to + // work in batches. + Point3D midPoint; + float maxSqrDist=-1; + bool doneHull=false; + size_t progressReduce=PROGRESS_REDUCE; + size_t n=0; + for(size_t ui=0; uigetStreamType() != STREAM_TYPE_IONS) + continue; + + const IonStreamData* ions=(const IonStreamData*)data[ui]; + + for(size_t uj=0; ujdata.size(); uj++) + { //Do contained-in-sphere check + if(!curHull.size() || midPoint.sqrDist(ions->data[uj].getPos())>= maxSqrDist) + { + //Copy point data into hull buffer + buffer[3*bufferOffset]=ions->data[uj].getPos()[0]; + buffer[3*bufferOffset+1]=ions->data[uj].getPos()[1]; + buffer[3*bufferOffset+2]=ions->data[uj].getPos()[2]; + bufferOffset++; + + //If we have hit the hull grab size, perform a hull + + if(bufferOffset == HULL_GRAB_SIZE) + { + bufferOffset+=curHull.size(); + tmp=(double*)realloc(buffer, + 3*bufferOffset*sizeof(double)); + if(!tmp) + { + free(buffer); + if(doneHull) + FREE_QHULL(); + + return HULL_ERR_NO_MEM; + } + + buffer=tmp; + //Copy in the old hull + for(size_t uk=0; uk::max(); + for(size_t ui=0; ui 4) + { + //Re-allocate the buffer to determine the last hull size + tmp=(double*)realloc(buffer, + 3*(bufferOffset+curHull.size())*sizeof(double)); + if(!tmp) + { + free(buffer); + return HULL_ERR_NO_MEM; + } + buffer=tmp; + + #pragma omp parallel for + for(unsigned int ui=0; ui &data, unsigned int *progress, + bool (*callback)(bool),std::vector &curHull, bool freeHull) +{ + + //Easy case of no data + if(data.size()< 4) + return 0; + + double *buffer; + double *tmp; + //Use malloc so we can re-alloc + buffer =(double*) malloc(HULL_GRAB_SIZE*3*sizeof(double)); + + if(!buffer) + return HULL_ERR_NO_MEM; + + size_t bufferOffset=0; + + //Do the convex hull in steps for two reasons + // 1) qhull chokes on large data + // 2) we need to run the callback every now and again, so we have to + // work in batches. + Point3D midPoint; + float maxSqrDist=-1; + bool doneHull=false; + + + size_t progressReduce=PROGRESS_REDUCE; + + for(size_t uj=0; uj= maxSqrDist) + { + + //Copy point data into hull buffer + buffer[3*bufferOffset]=data[uj][0]; + buffer[3*bufferOffset+1]=data[uj][1]; + buffer[3*bufferOffset+2]=data[uj][2]; + bufferOffset++; + + //If we have hit the hull grab size, perform a hull + + if(bufferOffset == HULL_GRAB_SIZE) + { + bufferOffset+=curHull.size(); + tmp=(double*)realloc(buffer, + 3*bufferOffset*sizeof(double)); + if(!tmp) + { + free(buffer); + if(doneHull) + FREE_QHULL(); + + return HULL_ERR_NO_MEM; + } + + buffer=tmp; + //Copy in the old hull + for(size_t uk=0; uk::max(); + for(size_t ui=0; ui 4) + { + //Re-allocate the buffer to determine the last hull size + tmp=(double*)realloc(buffer, + 3*(bufferOffset+curHull.size())*sizeof(double)); + if(!tmp) + { + free(buffer); + return HULL_ERR_NO_MEM; + } + buffer=tmp; + + #pragma omp parallel for + for(unsigned int ui=0; ui &resHull, Point3D &midPoint) +{ + const int dim=3; + //Now compute the new hull + //Generate the convex hull + //(result is stored in qh's globals :( ) + //note that the input is "joggled" to + //ensure simplicial facet generation + + qh_new_qhull( dim, + bufferSize, + buffer, + false, + (char *)"qhull QJ", //Joggle the output, such that only simplical facets are generated + NULL, + NULL); + + unsigned int numPoints=0; + //count points + //-- + //OKay, whilst this may look like invalid syntax, + //qh is actually a macro from qhull + //that creates qh. or qh-> as needed + vertexT *vertex = qh vertex_list; + while(vertex != qh vertex_tail) + { + vertex = vertex->next; + numPoints++; + } + //-- + + //store points in vector + //-- + vertex= qh vertex_list; + try + { + resHull.resize(numPoints); + } + catch(std::bad_alloc) + { + free(buffer); + return HULL_ERR_NO_MEM; + } + //-- + + //Compute mean point + //-- + int curPt=0; + midPoint=Point3D(0,0,0); + while(vertex != qh vertex_tail) + { + resHull[curPt]=Point3D(vertex->point[0], + vertex->point[1], + vertex->point[2]); + midPoint+=resHull[curPt]; + curPt++; + vertex = vertex->next; + } + midPoint*=1.0f/(float)numPoints; + //-- + + return 0; +} diff -Nru 3depict-0.0.12/src/backend/filters/filterCommon.h 3depict-0.0.13/src/backend/filters/filterCommon.h --- 3depict-0.0.12/src/backend/filters/filterCommon.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/filterCommon.h 2013-03-22 19:56:07.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * filterCommon.h - Helper routines for filter classes + * 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 . +*/ + +#ifndef FILTERCOMMON_H +#define FILTERCOMMON_H + +#include "../filter.h" + +#include "common/stringFuncs.h" +#include "common/xmlHelper.h" + +#include "backend/APT/APTClasses.h" +#include "backend/APT/APTRanges.h" + +//QHull library +#ifdef __POWERPC__ + #pragma push_macro("__POWERPC__") + #define __POWERPC__ 1 +#endif +extern "C" +{ + #include +} +#ifdef __POWERPC__ + #pragma pop_macro("__POWERPC__") +#endif +#define FREE_QHULL() { qh_freeqhull(!qh_ALL); int curlong, totlong; \ + qh_memfreeshort(&curlong, &totlong);} + + +enum +{ + HULL_ERR_NO_MEM=1, + HULL_ERR_USER_ABORT, + HULL_ERR_ENUM_END +}; + +//serialise 3D std::vectors to specified output stream in XML format +void writeVectorsXML(std::ostream &f, const char *containerName, + const std::vector &vectorParams, unsigned int depth); + +//Serialise out "enabled" ions as XML +void writeIonsEnabledXML(std::ostream &f, const char *containerName, + const std::vector &enabledState, const std::vector &names, + unsigned int depth); + +//serialise 3D scalars to specified output stream in XML format +// - depth is tab indentation depth +// - container name for : (newline) +template +void writeScalarsXML(std::ostream &f, const char *containerName, + const std::vector &scalarParams, unsigned int depth) +{ + f << tabs(depth) << "<" << containerName << ">" << std::endl; + for(unsigned int ui=0; ui" << std::endl; + + f << tabs(depth) << "" << std::endl; +} + +//Nodeptr must be pointing at container node +template +bool readScalarsXML(xmlNodePtr nodePtr,std::vector &scalarParams) +{ + std::string tmpStr; + nodePtr=nodePtr->xmlChildrenNode; + + scalarParams.clear(); + while(!XMLHelpFwdToElem(nodePtr,"scalar")) + { + xmlChar *xmlString; + T v; + //Get value + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(v,tmpStr)) + return false; + scalarParams.push_back(v); + } + return true; +} + +//serialise 3D std::vectors to specified output stream in XML format +bool readVectorsXML(xmlNodePtr nodePtr, + std::vector &vectorParams); + + +//Parse a "colour" node, extracting rgba data +bool parseXMLColour(xmlNodePtr &nodePtr, + float &r, float&g, float&b, float&a); + +//Returns the ion stream's range ID from the rangefile, if and only if it every ion in input +// is ranged tht way. Otherwise returns -1. +unsigned int getIonstreamIonID(const IonStreamData *d, const RangeFile *r); + +//!Extend a point data vector using some ion data +unsigned int extendPointVector(std::vector &dest, const std::vector &vIonData, + bool (*callback)(bool),unsigned int &progress, size_t offset); + +const RangeFile *getRangeFile(const std::vector &dataIn); + +//Compute the convex hull of a set of input points from fiilterstream data +unsigned int computeConvexHull(const std::vector &data, + unsigned int *progress, bool (*callback)(bool), + std::vector &hullPts, bool freeHull=true); +//Compute the convex hull of a set of input points +unsigned int computeConvexHull(const std::vector &data, + unsigned int *progress, bool (*callback)(bool), + std::vector &hullPts, bool freeHull=true); +#endif diff -Nru 3depict-0.0.12/src/backend/filters/geometryHelpers.cpp 3depict-0.0.13/src/backend/filters/geometryHelpers.cpp --- 3depict-0.0.12/src/backend/filters/geometryHelpers.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/geometryHelpers.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,480 @@ +/* + * geometryHelpers.cpp - Various spatial geometry operators for point clouds + * 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 . +*/ + + +#include "geometryHelpers.h" +#ifdef _OPENMP +#include +#endif + +const size_t DEFAULT_NUM_CALLBACK=5000; + +//These numbers have not been optimised. On a 2CPU system, I cannot find +// a case where the // option is outrun by the linear one, over 3 averages +//--- +//Minimum number of input points before we will do reserve testing +const size_t MIN_SAMPLE_TEST = 1000; +//Minimim number of input points before we will engage a parallel algorithm +const size_t MIN_PARALLELISE = 20000; +//--- + +CropHelper::CropHelper(bool (*callback)(bool), unsigned int *p, + size_t totalData,size_t filterMode, + vector &vectors, vector &scalars) +{ + algorithm=filterMode; + curProgCount=0; + mapMax=0; + invertedClip=false; + + switch(algorithm) + { + case CROP_SPHERE_OUTSIDE: + invertedClip=true; + case CROP_SPHERE_INSIDE: + { + ASSERT(vectors.size() == 1); + ASSERT(scalars.size() == 1); + ASSERT(scalars[0] >= 0.0f); + + + fA=scalars[0]*scalars[0]; + fB=scalars[0]; + pA=vectors[0]; + break; + } + case CROP_PLANE_BACK: + invertedClip=true; + case CROP_PLANE_FRONT: + { + ASSERT(vectors.size() == 2); + ASSERT(scalars.size() == 0); + + pA=vectors[0]; + pB=vectors[1]; + break; + } + case CROP_CYLINDER_OUTSIDE: + invertedClip=true; + case CROP_CYLINDER_INSIDE: + { + ASSERT(vectors.size() == 2); + ASSERT(scalars.size() == 1); + + setupCylinder(vectors[0],scalars[0],vectors[1]); + break; + } + case CROP_AAB_OUTSIDE: + invertedClip=true; + case CROP_AAB_INSIDE: + { + ASSERT(vectors.size() ==2); + ASSERT(scalars.size() == 0); + + pA=vectors[0]-vectors[1]; + pB=vectors[0]+vectors[1]; + break; + } + + default: + ASSERT(false); + } + + setAlgorithm(); + + + numCallback=DEFAULT_NUM_CALLBACK; + callbackFunc=callback; + progressPtr=p; + totalDataCount=totalData; +} + + +void CropHelper::setAlgorithm() +{ + mapFunc=0; + + //Assign the desired member function + switch(algorithm) + { + case CROP_SPHERE_OUTSIDE: + case CROP_SPHERE_INSIDE: + cropFunc=&CropHelper::filterSphereInside; + mapFunc=&CropHelper::mapSphereInside; + break; + case CROP_PLANE_FRONT: + case CROP_PLANE_BACK: + cropFunc=&CropHelper::filterPlaneFront; + break; + case CROP_CYLINDER_INSIDE: + case CROP_CYLINDER_OUTSIDE: + cropFunc=&CropHelper::filterCylinderInside; + mapFunc=&CropHelper::mapCylinderInside; + break; + case CROP_AAB_INSIDE: + case CROP_AAB_OUTSIDE: + cropFunc=&CropHelper::filterBoxInside; + break; + default: + ASSERT(false); + } +} + +unsigned int CropHelper::runFilter(const vector &dataIn, + vector &dataOut ) +{ + + RandNumGen rng; + rng.initTimer(); + + float allocHint=0; + //If we have enough input data, try sampling + // the input randomly to test if we can + // pre-allocate enough space for output data + if(dataIn.size() > MIN_SAMPLE_TEST) + { + const size_t SAMPLE_SIZE=30; + + vector samples; + unsigned int dummy; + randomDigitSelection(samples,dataIn.size(),rng, + SAMPLE_SIZE,dummy, dummyCallback); + + size_t tally=0; + for(size_t ui=0;ui*cropFunc)(dataIn[samples[ui]].getPosRef())) ^ invertedClip) + tally++; + } + + allocHint = (float)tally/(float)SAMPLE_SIZE; + } + + +#ifndef _OPENMP + return runFilterLinear(dataIn,dataOut,allocHint); +#else + if(dataIn.size() < MIN_PARALLELISE || rng.genUniformDev() < 0.5f) + return runFilterLinear(dataIn,dataOut,allocHint); + else + { + return runFilterParallel(dataIn,dataOut,allocHint); + } +#endif +} + +unsigned int CropHelper::runFilterLinear(const vector &dataIn, + vector &dataOut,float allocHint ) +{ + if(allocHint > 0.0f) + dataOut.reserve((unsigned int) ( (float)dataIn.size()*allocHint)); + + size_t &n=curProgCount; + size_t curProg=0; + //Run the data filtering using a single threaded algorithm + // copying to output + if(!invertedClip) + { + for(size_t ui=0; ui*cropFunc)(dataIn[ui].getPosRef()))) + dataOut.push_back(dataIn[ui]); + + //update progress every CALLBACK ions + if(!curProg--) + { + n+=numCallback; + *progressPtr= (unsigned int)((float)(n)/((float)totalDataCount)*100.0f); + curProg=numCallback; + + if(!(*callbackFunc)(false)) + return ERR_CROP_CALLBACK_FAIL; + } + } + + } + else + { + for(size_t ui=0; ui*cropFunc)(dataIn[ui].getPosRef()))) + dataOut.push_back(dataIn[ui]); + + //update progress every CALLBACK ions + if(!curProg--) + { + n+=numCallback; + *progressPtr= (unsigned int)((float)(n)/((float)totalDataCount)*100.0f); + curProg=numCallback; + + if(!(*callbackFunc)(false)) + return ERR_CROP_CALLBACK_FAIL; + } + } + } + + return 0; +} + +unsigned int CropHelper::runFilterParallel(const vector &dataIn, + vector &dataOut, float allocHint ) +{ +#ifdef _OPENMP + + size_t &n=curProgCount; + size_t curProg=0; + + //Create a vector of indices for which + // points successfully passed the test + size_t nThreads=omp_get_max_threads(); + vector inside[nThreads]; + + if(allocHint > 0.0f) + { + for(size_t ui=0;ui*cropFunc)(dataIn[ui].getPosRef())) ^ invertedClip) + inside[omp_get_thread_num()].push_back(ui); + + //update progress every CALLBACK ions + if(!curProg--) + { +#pragma omp critical + { + n+=numCallback; + *progressPtr= (unsigned int)((float)(n)/((float)totalDataCount)*100.0f); + if(!(*callbackFunc)(false)) + spin=true; + } + curProg=numCallback; + } + } + + if(spin) + return ERR_CROP_CALLBACK_FAIL; + + //map the successful ions into a single output block + // -- + vector offsets; + offsets.resize(nThreads); + size_t totalOut=0; + for(size_t ui=0;ui 0.0f); +} + +bool CropHelper::filterBoxInside(const Point3D &testPt) const +{ + return (pA[0] < testPt[0] && pA[1] < testPt[1] && pA[2] < testPt[2] )&& + (pB[0] > testPt[0] && pB[1] > testPt[1] && pB[2] > testPt[2] ) ; +} + + +bool CropHelper::filterCylinderInside(const Point3D &testPt) const +{ + + //pA - cylinder origin + //fA - cylinder half length (origin to end, along axis) + //fB - cylinder sqr radius + //qA - rotation quaternion + Point3D ptmp; + if(nearAxis) + { + ptmp=testPt-pA; + + return (ptmp[2] < fA && ptmp[2] > -fA && + ptmp[0]*ptmp[0]+ptmp[1]*ptmp[1] < fB); + + } + else + { + Point3f p; + //Translate to get position w respect to cylinder centre + ptmp=testPt-pA; + p.fx=ptmp[0]; + p.fy=ptmp[1]; + p.fz=ptmp[2]; + //rotate ion position into cylindrical coordinates + quat_rot_apply_quat(&p,&qA); + + //Check inside upper and lower bound of cylinder + // and check inside cylinder radius + return (p.fz < fA && p.fz > -fA && + p.fx*p.fx+p.fy*p.fy < fB); + } +} + + +unsigned int CropHelper::mapSphereInside(const Point3D &testPt) const +{ + float radius; + radius = sqrt(testPt.sqrDist(pA)); + + if(radius <=fB) + return (unsigned int) (mapMax*(radius/fB)); + else + return -1; +} + +unsigned int CropHelper::mapCylinderInside( const Point3D &testPt) const +{ + + //pA - cylinder origin + //fA - cylinder half length (origin to end, along axis) + //fB - cylinder sqr radius + //qA - rotation quaternion + Point3D ptmp; + float fZ; + if(nearAxis) + { + ptmp=testPt-pA; + + if(!(ptmp[2] < fA && ptmp[2] > -fA && + ptmp[0]*ptmp[0]+ptmp[1]*ptmp[1] < fB) ) + return (unsigned int)-1; + else + fZ=ptmp[2]; + } + else + { + Point3f p; + //Translate to get position w respect to cylinder centre + ptmp=testPt-pA; + p.fx=ptmp[0]; + p.fy=ptmp[1]; + p.fz=ptmp[2]; + //rotate ion position into cylindrical coordinates + quat_rot_apply_quat(&p,&qA); + + //Check inside upper and lower bound of cylinder + // and check inside cylinder radius + if(!(p.fz < fA && p.fz > -fA && + p.fx*p.fx+p.fy*p.fy < fB)) + return (unsigned int)-1; + + fZ=p.fz; + } + + return (unsigned int)(((fZ+fA)/(2.0*fA))*(float)mapMax); + +} + +//Direction is the axis along the full length of the cylinder +void CropHelper::setupCylinder(Point3D origin,float radius, Point3D direction) +{ + ASSERT(direction.sqrMag() > sqrt(std::numeric_limits::epsilon())); + ASSERT(radius > 0.0f); + + pA=origin; + //cylinder half length + fA=sqrt(direction.sqrMag())/2.0f; + //cylinder square radius + fB=radius*radius; + + Point3D zDir(0.0f,0.0f,1.0f); + direction.normalise(); + + float angle = zDir.angle(direction); + //Check that we actually need to rotate, to avoid numerical singularity + //when cylinder axis is too close to (or is) z-axis + if(angle > sqrt(std::numeric_limits::epsilon()) + && angle < M_PI - sqrt(std::numeric_limits::epsilon())) + { + //Cross product desired direction with + //zDirection to produce rotation vector, that when applied + // moves us from actual cylinder coordinates to normal cylindrical coordinates + + //bastardise the Z direction to become our rotation + // axis that brings us back to Z. + zDir = zDir.crossProd(direction); + zDir.normalise(); + + Point3f rotVec; + rotVec.fx=zDir[0]; + rotVec.fy=zDir[1]; + rotVec.fz=zDir[2]; + + //Generate the rotating quaternions + quat_get_rot_quat(&rotVec,-angle,&qA); + nearAxis=false; + + } + else + { + //Too close to the Z-axis, rotation vector is unable + //to be stably computed, and we don't need to rotate anyway + nearAxis=true; + } +} + +unsigned int CropHelper::mapIon1D(const IonHit &ionIn) const +{ + ASSERT(!invertedClip); + ASSERT(mapFunc); + ASSERT(mapMax); + //return the 1D mapping for the ion + return (this->*mapFunc)(ionIn.getPosRef()); +} + +void CropHelper::setFilterMode(size_t filterMode) +{ + ASSERT(filterMode < CROP_ENUM_END); + algorithm=filterMode; + setAlgorithm(); +} + + diff -Nru 3depict-0.0.12/src/backend/filters/geometryHelpers.h 3depict-0.0.13/src/backend/filters/geometryHelpers.h --- 3depict-0.0.12/src/backend/filters/geometryHelpers.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/geometryHelpers.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,187 @@ +/* + * geometryHelpers.h - 3D Geometric operations helper classes + * 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 . +*/ +#ifndef GEOMETRYHELPER_H +#define GEOMETRYHELPER_H + + +#include "../APT/APTClasses.h" + + +enum +{ + CROP_SPHERE_INSIDE, + CROP_SPHERE_OUTSIDE, + CROP_PLANE_FRONT, + CROP_PLANE_BACK, + CROP_CYLINDER_INSIDE, + CROP_CYLINDER_OUTSIDE, + CROP_AAB_OUTSIDE, + CROP_AAB_INSIDE, + CROP_ENUM_END +}; + + +enum +{ + ERR_CROP_CALLBACK_FAIL=1, +}; + +class CropHelper; + +//Type declaration for pointer to constant member function. +// typename is in the middle of the declaration (i.e. "CropFuncPtr") +typedef bool (CropHelper::* CropFuncPtr)(const Point3D &p) const; +typedef unsigned int (CropHelper::* MapFuncPtr)(const Point3D &p) const; + + + + +//Assistance class for helping cropping +// see the end of this file (.h) for +// mathematical description of each primitve +class CropHelper +{ + private: + //Filter parameters + // ---- + size_t algorithm; + + //Geometric parameters, whose meaning is determined + // by the choice of geometric algorithm + Point3D pA,pB; //3D vector params + float fA,fB; //scalar params + Quaternion qA ; //rotation quaternion + bool nearAxis; //true if rotation is near-zaxis (ie rotation doesn't need ot be done) + bool invertedClip; + + size_t mapMax; //Mapping maxima. + + + // -- + + //Helper values + //--- + //Algorithm to use + CropFuncPtr cropFunc; + MapFuncPtr mapFunc; + + size_t curProgCount; + size_t totalDataCount; + unsigned int *progressPtr; + + bool (*callbackFunc)(bool); + size_t numCallback; + //-- + + + //Various testing point containment against primitive + // functions + //---- + //PA - Cylinder origin + //PB - Cylinder 1/2 axis vector + //fA - Cylinder radius + bool filterCylinderInside(const Point3D &p) const; + + //returns true if point p is wholly inside sphere + //PA - sphere origin + //fA - square of sphere radius + bool filterSphereInside(const Point3D &p) const; + + //Returns true if point p is in front of the plane + //pA - plane origin + //pB - plane normal + bool filterPlaneFront(const Point3D &p) const; + + //returns true if the point is inside the box + //pA - Lower point of box + //pB - upper point of box + bool filterBoxInside(const Point3D &testPt) const; + //---- + + //Mapping functions. returns 0 -> mapMax + unsigned int mapCylinderInside(const Point3D &p) const; + + unsigned int mapSphereInside(const Point3D &p) const; + + + //Initialise the data variables for the specified cylinder + void setupCylinder(Point3D origin, + float radius,Point3D direction); + + //intialise the function pointer for the chosen algorithm + void setAlgorithm(); + + + //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 &dataIn, + vector &dataOut,float allocHint); + + //Run the input filtering in parallel (multi CPU) mode + unsigned int runFilterParallel(const vector &dataIn, + vector &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 &vectors, vector &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 &dataIn, + vector &dataOut); + + + void setMapMaxima(size_t 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; + + //Choose the cropping mode for the filter + void setFilterMode(size_t filterMode); + +}; + + +//Primitive Descriptions: What you need to pass in +//--- + +//Sphere Primitive: +// Vectors +// 0 - Origin +// Scalars +// 0 - Radius + +//Cylinder Primitive +// Vectors +// 0 - Origin +// 1 - Axis : This is the distance from one end of the cylinder +// to the other, ie from the centre of one circle +// end-cap to the other +// Scalars +// 0 - radius + + + + +//--- +#endif diff -Nru 3depict-0.0.12/src/backend/filters/ionClip.cpp 3depict-0.0.13/src/backend/filters/ionClip.cpp --- 3depict-0.0.12/src/backend/filters/ionClip.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionClip.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1388 @@ +/* + * ionClip.cpp -3Depict filter to perform clipping of 3D point clouds + * 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 . +*/ +#include "ionClip.h" + + +#include "geometryHelpers.h" +#include "filterCommon.h" + +#include + + +//!Error codes +enum +{ + CALLBACK_FAIL=1, + BAD_ALLOC, +}; + +//!Possible primitive types for ion clipping +enum +{ + PRIMITIVE_SPHERE, + PRIMITIVE_PLANE, + PRIMITIVE_CYLINDER, + PRIMITIVE_AAB, //Axis aligned box + + PRIMITIVE_END //Not actually a primitive, just end of enum +}; + +enum { + KEY_ORIGIN=1, + KEY_PRIMITIVE_TYPE, + KEY_RADIUS, + KEY_PRIMITIVE_SHOW, + KEY_PRIMITIVE_INVERTCLIP, + KEY_NORMAL, + KEY_CORNER, + KEY_AXIS_LOCKMAG, +}; + + + +const char *PRIMITIVE_NAMES[] = { + NTRANS("Sphere"), + NTRANS("Plane"), + NTRANS("Cylinder"), + NTRANS("Aligned box") + }; + + + +unsigned int primitiveID(const std::string &str) +{ + for(unsigned int ui=0;uiprimitiveType=primitiveType; + p->invertedClip=invertedClip; + p->showPrimitive=showPrimitive; + p->vectorParams.resize(vectorParams.size()); + p->scalarParams.resize(scalarParams.size()); + + std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin()); + std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin()); + + p->lockAxisMag = lockAxisMag; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + + return p; +} + +//!Get approx number of bytes for caching output +size_t IonClipFilter::numBytesForCache(size_t nObjects) const +{ + //Without full processing, we cannot tell, so provide upper estimate. + return nObjects*IONDATA_SIZE; +} + +//!update filter +unsigned int IonClipFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, + bool (*callback)(bool)) +{ + ASSERT(vectorParams.size() || scalarParams.size()); + //Clear selection devices, first deleting any we have + clearDevices(); + + if(showPrimitive) + { + //TODO: This is a near-copy of compositionProfile.cpp - refactor + //construct a new primitive, do not cache + DrawStreamData *drawData=new DrawStreamData; + drawData->parent =this; + switch(primitiveType) + { + case PRIMITIVE_SPHERE: + { + //Add drawable components + DrawSphere *dS = new DrawSphere; + dS->setOrigin(vectorParams[0]); + dS->setRadius(scalarParams[0]); + //FIXME: Alpha blending is all screwed up. May require more + //advanced drawing in scene. (front-back drawing). + //I have set alpha=1 for now. + dS->setColour(0.5,0.5,0.5,1.0); + dS->setLatSegments(40); + dS->setLongSegments(40); + dS->wantsLight=true; + drawData->drawables.push_back(dS); + + //Set up selection "device" for user interaction + //Note the order of s->addBinding is critical, + //as bindings are selected by first match. + //==== + //The object is selectable + dS->canSelect=true; + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding b[3]; + + //Apple doesn't have right click, so we need + //to hook up an additional system for them. + //Don't use ifdefs, as this would be useful for + //normal laptops and the like. + b[0].setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_SPHERE_BIND_ORIGIN, + BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); + b[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b[0]); + + //Bind the drawable object to the properties we wish + //to be able to modify + b[1].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_RADIUS, + BINDING_SPHERE_RADIUS,dS->getRadius(),dS); + b[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + b[1].setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(b[1]); + + b[2].setBinding(SELECT_BUTTON_RIGHT,0,DRAW_SPHERE_BIND_ORIGIN, + BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); + b[2].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b[2]); + + devices.push_back(s); + //===== + break; + } + case PRIMITIVE_PLANE: + { + const float drawScale=10.0f; + //Origin + normal + ASSERT(vectorParams.size() == 2); + + //Add drawable components + DrawSphere *dS = new DrawSphere; + dS->setOrigin(vectorParams[0]); + dS->setRadius(drawScale/10); + dS->setColour(0.5,0.5,0.5,1.0); + dS->setLatSegments(40); + dS->setLongSegments(40); + dS->wantsLight=true; + drawData->drawables.push_back(dS); + + DrawVector *dV = new DrawVector; + dV->setOrigin(vectorParams[0]); + dV->setVector(vectorParams[1]*drawScale); + dV->wantsLight=true; + drawData->drawables.push_back(dV); + + //Set up selection "device" for user interaction + //==== + //The object is selectable + dS->canSelect=true; + dV->canSelect=true; + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding b[2]; + //Bind the drawable object to the properties we wish + //to be able to modify + + //Bind orientation to vector left click + b[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_VECTOR_BIND_ORIENTATION, + BINDING_PLANE_DIRECTION, dV->getVector(),dV); + b[0].setInteractionMode(BIND_MODE_POINT3D_ROTATE); + b[0].setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(b[0]); + + //Bind translation to sphere left click + b[1].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, + BINDING_PLANE_ORIGIN,dS->getOrigin(),dS); + b[1].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b[1]); + + + devices.push_back(s); + //===== + break; + } + case PRIMITIVE_CYLINDER: + { + //Origin + normal + ASSERT(vectorParams.size() == 2); + //Add drawable components + DrawCylinder *dC = new DrawCylinder; + dC->setOrigin(vectorParams[0]); + dC->setRadius(scalarParams[0]); + dC->setColour(0.5,0.5,0.5,1.0); + dC->setSlices(40); + dC->setLength(sqrt(vectorParams[1].sqrMag())); + dC->setDirection(vectorParams[1]); + dC->wantsLight=true; + drawData->drawables.push_back(dC); + + //Set up selection "device" for user interaction + //==== + //The object is selectable + dC->canSelect=true; + //Start and end radii must be the same (not a + //tapered cylinder) + dC->lockRadii(); + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding b; + //Bind the drawable object to the properties we wish + //to be able to modify + + //Bind left + command button to move + b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_CYLINDER_BIND_ORIGIN, + BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + //Bind left + shift to change orientation + b.setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_CYLINDER_BIND_DIRECTION, + BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); + + if(lockAxisMag) + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); + else + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); + s->addBinding(b); + + //Bind right button to changing position + b.setBinding(SELECT_BUTTON_RIGHT,0,DRAW_CYLINDER_BIND_ORIGIN, + BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + //Bind middle button to changing orientation + b.setBinding(SELECT_BUTTON_MIDDLE,0,DRAW_CYLINDER_BIND_DIRECTION, + BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); + if(lockAxisMag) + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); + else + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); + s->addBinding(b); + + //Bind left button to changing radius + b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_CYLINDER_BIND_RADIUS, + BINDING_CYLINDER_RADIUS,dC->getRadius(),dC); + b.setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + b.setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(b); + + devices.push_back(s); + //===== + + break; + } + case PRIMITIVE_AAB: + { + //Centre + corner + ASSERT(vectorParams.size() == 2); + ASSERT(scalarParams.size() == 0); + + //Add drawable components + DrawRectPrism *dR = new DrawRectPrism; + dR->setAxisAligned(vectorParams[0]-vectorParams[1], + vectorParams[0] + vectorParams[1]); + dR->setColour(0.5,0.5,0.5,1.0); + dR->setDrawMode(DRAW_FLAT); + dR->wantsLight=true; + drawData->drawables.push_back(dR); + + + //Set up selection "device" for user interaction + //==== + //The object is selectable + dR->canSelect=true; + + SelectionDevice *s = new SelectionDevice(this); + SelectionBinding b[2]; + //Bind the drawable object to the properties we wish + //to be able to modify + + //Bind orientation to sphere left click + b[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_RECT_BIND_TRANSLATE, + BINDING_RECT_TRANSLATE, vectorParams[0],dR); + b[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b[0]); + + + b[1].setBinding(SELECT_BUTTON_RIGHT,0,DRAW_RECT_BIND_CORNER_MOVE, + BINDING_RECT_CORNER_MOVE, vectorParams[1],dR); + b[1].setInteractionMode(BIND_MODE_POINT3D_SCALE); + s->addBinding(b[1]); + + devices.push_back(s); + //===== + break; + } + default: + ASSERT(false); + + } + + drawData->cached=0; + getOut.push_back(drawData); + } + + //use the cached copy of the data if we have it. + if(cacheOK) + { + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) + getOut.push_back(dataIn[ui]); + } + + return 0; + } + + + IonStreamData *d=0; + try + { + + std::map,size_t> primitiveTypeMap; + + using std::make_pair; + //map the primitive enum type, and the clip inversion state + // to the CropHelper clip mode + primitiveTypeMap[make_pair((size_t)PRIMITIVE_SPHERE,false)]=CROP_SPHERE_INSIDE; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_SPHERE,true)]=CROP_SPHERE_OUTSIDE; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_PLANE,false)]=CROP_PLANE_FRONT; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_PLANE,true)]=CROP_PLANE_BACK; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_CYLINDER,false)]=CROP_CYLINDER_INSIDE; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_CYLINDER,true)]=CROP_CYLINDER_OUTSIDE; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_AAB,false)]=CROP_AAB_INSIDE; + primitiveTypeMap[make_pair((size_t)PRIMITIVE_AAB,true)]=CROP_AAB_OUTSIDE; + + size_t mode; + mode = primitiveTypeMap[make_pair(primitiveType,invertedClip)]; + size_t totalSize=numElements(dataIn); + CropHelper cropper(callback,&progress.filterProgress, + totalSize,mode, + vectorParams,scalarParams ); + + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + d=new IonStreamData; + d->parent=this; + + //Filter input data to output data. + if(cropper.runFilter(((const IonStreamData *)dataIn[ui])->data,d->data)) + return CALLBACK_FAIL; + + if(d->data.size()) + { + //Copy over other attributes + d->r = ((IonStreamData *)dataIn[ui])->r; + d->g = ((IonStreamData *)dataIn[ui])->g; + d->b =((IonStreamData *)dataIn[ui])->b; + d->a =((IonStreamData *)dataIn[ui])->a; + d->ionSize =((IonStreamData *)dataIn[ui])->ionSize; + d->representationType=((IonStreamData *)dataIn[ui])->representationType; + + //getOut is const, so shouldn't be modified + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + + getOut.push_back(d); + d=0; + } + else + delete d; + break; + } + default: + //Just copy across the ptr, if we are unfamiliar with this type + getOut.push_back(dataIn[ui]); + break; + } + } + } + catch(std::bad_alloc) + { + if(d) + delete d; + return BAD_ALLOC; + } + return 0; + +} + +//!Get the properties of the filter, in key-value form. First vector is for each output. +void IonClipFilter::getProperties(FilterPropGroup &propertyList) const +{ + ASSERT(vectorParams.size() || scalarParams.size()); + + FilterProperty p; + + size_t curGroup=0; + //Let the user know what the valid values for Primitive type + string tmpStr; + + vector > choices; + + choices.push_back(make_pair((unsigned int)PRIMITIVE_SPHERE , + primitiveStringFromID(PRIMITIVE_SPHERE))); + choices.push_back(make_pair((unsigned int)PRIMITIVE_PLANE , + primitiveStringFromID(PRIMITIVE_PLANE))); + choices.push_back(make_pair((unsigned int)PRIMITIVE_CYLINDER , + primitiveStringFromID(PRIMITIVE_CYLINDER))); + choices.push_back(make_pair((unsigned int)PRIMITIVE_AAB, + primitiveStringFromID(PRIMITIVE_AAB))); + + tmpStr= choiceString(choices,primitiveType); + p.name=TRANS("Primitive"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_CHOICE; + p.helpText=TRANS("Shape of clipping object"); + p.key=KEY_PRIMITIVE_TYPE; + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,showPrimitive); + p.key=KEY_PRIMITIVE_SHOW; + p.name=TRANS("Show Primitive"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Display the 3D interaction object"); + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,invertedClip); + p.key=KEY_PRIMITIVE_INVERTCLIP; + p.name=TRANS("Invert Clip"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Switch between retaining points inside (false) and outside (true) of primitive"); + propertyList.addProperty(p,curGroup); + + switch(primitiveType) + { + case PRIMITIVE_SPHERE: + { + ASSERT(vectorParams.size() == 1); + ASSERT(scalarParams.size() == 1); + stream_cast(tmpStr,vectorParams[0]); + p.key=KEY_ORIGIN; + p.name=TRANS("Origin"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Position for centre of sphere"); + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,scalarParams[0]); + p.key=KEY_RADIUS; + p.name=TRANS("Radius"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Radius of sphere"); + propertyList.addProperty(p,curGroup); + + break; + } + case PRIMITIVE_PLANE: + { + ASSERT(vectorParams.size() == 2); + ASSERT(scalarParams.size() == 0); + stream_cast(tmpStr,vectorParams[0]); + p.key=KEY_ORIGIN; + p.name=TRANS("Origin"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Position that plane passes through"); + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,vectorParams[1]); + p.key=KEY_NORMAL; + p.name=TRANS("Plane Normal"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Perpendicular direction for plane"); + propertyList.addProperty(p,curGroup); + + break; + } + case PRIMITIVE_CYLINDER: + { + ASSERT(vectorParams.size() == 2); + ASSERT(scalarParams.size() == 1); + stream_cast(tmpStr,vectorParams[0]); + p.key=KEY_ORIGIN; + p.name=TRANS("Origin"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Centre of cylinder"); + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,vectorParams[1]); + p.key=KEY_NORMAL; + p.name=TRANS("Axis"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Positive vector for cylinder"); + propertyList.addProperty(p,curGroup); + + if(lockAxisMag) + tmpStr="1"; + else + tmpStr="0"; + p.key=KEY_AXIS_LOCKMAG; + p.name=TRANS("Lock Axis Mag."); + p.data=tmpStr; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Prevent changing length of cylinder during 3D interaction"); + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,scalarParams[0]); + p.key=KEY_RADIUS; + p.name=TRANS("Radius"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Radius of cylinder"); + propertyList.addProperty(p,curGroup); + break; + } + case PRIMITIVE_AAB: + { + ASSERT(vectorParams.size() == 2); + ASSERT(scalarParams.size() == 0); + stream_cast(tmpStr,vectorParams[0]); + p.key=KEY_ORIGIN; + p.name=TRANS("Origin"); + p.data= tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Centre of axis aligned box"); + propertyList.addProperty(p,curGroup); + + stream_cast(tmpStr,vectorParams[1]); + p.key=KEY_CORNER; + p.name=TRANS("Corner offset"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_POINT3D; + p.helpText=TRANS("Vector to corner of box"); + propertyList.addProperty(p,curGroup); + break; + } + default: + ASSERT(false); + } + +} + +//!Set the properties for the nth filter. Returns true if prop set OK +bool IonClipFilter::setProperty(unsigned int key, + const std::string &value, bool &needUpdate) +{ + + needUpdate=false; + switch(key) + { + case KEY_PRIMITIVE_TYPE: + { + unsigned int newPrimitive; + + newPrimitive=primitiveID(value); + if(newPrimitive == (unsigned int)-1) + return false; + + primitiveType=newPrimitive; + + switch(primitiveType) + { + //If we are switching between essentially + //similar data types, don't reset the data. + //Otherwise, wipe it and try again + case PRIMITIVE_SPHERE: + if(vectorParams.size() !=1) + { + vectorParams.clear(); + vectorParams.push_back(Point3D(0,0,0)); + } + if(scalarParams.size()!=1) + { + scalarParams.clear(); + scalarParams.push_back(10.0f); + } + break; + case PRIMITIVE_PLANE: + if(vectorParams.size() >2) + { + vectorParams.clear(); + vectorParams.push_back(Point3D(0,0,0)); + vectorParams.push_back(Point3D(0,1,0)); + } + else if (vectorParams.size() ==2) + { + vectorParams[1].normalise(); + } + else if(vectorParams.size() ==1) + { + vectorParams.push_back(Point3D(0,1,0)); + } + + scalarParams.clear(); + break; + case PRIMITIVE_CYLINDER: + if(vectorParams.size()>2) + { + vectorParams.resize(2); + } + else if(vectorParams.size() ==1) + { + vectorParams.push_back(Point3D(0,1,0)); + } + else if(!vectorParams.size()) + { + vectorParams.push_back(Point3D(0,0,0)); + vectorParams.push_back(Point3D(0,1,0)); + + } + + if(scalarParams.size()!=1) + { + scalarParams.clear(); + scalarParams.push_back(10.0f); + } + break; + case PRIMITIVE_AAB: + + if(vectorParams.size() >2) + { + vectorParams.clear(); + vectorParams.push_back(Point3D(0,0,0)); + vectorParams.push_back(Point3D(1,1,1)); + } + else if(vectorParams.size() ==1) + { + vectorParams.push_back(Point3D(1,1,1)); + } + //check to see if any components of the + //corner offset are zero; we disallow a + //zero, 1 or 2 dimensional box + for(unsigned int ui=0;ui<3;ui++) + { + vectorParams[1][ui]=fabs(vectorParams[1][ui]); + if(vectorParams[1][ui] ::epsilon()) + vectorParams[1][ui] = 1; + } + scalarParams.clear(); + break; + + default: + ASSERT(false); + } + + clearCache(); + needUpdate=true; + return true; + } + case KEY_ORIGIN: + { + ASSERT(vectorParams.size() >= 1); + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(vectorParams[0] == newPt )) + { + vectorParams[0] = newPt; + needUpdate=true; + clearCache(); + } + + return true; + } + case KEY_CORNER: + { + ASSERT(vectorParams.size() >= 2); + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(!(vectorParams[1] == newPt )) + { + vectorParams[1] = newPt; + needUpdate=true; + clearCache(); + } + + return true; + } + case KEY_RADIUS: + { + ASSERT(scalarParams.size() >=1); + float newRad; + if(stream_cast(newRad,value)) + return false; + + if(scalarParams[0] != newRad ) + { + scalarParams[0] = newRad; + needUpdate=true; + clearCache(); + } + return true; + } + case KEY_NORMAL: + { + ASSERT(vectorParams.size() >=2); + Point3D newPt; + if(!newPt.parse(value)) + return false; + + if(primitiveType == PRIMITIVE_CYLINDER) + { + if(lockAxisMag && + newPt.sqrMag() > sqrt(std::numeric_limits::epsilon())) + { + newPt.normalise(); + newPt*=sqrt(vectorParams[1].sqrMag()); + } + } + if(!(vectorParams[1] == newPt )) + { + vectorParams[1] = newPt; + needUpdate=true; + clearCache(); + } + return true; + } + case KEY_PRIMITIVE_SHOW: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + if(stripped=="1") + showPrimitive=true; + else + showPrimitive=false; + + needUpdate=true; + + break; + } + case KEY_PRIMITIVE_INVERTCLIP: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=invertedClip; + if(stripped=="1") + invertedClip=true; + else + invertedClip=false; + + //if the result is different, the + //cache should be invalidated + if(lastVal!=invertedClip) + { + needUpdate=true; + clearCache(); + } + + break; + } + + case KEY_AXIS_LOCKMAG: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + if(stripped=="1") + lockAxisMag=true; + else + lockAxisMag=false; + + needUpdate=true; + + break; + } + default: + ASSERT(false); + return false; + } + + ASSERT(vectorParams.size() || scalarParams.size()); + + return true; +} + +//!Get the human readable error string associated with a particular error code during refresh(...) +std::string IonClipFilter::getErrString(unsigned int code) const +{ + switch(code) + { + case BAD_ALLOC: + return std::string("Insufficient mem. for Ionclip"); + case CALLBACK_FAIL: + return std::string("Ionclip Aborted"); + } + ASSERT(false); +} + +bool IonClipFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<"<< trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + writeVectorsXML(f,"vectorparams",vectorParams, depth+1); + writeScalarsXML(f,"scalarparams",scalarParams,depth+1); + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool IonClipFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + std::string tmpStr; + //Retrieve primitive type + //==== + if(!XMLGetNextElemAttrib(nodePtr,primitiveType,"primitivetype","value")) + return false; + if(primitiveType >= PRIMITIVE_END) + return false; + //==== + + //Retrieve clip inversion + //==== + // + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"invertedclip","value")) + return false; + if(tmpStr == "0") + invertedClip=false; + else if(tmpStr == "1") + invertedClip=true; + else + return false; + //==== + + //Retrieve primitive visiblity + //==== + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"showprimitive","value")) + return false; + if(tmpStr == "0") + showPrimitive=false; + else if(tmpStr == "1") + showPrimitive=true; + else + return false; + //==== + + //Retrieve axis lock mode + //==== + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"lockaxismag","value")) + return false; + if(tmpStr == "0") + lockAxisMag=false; + else if(tmpStr == "1") + lockAxisMag=true; + else + return false; + //==== + + //Retreive vector parameters + //=== + if(XMLHelpFwdToElem(nodePtr,"vectorparams")) + return false; + + if(!readVectorsXML(nodePtr,vectorParams)) + return false; + //=== + + //Retreive scalar parameters + //=== + if(XMLHelpFwdToElem(nodePtr,"scalarparams")) + return false; + + if(!readScalarsXML(nodePtr,scalarParams)) + return false; + //=== + + //Check the scalar params match the selected primitive + switch(primitiveType) + { + case PRIMITIVE_SPHERE: + if(vectorParams.size() != 1 || scalarParams.size() !=1) + return false; + break; + case PRIMITIVE_PLANE: + case PRIMITIVE_AAB: + if(vectorParams.size() != 2 || scalarParams.size() !=0) + return false; + break; + case PRIMITIVE_CYLINDER: + if(vectorParams.size() != 2 || scalarParams.size() !=1) + return false; + break; + + default: + ASSERT(false); + return false; + } + + ASSERT(vectorParams.size() || scalarParams.size()); + return true; +} + +unsigned int IonClipFilter::getRefreshBlockMask() const +{ + return STREAM_TYPE_IONS ; +} + +unsigned int IonClipFilter::getRefreshEmitMask() const +{ + if(showPrimitive) + return STREAM_TYPE_IONS | STREAM_TYPE_DRAW; + else + return STREAM_TYPE_IONS ; +} + +unsigned int IonClipFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS; +} + +void IonClipFilter::setPropFromBinding(const SelectionBinding &b) +{ + switch(b.getID()) + { + case BINDING_CYLINDER_RADIUS: + case BINDING_SPHERE_RADIUS: + b.getValue(scalarParams[0]); + break; + case BINDING_CYLINDER_ORIGIN: + case BINDING_SPHERE_ORIGIN: + case BINDING_PLANE_ORIGIN: + case BINDING_RECT_TRANSLATE: + b.getValue(vectorParams[0]); + break; + case BINDING_CYLINDER_DIRECTION: + b.getValue(vectorParams[1]); + break; + case BINDING_PLANE_DIRECTION: + { + Point3D p; + b.getValue(p); + p.normalise(); + + vectorParams[1] =p; + break; + } + case BINDING_RECT_CORNER_MOVE: + { + //Prevent the corner offset from acquiring a vector + //with a negative component. + Point3D p; + b.getValue(p); + for(unsigned int ui=0;ui<3;ui++) + { + p[ui]=fabs(p[ui]); + //Should be positive + if(p[ui] ::epsilon()) + return; + } + + vectorParams[1]=p; + break; + } + default: + ASSERT(false); + } + clearCache(); +} + + +#ifdef DEBUG + +//Create a synthetic dataset of points +// returned pointer *must* be deleted by caller. +//Span must have 3 elements, and for best results should be co-prime with +// one another; eg all prime numbers +IonStreamData *synthData(const unsigned int span[],unsigned int numPts); + + +//Test the spherical clipping primitive +bool sphereTest(); +//Test the plane primitive +bool planeTest(); +//Test the cylinder primitive +bool cylinderTest(const Point3D &pAxis, const unsigned int *span, float testRadius); + +//Test the axis-aligned box primitve +bool rectTest(); + + +bool IonClipFilter::runUnitTests() +{ + if(!sphereTest()) + return false; + + if(!planeTest()) + return false; + + unsigned int span[]={ + 5, 7, 9 + }; + const float TEST_RADIUS=3.0f; + Point3D axis; + axis=Point3D(1,2,3); + if(!cylinderTest(axis,span,TEST_RADIUS)) + return false; + + axis=Point3D(0,1,0); + if(!cylinderTest(axis,span,TEST_RADIUS)) + return false; + + if(!rectTest()) + return false; + + return true; +} + +bool sphereTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + unsigned int span[]={ + 5, 7, 9 + }; + const unsigned int NUM_PTS=10000; + IonStreamData *d=synthData(span,NUM_PTS); + streamIn.push_back(d); + + IonClipFilter *f=new IonClipFilter; + f->setCaching(false); + + bool needUp; std::string s; + TEST(f->setProperty(KEY_PRIMITIVE_TYPE, + primitiveStringFromID(PRIMITIVE_SPHERE),needUp),"Set Prop"); + + Point3D pOrigin((float)span[0]/2,(float)span[1]/2,(float)span[2]/2); + stream_cast(s,pOrigin); + TEST(f->setProperty(KEY_ORIGIN,s,needUp),"Set prop"); + + const float TEST_RADIUS=1.2f; + stream_cast(s,TEST_RADIUS); + TEST(f->setProperty(KEY_RADIUS,s,needUp),"Set prop"); + + TEST(f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp),"Set prop"); + + //Do the refresh + ProgressData p; + f->refresh(streamIn,streamOut,p,dummyCallback); + + delete f; + delete d; + + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + + TEST(streamOut[0]->getNumBasicObjects() > 0, "clipped point count"); + + const IonStreamData *dOut=(IonStreamData*)streamOut[0]; + + for(unsigned int ui=0;uidata.size();ui++) + { + Point3D p; + p=dOut->data[ui].getPos(); + + TEST(sqrt(p.sqrDist(pOrigin)) + <= TEST_RADIUS,"Sphere containment"); + } + + delete dOut; + return true; +} + +bool planeTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + unsigned int span[]={ + 5, 7, 9 + }; + const unsigned int NUM_PTS=10000; + IonStreamData *d=synthData(span,NUM_PTS); + streamIn.push_back(d); + + IonClipFilter *f=new IonClipFilter; + f->setCaching(false); + + bool needUp; std::string s; + TEST(f->setProperty(KEY_PRIMITIVE_TYPE, + primitiveStringFromID(PRIMITIVE_PLANE),needUp),"set prop"); + + Point3D pOrigin((float)span[0]/2,(float)span[1]/2,(float)span[2]/2); + stream_cast(s,pOrigin); + TEST(f->setProperty(KEY_ORIGIN,s,needUp),"Set prop"); + + Point3D pPlaneDir(1,2,3); + stream_cast(s,pPlaneDir); + TEST(f->setProperty(KEY_NORMAL,s,needUp),"Set prop"); + + TEST(f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp),"Set prop"); + + //Do the refresh + ProgressData p; + f->refresh(streamIn,streamOut,p,dummyCallback); + + delete f; + delete d; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + + const IonStreamData *dOut=(IonStreamData*)streamOut[0]; + + for(unsigned int ui=0;uidata.size();ui++) + { + Point3D p; + p=dOut->data[ui].getPos(); + + p=p-pOrigin; + TEST(p.dotProd(pPlaneDir) >=0, "Plane direction"); + } + + delete dOut; + return true; +} + +bool cylinderTest(const Point3D &pAxis, const unsigned int *span, float testRadius) +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + const unsigned int NUM_PTS=10000; + IonStreamData *d=synthData(span,NUM_PTS); + streamIn.push_back(d); + + IonClipFilter*f=new IonClipFilter; + f->setCaching(false); + + bool needUp; std::string s; + TEST(f->setProperty(KEY_PRIMITIVE_TYPE, + primitiveStringFromID(PRIMITIVE_CYLINDER),needUp),"Set prop"); + + Point3D pOrigin((float)span[0]/2,(float)span[1]/2,(float)span[2]/2); + stream_cast(s,pOrigin); + TEST(f->setProperty(KEY_ORIGIN,s,needUp),"Set prop"); + + stream_cast(s,pAxis); + TEST(f->setProperty(KEY_NORMAL,s,needUp),"Set prop"); + + stream_cast(s,testRadius); + TEST(f->setProperty(KEY_RADIUS,s,needUp),"Set prop"); + + TEST(f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp),"Set prop"); + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + delete f; + delete d; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + + const IonStreamData *dOut=(IonStreamData*)streamOut[0]; + + DrawCylinder *dC = new DrawCylinder; + dC->setRadius(testRadius); + dC->setOrigin(pOrigin); + float len = sqrt(pAxis.sqrMag()); + + Point3D axisNormal(pAxis); + axisNormal.normalise(); + + dC->setDirection(pAxis); + dC->setLength(len); + + BoundCube b; + dC->getBoundingBox(b); + + delete dC; + + b.expand(sqrt(std::numeric_limits::epsilon())); + for(unsigned int ui=0;uidata.size();ui++) + { + Point3D p; + p=dOut->data[ui].getPos(); + //FIXME: This fails, but appears to work, depending upon the + // tests I put it through??? + TEST(b.containsPt(p), "Bounding box containment"); + } + + delete dOut; + + return true; +} + +bool rectTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + unsigned int span[]={ + 5, 7, 9 + }; + const unsigned int NUM_PTS=10000; + IonStreamData *d=synthData(span,NUM_PTS); + streamIn.push_back(d); + + IonClipFilter*f=new IonClipFilter; + f->setCaching(false); + + bool needUp; std::string s; + TEST(f->setProperty(KEY_PRIMITIVE_TYPE, + primitiveStringFromID(PRIMITIVE_AAB),needUp),"set prop"); + TEST(f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp),"Set prop"); + TEST(f->setProperty(KEY_PRIMITIVE_INVERTCLIP,"0",needUp),"Set prop"); + + Point3D pOrigin(span[0],span[1],span[2]); + pOrigin*=0.25f; + stream_cast(s,pOrigin); + TEST(f->setProperty(KEY_ORIGIN,s,needUp),"Set prop"); + + Point3D pCorner(span[0],span[1],span[2]); + pCorner*=0.25f; + stream_cast(s,pCorner); + TEST(f->setProperty(KEY_CORNER,s,needUp),"Set prop"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + delete f; + delete d; + + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + const IonStreamData *dOut=(IonStreamData*)streamOut[0]; + + BoundCube b; + b.setBounds(pOrigin-pCorner,pOrigin+pCorner); + for(unsigned int ui=0;uidata.size();ui++) + { + Point3D p; + p=dOut->data[ui].getPos(); + + TEST(b.containsPt(p), "Bounding box containment"); + } + + + delete dOut; + return true; +} + + +IonStreamData *synthData(const unsigned int span[], unsigned int numPts) +{ + IonStreamData *d = new IonStreamData; + + for(unsigned int ui=0;uidata.push_back(h); + } + + return d; +} + + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/ionClip.h 3depict-0.0.13/src/backend/filters/ionClip.h --- 3depict-0.0.12/src/backend/filters/ionClip.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionClip.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * ionClip.h - Clipping of 3D point clouds + * 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 . +*/ +#ifndef IONCLIP_H +#define IONCLIP_H + +#include "../filter.h" +#include "../../common/translation.h" + +//!Ion spatial clipping filter +class IonClipFilter : public Filter +{ + protected: + //!Number explaining basic primitive type + /* Possible Modes: + * Planar clip (origin + normal) + * spherical clip (origin + radius) + * Cylindrical clip (origin + axis + length) + * Axis aligned box (origin + corner) + */ + unsigned int primitiveType; + + //!Whether to reverse the clip. True means that the interior is excluded + bool invertedClip; + //!Whether to show the primitive or not + bool showPrimitive; + //!Vector paramaters for different primitives + vector vectorParams; + //!Scalar paramaters for different primitives + vector scalarParams; + //Lock the primitive axis during for cylinder? + bool lockAxisMag; + + public: + IonClipFilter(); + + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //!Returns FILTER_TYPE_IONCLIP + unsigned int getType() const { return FILTER_TYPE_IONCLIP;}; + + //!Get approx number of bytes for caching output + size_t numBytesForCache(size_t nObjects) const; + + //!update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + //!Return human readable name for filter + virtual std::string typeString() const { return std::string(TRANS("Clipping"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter. Returns true if prop set OK + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, unsigned int depth=0) const; + + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be possibly used during ::refresh + unsigned int getRefreshUseMask() const; + + + //!Set internal property value using a selection binding + void setPropFromBinding(const SelectionBinding &b); + +#ifdef DEBUG + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/ionColour.cpp 3depict-0.0.13/src/backend/filters/ionColour.cpp --- 3depict-0.0.12/src/backend/filters/ionColour.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionColour.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,650 @@ +/* + * ionColour.cpp - Filter to create coloured batches of ions based upon value + * 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 . +*/ +#include "ionColour.h" + +#include "filterCommon.h" + +#include "common/colourmap.h" + + +const unsigned int MAX_NUM_COLOURS=256; +enum +{ + KEY_IONCOLOURFILTER_COLOURMAP, + KEY_IONCOLOURFILTER_MAPSTART, + KEY_IONCOLOURFILTER_MAPEND, + KEY_IONCOLOURFILTER_NCOLOURS, + KEY_IONCOLOURFILTER_SHOWBAR, +}; + +enum +{ + IONCOLOUR_ABORT_ERR +}; + +IonColourFilter::IonColourFilter() : colourMap(0), nColours(MAX_NUM_COLOURS), + showColourBar(true) +{ + mapBounds[0] = 0.0f; + mapBounds[1] = 100.0f; + + cacheOK=false; + cache=true; //By default, we should cache, but decision is made higher up + +} + +Filter *IonColourFilter::cloneUncached() const +{ + IonColourFilter *p=new IonColourFilter(); + p->colourMap = colourMap; + p->mapBounds[0]=mapBounds[0]; + p->mapBounds[1]=mapBounds[1]; + p->nColours =nColours; + p->showColourBar =showColourBar; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +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 r,g,b; + r.resize(nColours); + g.resize(nColours); + b.resize(nColours); + + for (unsigned int ui=0;uisetColourVec(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 &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + //use the cached copy if we have it. + if(cacheOK) + { + ASSERT(filterOutputs.size()); + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) + getOut.push_back(dataIn[ui]); + } + + for(unsigned int ui=0;uiparent=this; + d->drawables.push_back(makeColourBar()); + d->cached=0; + getOut.push_back(d); + } + return 0; + } + + + ASSERT(nColours >0 && nColours<=MAX_NUM_COLOURS); + IonStreamData *d[nColours]; + unsigned char rgb[3]; //RGB array + //Build the colourmap values, each as a unique filter output + for(unsigned int ui=0;uiparent=this; + 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]); + + d[ui]->r=rgb[0]/255.0f; + d[ui]->g=rgb[1]/255.0f; + d[ui]->b=rgb[2]/255.0f; + d[ui]->a=1.0f; + } + + //Try to maintain ion size if possible + bool haveIonSize,sameSize; // have we set the ionSize? + float ionSize; + haveIonSize=false; + sameSize=true; + + //Did we find any ions in this pass? + bool foundIons=false; + unsigned int totalSize=numElements(dataIn); + unsigned int curProg=NUM_CALLBACK; + size_t n=0; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + foundIons=true; + + //Check for ion size consistency + if(haveIonSize) + { + sameSize &= (fabs(ionSize-((const IonStreamData *)dataIn[ui])->ionSize) + < std::numeric_limits::epsilon()); + } + else + { + ionSize=((const IonStreamData *)dataIn[ui])->ionSize; + haveIonSize=true; + } + for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); + it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) + { + unsigned int colour; + + float tmp; + tmp= (it->getMassToCharge()-mapBounds[0])/(mapBounds[1]-mapBounds[0]); + tmp = std::max(0.0f,tmp); + tmp = std::min(tmp,1.0f); + + colour=(unsigned int)(tmp*(float)(nColours-1)); + d[colour]->data.push_back(*it); + + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + curProg=NUM_CALLBACK; + if(!(*callback)(false)) + { + for(unsigned int ui=0;uidrawables.push_back(makeColourBar()); + d->parent=this; + d->cached=0; + getOut.push_back(d); + } + + + //If all the ions are the same size, then propagate + if(haveIonSize && sameSize) + { + for(unsigned int ui=0;uiionSize=ionSize; + } + //merge the results as needed + if(cache) + { + for(unsigned int ui=0;uidata.size()) + d[ui]->cached=1; + else + d[ui]->cached=0; + if(d[ui]->data.size()) + filterOutputs.push_back(d[ui]); + } + cacheOK=filterOutputs.size(); + } + else + { + for(unsigned int ui=0;uicached=0; + } + cacheOK=false; + } + + //push the colours onto the output. cached or not (their status is set above). + for(unsigned int ui=0;uidata.size()) + getOut.push_back(d[ui]); + else + delete d[ui]; + } + + return 0; +} + + +void IonColourFilter::getProperties(FilterPropGroup &propertyList) const +{ + + FilterProperty p; + string tmpStr; + vector > choices; + + size_t curGroup=0; + + for(unsigned int ui=0;ui=NUM_COLOURMAPS || tmpMap ==colourMap) + return false; + + clearCache(); + needUpdate=true; + colourMap=tmpMap; + break; + } + case KEY_IONCOLOURFILTER_MAPSTART: + { + float tmpBound; + stream_cast(tmpBound,value); + if(tmpBound >=mapBounds[1]) + return false; + + clearCache(); + needUpdate=true; + mapBounds[0]=tmpBound; + break; + } + case KEY_IONCOLOURFILTER_MAPEND: + { + float tmpBound; + stream_cast(tmpBound,value); + if(tmpBound <=mapBounds[0]) + return false; + + clearCache(); + needUpdate=true; + mapBounds[1]=tmpBound; + break; + } + case KEY_IONCOLOURFILTER_NCOLOURS: + { + unsigned int numColours; + if(stream_cast(numColours,value)) + return false; + + clearCache(); + needUpdate=true; + //enforce 1->MAX_NUM_COLOURS range + nColours=std::min(numColours,MAX_NUM_COLOURS); + if(!nColours) + nColours=1; + break; + } + case KEY_IONCOLOURFILTER_SHOWBAR: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=showColourBar; + showColourBar=(stripped == "1"); + + //Only need update if changed + if(lastVal!=showColourBar) + needUpdate=true; + break; + } + + default: + ASSERT(false); + } + return true; +} + + +std::string IonColourFilter::getErrString(unsigned int code) const +{ + //Currently the only error is aborting + return std::string(TRANS("Aborted")); +} + +void IonColourFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + +bool IonColourFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + string str; + if(showColourBar) + str="1"; + else + str="0"; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool IonColourFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + std::string tmpStr; + //Retrieve colourmap + //==== + if(XMLHelpFwdToElem(nodePtr,"colourmap")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(colourMap,tmpStr)) + return false; + + if(colourMap>= NUM_COLOURMAPS) + return false; + xmlFree(xmlString); + //==== + + //Retrieve Extrema + //=== + float tmpMin,tmpMax; + if(XMLHelpFwdToElem(nodePtr,"extrema")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"min"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(tmpMin,tmpStr)) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"max"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(tmpMax,tmpStr)) + return false; + + xmlFree(xmlString); + + if(tmpMin > tmpMax) + return false; + + mapBounds[0]=tmpMin; + mapBounds[1]=tmpMax; + + //=== + + //Retrieve num colours + //==== + if(XMLHelpFwdToElem(nodePtr,"ncolours")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(nColours,tmpStr)) + return false; + + xmlFree(xmlString); + //==== + + //Retrieve num colours + //==== + if(XMLHelpFwdToElem(nodePtr,"showcolourbar")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + //convert from string to digit + if(stream_cast(showColourBar,tmpStr)) + return false; + + xmlFree(xmlString); + //==== + return true; +} + +unsigned int IonColourFilter::getRefreshBlockMask() const +{ + //Anything but ions can go through this filter. + return STREAM_TYPE_IONS; +} + +unsigned int IonColourFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_DRAW | STREAM_TYPE_IONS; +} + +unsigned int IonColourFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS; +} +#ifdef DEBUG + +IonStreamData *sythIonCountData(unsigned int numPts, float mStart, float mEnd) +{ + IonStreamData *d = new IonStreamData; + d->data.resize(numPts); + for(unsigned int ui=0; uidata[ui] =h; + } + + return d; +} + + +bool ionCountTest() +{ + const int NUM_PTS=1000; + vector streamIn,streamOut; + IonStreamData *d=sythIonCountData(NUM_PTS,0,100); + streamIn.push_back(d); + + + IonColourFilter *f = new IonColourFilter; + f->setCaching(false); + + bool needUpdate; + TEST(f->setProperty(KEY_IONCOLOURFILTER_NCOLOURS,"100",needUpdate),"Set prop"); + TEST(f->setProperty(KEY_IONCOLOURFILTER_MAPSTART,"0",needUpdate),"Set prop"); + TEST(f->setProperty(KEY_IONCOLOURFILTER_MAPEND,"100",needUpdate),"Set prop"); + TEST(f->setProperty(KEY_IONCOLOURFILTER_SHOWBAR,"0",needUpdate),"Set prop"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + delete f; + delete d; + + TEST(streamOut.size() == 99,"stream count"); + + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS,"stream type"); + } + + for(unsigned int ui=0;ui. +*/ +#ifndef IONCOLOUR_H +#define IONCOLOUR_H + +#include "../filter.h" +#include "../../common/translation.h" + +//!Ion colouring filter +class IonColourFilter: public Filter +{ + private: + //!Colourmap to use + /* 0 jetColorMap | 4 positiveColorMap + * 1 hotColorMap | 5 negativeColorMap + * 2 coldColorMap | 6 colorMap + * 3 blueColorMap | 7 cyclicColorMap + * 8 randColorMap | 9 grayColorMap + */ + unsigned int colourMap; + //!map start & end (spectrum value to align start and end of map to) + float mapBounds[2]; + + //!Number of unique colours to generate, max 256 + unsigned int nColours; + + //!Should we display the colour bar? + bool showColourBar; + + DrawColourBarOverlay* makeColourBar() const; + public: + IonColourFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + //!Returns FILTER_TYPE_IONCOLOURFILTER + unsigned int getType() const { return FILTER_TYPE_IONCOLOURFILTER;}; + //!Get (approx) number of bytes required for cache + virtual size_t numBytesForCache(size_t nObjects) const; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + //!return string naming the human readable type of this class + virtual std::string typeString() const { return std::string(TRANS("Spectral Colour"));} + + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty( unsigned int key, const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be used during ::refresh + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b); + +#ifdef DEBUG + bool runUnitTests() ; +#endif +}; +#endif diff -Nru 3depict-0.0.12/src/backend/filters/ionDownsample.cpp 3depict-0.0.13/src/backend/filters/ionDownsample.cpp --- 3depict-0.0.12/src/backend/filters/ionDownsample.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionDownsample.cpp 2013-04-10 19:28:41.000000000 +0000 @@ -0,0 +1,941 @@ +/* + * ionDownsample.cpp - Filter to perform sampling without replacement on input ion data + * 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 . +*/ + + +#include "../../common/translation.h" +#include "filterCommon.h" + +#include "ionDownsample.h" + + +//!Downsampling filter +enum +{ + IONDOWNSAMPLE_ABORT_ERR=1, + IONDOWNSAMPLE_BAD_ALLOC, +}; + + +// == Ion Downsampling filter == + +IonDownsampleFilter::IonDownsampleFilter() +{ + rng.initTimer(); + fixedNumOut=true; + fraction=0.1f; + maxAfterFilter=5000; + rsdIncoming=0; + perSpecies=false; + + cacheOK=false; + cache=true; //By default, we should cache, but decision is made higher up + +} + +void IonDownsampleFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + const RangeStreamData *c=0; + //Determine if we have an incoming range + for (size_t i = 0; i < dataIn.size(); i++) + { + if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE) + { + c=(const RangeStreamData *)dataIn[i]; + + dataOut.push_back(dataIn[i]); + break; + } + } + + //we no longer (or never did) have any incoming ranges. Not much to do + if(!c) + { + //delete the old incoming range pointer + if(rsdIncoming) + delete rsdIncoming; + rsdIncoming=0; + + //Well, don't use per-species info anymore + perSpecies=false; + } + else + { + + + //If we didn't have a previously incoming rsd, then make one up! + // - we can't use a reference, as the rangestreams are technically transient, + // so we have to copy. + if(!rsdIncoming) + { + rsdIncoming = new RangeStreamData; + *rsdIncoming=*c; + + if(ionFractions.size() != c->rangeFile->getNumIons()) + { + //set up some defaults; seeded from normal + ionFractions.resize(c->rangeFile->getNumIons(),fraction); + ionLimits.resize(c->rangeFile->getNumIons(),maxAfterFilter); + } + } + else + { + + //OK, so we have a range incoming already (from last time) + //-- the question is, is it the same one we had before ? + // + //Do a pointer comparison (its a hack, yes, but it should work) + if(rsdIncoming->rangeFile != c->rangeFile) + { + //hmm, it is different. well, trash the old incoming rng + delete rsdIncoming; + + rsdIncoming = new RangeStreamData; + *rsdIncoming=*c; + + ionFractions.resize(c->rangeFile->getNumIons(),fraction); + ionLimits.resize(c->rangeFile->getNumIons(),maxAfterFilter); + } + else if(ionFractions.size() !=c->rangeFile->getNumIons()) + { + //well its the same range, but somehow the number of ions + //have changed. Could be range was reloaded. + ionFractions.resize(rsdIncoming->rangeFile->getNumIons(),fraction); + ionLimits.resize(rsdIncoming->rangeFile->getNumIons(),maxAfterFilter); + } + + //Ensure what is enabled and is disabled is up-to-date + for(unsigned int ui=0;uienabledRanges.size();ui++) + rsdIncoming->enabledRanges[ui] = c->enabledRanges[ui]; + for(unsigned int ui=0;uienabledIons.size();ui++) + rsdIncoming->enabledIons[ui] = c->enabledIons[ui]; + + } + + } + + + ASSERT(ionLimits.size() == ionFractions.size()); +} + +Filter *IonDownsampleFilter::cloneUncached() const +{ + IonDownsampleFilter *p=new IonDownsampleFilter(); + p->rng = rng; + p->maxAfterFilter=maxAfterFilter; + p->fraction=fraction; + p->perSpecies=perSpecies; + p->rsdIncoming=rsdIncoming; + + p->ionFractions.resize(ionFractions.size()); + std::copy(ionFractions.begin(),ionFractions.end(),p->ionFractions.begin()); + p->ionLimits.resize(ionLimits.size()); + std::copy(ionLimits.begin(),ionLimits.end(),p->ionLimits.begin()); + + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + p->fixedNumOut=fixedNumOut; + return p; +} + +size_t IonDownsampleFilter::numBytesForCache(size_t nObjects) const +{ + if(fixedNumOut) + { + if(nObjects > maxAfterFilter) + return maxAfterFilter*IONDATA_SIZE; + else + return nObjects*IONDATA_SIZE; + } + else + { + return (size_t)((float)(nObjects*IONDATA_SIZE)*fraction); + } +} + +unsigned int IonDownsampleFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + //use the cached copy if we have it. + if(cacheOK) + { + for(size_t ui=0;uigetStreamType() != STREAM_TYPE_IONS) + getOut.push_back(dataIn[ui]); + } + for(size_t ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + if(!totalSize) + continue; + + IonStreamData *d; + d=new IonStreamData; + d->parent=this; + try + { + if(fixedNumOut) + { + float frac; + frac = (float)(((const IonStreamData*)dataIn[ui])->data.size())/(float)totalSize; + + randomSelect(d->data,((const IonStreamData *)dataIn[ui])->data, + rng,maxAfterFilter*frac,progress.filterProgress,callback,strongRandom); + + + } + else + { + + unsigned int curProg=NUM_CALLBACK; + size_t n=0; + //Reserve 90% of storage needed. + //highly likely with even modest numbers of ions + //that this will be exceeded + d->data.reserve((size_t)(fraction*0.9*totalSize)); + + ASSERT(dataIn[ui]->getStreamType() == STREAM_TYPE_IONS); + + for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); + it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) + { + if(rng.genUniformDev() < fraction) + d->data.push_back(*it); + + //update progress every CALLBACK ions + if(!curProg--) + { + curProg=NUM_CALLBACK; + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return IONDOWNSAMPLE_ABORT_ERR; + } + } + } + } + } + catch(std::bad_alloc) + { + delete d; + return IONDOWNSAMPLE_BAD_ALLOC; + } + + //skip ion output sets with no ions in them + if(d->data.empty()) + { + delete d; + continue; + } + + //Copy over other attributes + d->r = ((IonStreamData *)dataIn[ui])->r; + d->g = ((IonStreamData *)dataIn[ui])->g; + d->b =((IonStreamData *)dataIn[ui])->b; + d->a =((IonStreamData *)dataIn[ui])->a; + d->ionSize =((IonStreamData *)dataIn[ui])->ionSize; + d->representationType=((IonStreamData *)dataIn[ui])->representationType; + d->valueType=((IonStreamData *)dataIn[ui])->valueType; + + //getOut is const, so shouldn't be modified + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + + getOut.push_back(d); + break; + } + + default: + getOut.push_back(dataIn[ui]); + break; + } + + } + } + else + { + ASSERT(rsdIncoming); + const IonStreamData *input; + + //Construct two vectors. One with the ion IDs for each input + //ion stream. the other with the total number of ions in the input + //for each ion type + vector numIons,ionIDVec; + numIons.resize(rsdIncoming->rangeFile->getNumIons(),0); + + for(unsigned int uj=0;ujgetStreamType() == STREAM_TYPE_IONS) + { + input=(const IonStreamData*)dataIn[uj]; + if(input->data.size()) + { + unsigned int ionID; + ionID=rsdIncoming->rangeFile->getIonID( + input->data[0].getMassToCharge()); + + if(ionID != (unsigned int)-1) + numIons[ionID]+=input->data.size(); + + ionIDVec.push_back(ionID); + } + } + } + + size_t n=0; + unsigned int idPos=0; + for(size_t ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + input=(const IonStreamData*)dataIn[ui]; + + //Don't process ionstreams that are empty + if(input->data.empty()) + continue; + + //FIXME: Allow processing of unranged data + //Don't process streams that are not ranged, as we cannot get their desired fractions + //at this time + if(ionIDVec[idPos]==(unsigned int)-1) + continue; + + IonStreamData *d; + d=new IonStreamData; + d->parent=this; + try + { + if(fixedNumOut) + { + //if we are building the fixed number for output, + //then compute the relative fraction for this ion set + float frac; + frac = (float)(input->data.size())/(float)(numIons[ionIDVec[idPos]]); + + //The total number of ions is the specified value for this ionID, multiplied by + //this stream's fraction of the total incoming data + randomSelect(d->data,input->data, rng,(size_t)(frac*ionLimits[ionIDVec[idPos]]), + progress.filterProgress,callback,strongRandom); + } + else + { + //Use the direct fractions as entered in by user. + + unsigned int curProg=NUM_CALLBACK; + + float thisFraction = ionFractions[ionIDVec[idPos]]; + + //Reserve 90% of storage needed. + //highly likely (Poisson) with even modest numbers of ions + //that this will be exceeded, and thus we won't over-allocate + d->data.reserve((size_t)(thisFraction*0.9*numIons[ionIDVec[idPos]])); + + if(thisFraction) + { + for(vector::const_iterator it=input->data.begin(); + it!=input->data.end(); ++it) + { + if(rng.genUniformDev() < thisFraction) + d->data.push_back(*it); + + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= + (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return IONDOWNSAMPLE_ABORT_ERR; + } + } + } + + } + } + } + catch(std::bad_alloc) + { + delete d; + return IONDOWNSAMPLE_BAD_ALLOC; + } + + + if(d->data.size()) + { + //Copy over other attributes + d->r = input->r; + d->g = input->g; + d->b =input->b; + d->a =input->a; + d->ionSize =input->ionSize; + d->representationType=input->representationType; + d->valueType=input->valueType; + + + //getOut is const, so shouldn't be modified + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + + getOut.push_back(d); + } + else + delete d; + //next ion + idPos++; + + break; + } + + default: + getOut.push_back(dataIn[ui]); + break; + } + + } + + + } + + return 0; +} + + +void IonDownsampleFilter::getProperties(FilterPropGroup &propertyList) const +{ + + FilterProperty p; + size_t curGroup=0; + + string tmpStr; + stream_cast(tmpStr,fixedNumOut); + p.data=tmpStr; + p.name=TRANS("By Count"); + p.key=KEY_IONDOWNSAMPLE_FIXEDOUT; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Sample up to a fixed number of ions"); + propertyList.addProperty(p,curGroup); + + if(rsdIncoming) + { + stream_cast(tmpStr,perSpecies); + p.name=TRANS("Per Species"); + p.data=tmpStr; + p.key=KEY_IONDOWNSAMPLE_PERSPECIES; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Use species specific (from ranging) sampling values"); + propertyList.addProperty(p,curGroup); + } + + + propertyList.setGroupTitle(curGroup,TRANS("Sampling rates")); + curGroup++; + if(rsdIncoming && perSpecies) + { + unsigned int typeVal; + if(fixedNumOut) + typeVal=PROPERTY_TYPE_INTEGER; + else + typeVal=PROPERTY_TYPE_REAL; + + //create a single line for each + for(unsigned int ui=0; uienabledIons.size(); ui++) + { + if(rsdIncoming->enabledIons[ui]) + { + if(fixedNumOut) + stream_cast(tmpStr,ionLimits[ui]); + else + stream_cast(tmpStr,ionFractions[ui]); + + p.name=rsdIncoming->rangeFile->getName(ui); + p.data=tmpStr; + p.type=typeVal; + p.helpText=TRANS("Sampling value for species"); + p.key=KEY_IONDOWNSAMPLE_DYNAMIC+ui; + propertyList.addProperty(p,curGroup); + } + } + } + else + { + if(fixedNumOut) + { + stream_cast(tmpStr,maxAfterFilter); + p.key=KEY_IONDOWNSAMPLE_COUNT; + p.name=TRANS("Output Count"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_INTEGER; + p.helpText=TRANS("Sample up to this value of points"); + } + else + { + stream_cast(tmpStr,fraction); + p.name=TRANS("Out Fraction"); + p.data=tmpStr; + p.key=KEY_IONDOWNSAMPLE_FRACTION; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Sample this fraction of points"); + + } + propertyList.addProperty(p,curGroup); + } +} + +bool IonDownsampleFilter::setProperty( unsigned int key, + const std::string &value, bool &needUpdate) +{ + needUpdate=false; + switch(key) + { + case KEY_IONDOWNSAMPLE_FIXEDOUT: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=fixedNumOut; + fixedNumOut=(stripped=="1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=fixedNumOut) + { + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_IONDOWNSAMPLE_FRACTION: + { + float newFraction; + if(stream_cast(newFraction,value)) + return false; + + if(newFraction < 0.0f || newFraction > 1.0f) + return false; + + //In the case of fixed number output, + //our cache is invalidated + if(!fixedNumOut) + { + needUpdate=true; + clearCache(); + } + + fraction=newFraction; + + + break; + } + case KEY_IONDOWNSAMPLE_COUNT: + { + size_t count; + + if(stream_cast(count,value)) + return false; + + maxAfterFilter=count; + //In the case of fixed number output, + //our cache is invalidated + if(fixedNumOut) + { + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_IONDOWNSAMPLE_PERSPECIES: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=perSpecies; + + perSpecies=(stripped=="1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=perSpecies) + { + needUpdate=true; + clearCache(); + } + + break; + } + default: + { + ASSERT(rsdIncoming); + ASSERT(key >=KEY_IONDOWNSAMPLE_DYNAMIC); + ASSERT(key < KEY_IONDOWNSAMPLE_DYNAMIC+ionLimits.size()); + ASSERT(ionLimits.size() == ionFractions.size()); + + unsigned int offset; + offset=key-KEY_IONDOWNSAMPLE_DYNAMIC; + + //TODO: Disable this test - + // offset >=ionLimits.size() did happen, but should not have. + // Can't reproduce bug - something to do with wrong filter being given selected properties in UI + ASSERT( offset < ionLimits.size()); + if(offset >= ionLimits.size()) + return false; + + //Dynamically generated list of downsamples + if(fixedNumOut) + { + //Fixed count + size_t v; + if(stream_cast(v,value)) + return false; + ionLimits[offset]=v; + } + else + { + //Fixed fraction + float v; + if(stream_cast(v,value)) + return false; + + if(v < 0.0f || v> 1.0f) + return false; + + ionFractions[offset]=v; + } + + needUpdate=true; + clearCache(); + break; + } + + } + return true; +} + + +std::string IonDownsampleFilter::getErrString(unsigned int code) const +{ + switch(code) + { + case IONDOWNSAMPLE_ABORT_ERR: + return std::string(TRANS("Downsample Aborted")); + case IONDOWNSAMPLE_BAD_ALLOC: + return std::string(TRANS("Insuffient memory for downsample")); + } + + return std::string("BUG! Should not see this (IonDownsample)"); +} + +void IonDownsampleFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + + +bool IonDownsampleFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + writeScalarsXML(f,"fractions",ionFractions,depth+1); + + writeScalarsXML(f,"limits",ionLimits,depth+1); + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool IonDownsampleFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + using std::string; + string tmpStr; + + xmlChar *xmlString; + //Retrieve user string + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + + //Retrieve number out (yes/no) mode + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixednumout","value")) + return false; + + if(tmpStr == "1") + fixedNumOut=true; + else if(tmpStr== "0") + fixedNumOut=false; + else + return false; + //=== + + //Retrieve Fraction + //=== + if(!XMLGetNextElemAttrib(nodePtr,fraction,"fraction","value")) + return false; + //disallow negative or values gt 1. + if(fraction < 0.0f || fraction > 1.0f) + return false; + //=== + + + //Retrieve "perspecies" attrib + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"perspecies","value")) + return false; + + if(tmpStr == "1") + perSpecies=true; + else if(tmpStr== "0") + perSpecies=false; + else + return false; + + //Retrieve the ion per-species fractions + if(XMLHelpFwdToElem(nodePtr,"fractions")) + return false; + + //Populate the ion fraction vector + if(!readScalarsXML(nodePtr,ionFractions)) + return false; + + //Retrieve the ion per-species fractions + if(XMLHelpFwdToElem(nodePtr,"limits")) + return false; + + if(!readScalarsXML(nodePtr,ionLimits)) + return false; + + if(ionLimits.size()!=ionFractions.size()) + return false; + + return true; +} + + +unsigned int IonDownsampleFilter::getRefreshBlockMask() const +{ + return STREAM_TYPE_IONS ; +} + +unsigned int IonDownsampleFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_IONS; +} + +unsigned int IonDownsampleFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_RANGE | STREAM_TYPE_IONS; +} +//---------- + + +//Unit testing for this class +///----- +#ifdef DEBUG + +//Create a synthetic dataset of points +// returned pointer *must* be deleted. Span must have 3 elements, +// and for best results could be co-prime with one another; eg all prime numbers +IonStreamData *synthDataPts(unsigned int span[],unsigned int numPts); + +//Test for fixed number of output ions +bool fixedSampleTest(); + +//Test for variable number of output ions +bool variableSampleTest(); + +//Unit tests +bool IonDownsampleFilter::runUnitTests() +{ + if(!fixedSampleTest()) + return false; + + if(!variableSampleTest()) + return false; + + return true; +} + +bool fixedSampleTest() +{ + //Simulate some data to send to the filter + vector streamIn,streamOut; + IonStreamData *d= new IonStreamData; + + const unsigned int NUM_PTS=10000; + for(unsigned int ui=0;uidata.push_back(h); + } + + + streamIn.push_back(d); + //Set up the filter itself + IonDownsampleFilter *f=new IonDownsampleFilter; + f->setCaching(false); + + bool needUp; + string s; + unsigned int numOutput=NUM_PTS/10; + + TEST(f->setProperty(KEY_IONDOWNSAMPLE_FIXEDOUT,"1",needUp),"Set prop"); + stream_cast(s,numOutput); + TEST(f->setProperty(KEY_IONDOWNSAMPLE_COUNT,s,needUp),"Set prop"); + + //Do the refresh + ProgressData p; + f->refresh(streamIn,streamOut,p,dummyCallback); + + delete f; + delete d; + + //Pass some tests + TEST(streamOut.size() == 1, "Stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "stream type"); + TEST(streamOut[0]->getNumBasicObjects() == numOutput, "output ions (basicobject)"); + TEST( ((IonStreamData*)streamOut[0])->data.size() == numOutput, "output ions (direct)") + + delete streamOut[0]; + + return true; +} + +bool variableSampleTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + unsigned int span[]={ + 5, 7, 9 + }; + const unsigned int NUM_PTS=10000; + IonStreamData *d=synthDataPts(span,NUM_PTS); + + streamIn.push_back(d); + IonDownsampleFilter *f=new IonDownsampleFilter; + f->setCaching(false); + + bool needUp; + TEST(f->setProperty(KEY_IONDOWNSAMPLE_FIXEDOUT,"0",needUp),"Set prop"); + TEST(f->setProperty(KEY_IONDOWNSAMPLE_FRACTION,"0.1",needUp),"Set prop"); + + //Do the refresh + ProgressData p; + TEST(!(f->refresh(streamIn,streamOut,p,dummyCallback)),"refresh error code"); + + delete f; + delete d; + + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + + //It is HIGHLY improbable that it will be <1/10th of the requested number + TEST(streamOut[0]->getNumBasicObjects() > 0.01*NUM_PTS + && streamOut[0]->getNumBasicObjects() <= NUM_PTS,"ion fraction"); + + delete streamOut[0]; + + + return true; +} + +IonStreamData *synthDataPts(unsigned int span[], unsigned int numPts) +{ + IonStreamData *d = new IonStreamData; + + for(unsigned int ui=0;uidata.push_back(h); + } + + return d; +} + +#endif +///----- + diff -Nru 3depict-0.0.12/src/backend/filters/ionDownsample.h 3depict-0.0.13/src/backend/filters/ionDownsample.h --- 3depict-0.0.12/src/backend/filters/ionDownsample.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionDownsample.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * ionDownsample.h - Filter to perform sampling without replacement on input ion data + * 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 . +*/ +#ifndef IONDOWNSAMPLE_H +#define IONDOWNSAMPLE_H + +#include "../filter.h" + +enum +{ + KEY_IONDOWNSAMPLE_FRACTION=1, + KEY_IONDOWNSAMPLE_FIXEDOUT, + KEY_IONDOWNSAMPLE_COUNT, + KEY_IONDOWNSAMPLE_PERSPECIES, + KEY_IONDOWNSAMPLE_ENABLE, + //Dynamic area for this filter class. May validly use any index after this value + KEY_IONDOWNSAMPLE_DYNAMIC, +}; + +//!Random picker filter +class IonDownsampleFilter : public Filter +{ + private: + RandNumGen rng; + //When using fixed number output, maximum to allow out. + size_t maxAfterFilter; + //!Allow only a fixed number at output, alternate is random fraction (binomial dist). + bool fixedNumOut; + //Fraction to output + float fraction; + + + //!Should we use a per-species split or not? + bool perSpecies; + //This is filter's enabled ranges. 0 if we don't have a range + RangeStreamData *rsdIncoming; + + //!Fractions to output for species specific + std::vector ionFractions; + std::vector ionLimits; + public: + IonDownsampleFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + //!Returns FILTER_TYPE_IONDOWNSAMPLE + unsigned int getType() const { return FILTER_TYPE_IONDOWNSAMPLE;}; + //!Initialise filter prior to tree propagation + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + + //!Set mode, fixed num out/approximate out (fraction) + void setControlledOut(bool controlled) {fixedNumOut=controlled;}; + + //!Set the number of ions to generate after the filtering (when using count based fitlering). + void setFilterCount(size_t nMax) { maxAfterFilter=nMax;}; + + //!Get (approx) number of bytes required for cache + virtual size_t numBytesForCache(size_t nObjects) const; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + //!return string naming the human readable type of this class + virtual std::string typeString() const { return std::string(TRANS("Ion Sampler"));} + + + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty( unsigned int key, const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be possibly used during ::refresh + unsigned int getRefreshUseMask() const; + +#ifdef DEBUG + //Fire off the unit tests for this class. returns false if *any* test fails + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/ionInfo.cpp 3depict-0.0.13/src/backend/filters/ionInfo.cpp --- 3depict-0.0.12/src/backend/filters/ionInfo.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionInfo.cpp 2013-04-05 21:38:02.000000000 +0000 @@ -0,0 +1,947 @@ +/* + * ionInfo.cpp -Filter to compute various properties of valued point cloud + * 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 . +*/ +#include "ionInfo.h" + +#include "filterCommon.h" + +enum +{ + VOLUME_MODE_RECTILINEAR=0, + VOLUME_MODE_CONVEX, + VOLUME_MODE_END +}; + +const char *volumeModeString[] = { + NTRANS("Rectilinear"), + NTRANS("Convex hull") + }; + +enum +{ + ERR_NO_MEM, + ERR_USER_ABORT, + ERR_BAD_QHULL +}; + + +bool getRectilinearBounds(const std::vector &dataIn, BoundCube &bound, + unsigned int *progress, unsigned int totalSize,bool (*callback)(bool)) +{ + bound.setInvalid(); + + vector overflow; + + size_t n=0; + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + + const IonStreamData *ions; + ions = ( const IonStreamData *)dataIn[ui]; + n+=ions->data.size(); + BoundCube c; + if(ions->data.size() >1) + { + ions = (const IonStreamData*)dataIn[ui]; + c=getIonDataLimits(ions->data); + + if(c.isValid()) + { + if(bound.isValid()) + bound.expand(c); + else + bound=c; + } + } + else + { + //Do we have single ions in their own + //data structure? if so, they don't have a bound + //on their own, but may have one collectively. + if(ions->data.size()) + overflow.push_back(ions->data[0].getPos()); + } + + *progress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + return false; + } + } + + + //Handle any single ions + if(overflow.size() > 1) + { + BoundCube c; + c.setBounds(overflow); + if(bound.isValid()) + bound.expand(c); + else + bound=c; + } + else if(bound.isValid() && overflow.size() == 1) + bound.expand(overflow[0]); + + return true; +} + +IonInfoFilter::IonInfoFilter() : wantIonCounts(true), wantNormalise(false), + range(0), wantVolume(false), volumeAlgorithm(VOLUME_MODE_RECTILINEAR), + cubeSideLen(1.0f) +{ + cacheOK=false; + cache=true; //By default, we should cache, but decision is made higher up +} + +void IonInfoFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + const RangeStreamData *c=0; + //Determine if we have an incoming range + for (size_t i = 0; i < dataIn.size(); i++) + { + if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE) + { + c=(const RangeStreamData *)dataIn[i]; + + break; + } + } + + //we no longer (or never did) have any incoming ranges. Not much to do + if(!c) + { + //delete the old incoming range pointer + if(range) + delete range; + range=0; + } + else + { + //If we didn't have an incoming rsd, then make one up! + if(!range) + { + range= new RangeStreamData; + *range=*c; + } + else + { + + //OK, so we have a range incoming already (from last time) + //-- the question is, is it the same one we had before ? + //Do a pointer comparison (its a hack, yes, but it should work) + if(range->rangeFile != c->rangeFile) + { + //hmm, it is different. well, trash the old incoming rng + delete range; + + range = new RangeStreamData; + *range=*c; + } + + } + + } + +} + +Filter *IonInfoFilter::cloneUncached() const +{ + IonInfoFilter *p=new IonInfoFilter(); + + p->wantIonCounts=wantIonCounts; + p->wantVolume=wantVolume; + p->wantNormalise=wantNormalise; + p->cubeSideLen=cubeSideLen; + p->volumeAlgorithm=volumeAlgorithm; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + p->wantVolume=wantVolume; + p->volumeAlgorithm=volumeAlgorithm; + return p; +} + +unsigned int IonInfoFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + + //Count the number of ions input + size_t numTotalPoints = numElements(dataIn,STREAM_TYPE_IONS); + size_t numRanged=0; + + + if(!numTotalPoints) + { + consoleOutput.push_back((TRANS("No ions"))); + return 0; + } + + //Compute ion counts/composition as needed + if(wantIonCounts) + { + std::string str; + //Count the number of ions + if(range) + { + vector numIons; + ASSERT(range); + + const RangeFile *r=range->rangeFile; + numIons.resize(r->getNumIons()+1,0); + + //count ions per-species. Add a bin on the end for unranged + for(size_t ui=0;uigetStreamType() != STREAM_TYPE_IONS) + continue; + + const IonStreamData *i; + i = (const IonStreamData *)dataIn[ui]; + + for(size_t uj=0;ujdata.size(); uj++) + { + unsigned int id; + id = r->getIonID(i->data[uj].getMassToCharge()); + if(id != (unsigned int) -1) + numIons[id]++; + else + numIons[numIons.size()-1]++; + } + } + + stream_cast(str,numTotalPoints); + str=std::string(TRANS("--Counts--") ); + consoleOutput.push_back(str); + + size_t totalRanged; + if(wantNormalise) + { + totalRanged=0; + //sum all ions *except* the unranged. + for(size_t ui=0;uigetName(ui)) + std::string("\t") + str; + else + { + //output unranged count + str=std::string(TRANS("Unranged")) + std::string("\t") + str; + } + + consoleOutput.push_back(str); + } + str=std::string("----------"); + consoleOutput.push_back(str); + + + for(size_t ui=0;ui0) + consoleOutput.push_back(string(TRANS("Convex Volume (len^3): ")) + s); + else + consoleOutput.push_back(string(TRANS("Unable to compute volume"))); + + + break; + } + default: + ASSERT(false); + + } + +#ifdef DEBUG + lastVolume=computedVol; +#endif + } + + + //"Pairwise events" - where we perform an action if both + //These + if(wantIonCounts && wantVolume) + { + if(computedVol > sqrt(std::numeric_limits::epsilon())) + { + float density; + std::string s; + + if(range) + { + density=(float)numRanged/computedVol; + stream_cast(s,density); + consoleOutput.push_back(string(TRANS("Ranged Density (pts/vol):")) + s ); + } + + density=(float)numTotalPoints/computedVol; + stream_cast(s,density); + consoleOutput.push_back(string(TRANS("Total Density (pts/vol):")) + s ); + + + } + } + + return 0; +} + +size_t IonInfoFilter::numBytesForCache(size_t nObjects) const +{ + return 0; +} + + +void IonInfoFilter::getProperties(FilterPropGroup &propertyList) const +{ + string str; + FilterProperty p; + size_t curGroup=0; + + vector > choices; + string tmpStr; + + stream_cast(str,wantIonCounts); + p.key=IONINFO_KEY_TOTALS; + if(range) + { + p.name=TRANS("Compositions"); + p.helpText=TRANS("Display compositional data for points in console"); + } + else + { + p.name=TRANS("Counts"); + p.helpText=TRANS("Display count data for points in console"); + } + p.data= str; + p.type=PROPERTY_TYPE_BOOL; + propertyList.addProperty(p,curGroup); + + + if(wantIonCounts && range) + { + stream_cast(str,wantNormalise); + p.name=TRANS("Normalise"); + p.data=str; + p.key=IONINFO_KEY_NORMALISE; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Normalise count data"); + + propertyList.addProperty(p,curGroup); + } + + curGroup++; + + stream_cast(str,wantVolume); + p.key=IONINFO_KEY_VOLUME; + p.name=TRANS("Volume"); + p.data= str; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Compute volume for point data"); + propertyList.addProperty(p,curGroup); + + if(wantVolume) + { + for(unsigned int ui=0;ui &data, + float &volume,bool (*callback)(bool))const +{ + volume=0; + + //TODO: replace with real progress + unsigned int dummyProgress; + unsigned int errCode; + + //Compute the convex hull, leaving the qhull data structure intact + const bool NO_FREE_QHULL=false; + vector hullPts; + if((errCode=computeConvexHull(data,&dummyProgress,callback, + hullPts,NO_FREE_QHULL))) + return errCode; + + Point3D midPt(0,0,0); + + for(size_t ui=0;uisimplicial); + + ui=0; + vertex = (vertexT *)curFac->vertices->e[ui].p; + while(vertex) + { //copy the vertex info into the pt array + (ptArray[ui])[0] = vertex->point[0]; + (ptArray[ui])[1] = vertex->point[1]; + (ptArray[ui])[2] = vertex->point[2]; + + //increment before updating vertex + //to allow checking for NULL termination + ui++; + vertex = (vertexT *)curFac->vertices->e[ui].p; + + } + + //note that this counter has been post incremented. + ASSERT(ui ==3); + volume+=pyramidVol(ptArray,midPt); + + + curFac=curFac->next; + } + + + //Free the convex hull mem + FREE_QHULL(); + + return 0; +} + +bool IonInfoFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool IonInfoFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + using std::string; + string tmpStr; + + xmlChar *xmlString; + //Retrieve user string + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + + //-- + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantioncounts","value")) + return false; + if(tmpStr == "1") + wantIonCounts=true; + else if(tmpStr == "0") + wantIonCounts=false; + else + return false; + //--= + + //-- + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantnormalise","value")) + return false; + if(tmpStr == "1") + wantNormalise=true; + else if(tmpStr == "0") + wantNormalise=false; + else + return false; + //--= + + + //-- + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantvolume","value")) + return false; + if(tmpStr == "1") + wantVolume=true; + else if(tmpStr == "0") + wantVolume=false; + else + return false; + //--= + + //-- + unsigned int tmpInt; + if(!XMLGetNextElemAttrib(nodePtr,tmpInt,"volumealgorithm","value")) + return false; + + if(tmpInt >=VOLUME_MODE_END) + return false; + volumeAlgorithm=tmpInt; + //--= + + //-- + float tmpFloat; + if(!XMLGetNextElemAttrib(nodePtr,tmpFloat,"cubesidelen","value")) + return false; + + if(tmpFloat <= 0.0f) + return false; + cubeSideLen=tmpFloat; + //--= + + + return true; +} + +unsigned int IonInfoFilter::getRefreshBlockMask() const +{ + return STREAMTYPE_MASK_ALL; +} + +unsigned int IonInfoFilter::getRefreshEmitMask() const +{ + return 0; +} + +unsigned int IonInfoFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; +} + +#ifdef DEBUG + +void makeBox(float boxSize,IonStreamData *d) +{ + d->data.clear(); + for(unsigned int ui=0;ui<8;ui++) + { + IonHit h; + float x,y,z; + + x= (float)(ui &1)*boxSize; + y= (float)((ui &2) >> 1)*boxSize; + z= (float)((ui &4) >> 2)*boxSize; + + h.setPos(Point3D(x,y,z)); + h.setMassToCharge(1); + d->data.push_back(h); + } +} +void makeSphereOutline(float radius, float angularStep, + IonStreamData *d) +{ + d->clear(); + ASSERT(angularStep > 0.0f); + unsigned int numAngles=(unsigned int)( 180.0f/angularStep); + + for( unsigned int ui=0; ui0.5 + longit = (float)((int)ui-(int)(numAngles/2))/(float)(numAngles); + //longitude test + longit*=180.0f; + + for( unsigned int uj=0; uj1 + latit = (float)((int)uj)/(float)(numAngles); + latit*=180.0f; + + float x,y,z; + x=radius*cos(longit)*sin(latit); + y=radius*sin(longit)*sin(latit); + z=radius*cos(latit); + + IonHit h; + h.setPos(Point3D(x,y,z)); + h.setMassToCharge(1); + d->data.push_back(h); + } + } +} + +bool volumeBoxTest() +{ + //Construct a few boxes, then test each of their volumes + IonStreamData *d=new IonStreamData(); + + const float SOMEBOX=7.0f; + makeBox(7.0,d); + + + //Construct the filter, and then set up the options we need + IonInfoFilter *f = new IonInfoFilter; + f->setCaching(false); + + //activate volume measurement + bool needUp; + TEST(f->setProperty(IONINFO_KEY_VOLUME,"1",needUp),"Set prop"); + string s; + stream_cast(s,(int)VOLUME_MODE_RECTILINEAR); + + //Can return false if algorithm already selected. Do not + // test return + f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, s,needUp); + + + vector streamIn,streamOut; + streamIn.push_back(d); + + ProgressData p; + f->refresh(streamIn,streamOut,p,dummyCallback); + + //No ions come out of the info + TEST(streamOut.empty(),"stream size test"); + + vector consoleStrings; + f->getConsoleStrings(consoleStrings); + + //weak test for the console string size + TEST(consoleStrings.size(), "console strings existance test"); + + + //Ensure that the rectilinear volume is the same as + // the theoretical value + float volMeasure,volReal;; + volMeasure=f->getLastVolume(); + volReal =SOMEBOX*SOMEBOX*SOMEBOX; + + TEST(fabs(volMeasure -volReal) < + 10.0f*sqrt(std::numeric_limits::epsilon()), + "volume estimation test (rect)"); + + + //Try again, but with convex hull + stream_cast(s,(int)VOLUME_MODE_CONVEX); + f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, s,needUp); + + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback), "refresh"); + volMeasure=f->getLastVolume(); + + TEST(fabs(volMeasure -volReal) < + 10.0f*sqrt(std::numeric_limits::epsilon()), + "volume estimation test (convex)"); + + + + + delete d; + delete f; + return true; +} + +bool volumeSphereTest() +{ + //Construct a few boxes, then test each of their volumes + IonStreamData *d=new IonStreamData(); + + const float OUTLINE_RADIUS=7.0f; + const float ANGULAR_STEP=2.0f; + makeSphereOutline(OUTLINE_RADIUS,ANGULAR_STEP,d); + + //Construct the filter, and then set up the options we need + IonInfoFilter *f = new IonInfoFilter; + f->setCaching(false); + + //activate volume measurement + bool needUp; + TEST(f->setProperty(IONINFO_KEY_VOLUME,"1",needUp),"Set prop"); + + //Can return false if the default algorithm is the same + // as the selected algorithm + f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, + volumeModeString[VOLUME_MODE_RECTILINEAR],needUp); + + + vector streamIn,streamOut; + streamIn.push_back(d); + + ProgressData p; + f->refresh(streamIn,streamOut,p,dummyCallback); + + //No ions come out of the info + TEST(streamOut.empty(),"stream size test"); + + vector consoleStrings; + f->getConsoleStrings(consoleStrings); + + //weak test for the console string size + TEST(consoleStrings.size(), "console strings existance test"); + + + float volMeasure,volReal; + volMeasure=f->getLastVolume(); + //Bounding box for sphere is diameter^3. + volReal =8.0f*OUTLINE_RADIUS*OUTLINE_RADIUS*OUTLINE_RADIUS; + TEST(fabs(volMeasure -volReal) < 0.05*volReal,"volume test (rect est of sphere)"); + + + //Try again, but with convex hull + TEST(f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, + volumeModeString[VOLUME_MODE_CONVEX],needUp),"Set prop"); + + vector dummy; + f->getConsoleStrings(dummy); + + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + + volMeasure=f->getLastVolume(); + + //Convex volume of sphere + 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"); + + delete d; + delete f; + return true; +} + +bool IonInfoFilter::runUnitTests() +{ + if(!volumeBoxTest()) + return false; + + if(!volumeSphereTest()) + return false; + + return true; +} +#endif + diff -Nru 3depict-0.0.12/src/backend/filters/ionInfo.h 3depict-0.0.13/src/backend/filters/ionInfo.h --- 3depict-0.0.12/src/backend/filters/ionInfo.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/ionInfo.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * ionInfo.h -Filter to compute various properties of valued point cloud + * 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 . +*/ +#ifndef IONINFO_H +#define IONINFO_H + +#include "../filter.h" +#include "../../common/translation.h" + +enum +{ + IONINFO_KEY_TOTALS=1, + IONINFO_KEY_NORMALISE, + IONINFO_KEY_VOLUME, + IONINFO_KEY_VOLUME_ALGORITHM, +}; + +//!Ion derived information filter, things like volume, composition, etc. +class IonInfoFilter : public Filter +{ + private: + //!Do we want to know information about the number of ions/composition + bool wantIonCounts; + + //!Do we want to normalise the ion count data? + bool wantNormalise; + + + //!Parent rangefile in tree + RangeStreamData *range; + + //!Do we want to know about the volume + bool wantVolume; + + //!Method for volume computation + unsigned int volumeAlgorithm; + + //Side length for filled cube volume estimation + float cubeSideLen; + +#ifdef DEBUG + float lastVolume; +#endif + + //!String for + size_t volumeEstimationStringFromID(const char *str) const; + + //Convex hull volume estimation routine. + //returns 0 on success. global "qh " "object" will contain + //the hull. Volume is computed. + unsigned int convexHullEstimateVol(const vector &data, + float &vol,bool (*callback)(bool)) const; + public: + //!Constructor + IonInfoFilter(); + + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //Perform filter intialisation, for pre-detection of range data + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + + //!Apply filter to new data, updating cache as needed. Vector + // of returned pointers must be deleted manually, first checking + // ->cached. + unsigned int refresh(const std::vector &dataIn, + std::vector &dataOut, + ProgressData &progress, bool (*callback)(bool)); + //!Get (approx) number of bytes required for cache + size_t numBytesForCache(size_t nObjects) const; + + //!return type ID + unsigned int getType() const { return FILTER_TYPE_IONINFO;} + + //!Return filter type as std::string + std::string typeString() const { return std::string(TRANS("Ion info"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter, + //!needUpdate tells us if filter output changes due to property set + bool setProperty( unsigned int key, + const std::string &value, bool &needUpdate); + + + void setPropFromBinding( const SelectionBinding &b) ; + + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + /* Current supported formats are STATE_FORMAT_XML + */ + bool writeState(std::ostream &f, unsigned int format, + unsigned int depth) const; + + //!Read state from XML stream, using xml format + /* Current supported formats are STATE_FORMAT_XML + */ + bool readState(xmlNodePtr& n, const std::string &packDir=""); + + //!Get the bitmask encoded list of filterStreams that this filter blocks from propagation. + // i.e. if this filterstream is passed to refresh, it is not emitted. + // This MUST always be consistent with ::refresh for filters current state. + unsigned int getRefreshBlockMask() const; + + //!Get the bitmask encoded list of filterstreams that this filter emits from ::refresh. + // This MUST always be consistent with ::refresh for filters current state. + unsigned int getRefreshEmitMask() const; + + //!Get the bitmask encoded list of filterstreams that this filter may use during ::refresh. + unsigned int getRefreshUseMask() const; + +#ifdef DEBUG + bool runUnitTests(); + + //Debugging function only; must be called after refresh. + //Returns the last estimation for volume. + float getLastVolume() { float tmp=lastVolume; lastVolume=0;return tmp; } +#endif +}; + + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/rangeFile.cpp 3depict-0.0.13/src/backend/filters/rangeFile.cpp --- 3depict-0.0.12/src/backend/filters/rangeFile.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/rangeFile.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,1376 @@ +/* + * rangeFile.cpp - bins ions into different value ranges given an input range file + * 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 . +*/ +#include "rangeFile.h" + +#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, +}; + +const unsigned int NUM_ROWS_ION=3; +const unsigned int NUM_ROWS_RANGE=4; +//!Error codes +enum +{ + RANGEFILE_ABORT_FAIL=1, + RANGEFILE_BAD_ALLOC +}; +//== Range File Filter == + +RangeFileFilter::RangeFileFilter() +{ + dropUnranged=true; + assumedFileFormat=RANGE_FORMAT_ORNL; +} + + +Filter *RangeFileFilter::cloneUncached() const +{ + RangeFileFilter *p=new RangeFileFilter(); + p->rng = rng; + p->rngName=rngName; + p->enabledRanges.resize(enabledRanges.size()); + std::copy(enabledRanges.begin(),enabledRanges.end(), + p->enabledRanges.begin()); + p->enabledIons.resize(enabledIons.size()); + std::copy(enabledIons.begin(),enabledIons.end(), + p->enabledIons.begin()); + p->assumedFileFormat=assumedFileFormat; + p->dropUnranged=dropUnranged; + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +void RangeFileFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + //Copy any input, except range files to output + for(size_t ui=0;uigetStreamType() != STREAM_TYPE_RANGE) + dataOut.push_back(dataIn[ui]); + } + + //Create a rangestream data to push through the init phase + if(rng.getNumIons() && rng.getNumRanges()) + { + RangeStreamData *rngData=new RangeStreamData; + rngData->parent=this; + rngData->rangeFile=&rng; + rngData->enabledRanges.resize(enabledRanges.size()); + std::copy(enabledRanges.begin(),enabledRanges.end(),rngData->enabledRanges.begin()); + rngData->enabledIons.resize(enabledIons.size()); + std::copy(enabledIons.begin(),enabledIons.end(),rngData->enabledIons.begin()); + rngData->cached=0; + + dataOut.push_back(rngData); + } + +} + +unsigned int RangeFileFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + + //use the cached copy of the data if we have it. + if(cacheOK) + { + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) + getOut.push_back(dataIn[ui]); + } + + return 0; + } + + vector d; + + //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;uiparent=this; + } + + 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; + + + progress.step=1; + progress.filterProgress=0; + progress.stepName=TRANS("Pre-Allocate"); + progress.maxStep=2; + + vector 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;uigetStreamType()) + { + 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 *dSizeArr = new vector[nT]; + for(unsigned int uk=0;ukdata.size();uj++) + { +#ifdef _OPENMP + 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--) + { +#pragma omp critical + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + curProg=NUM_CALLBACK; + + + if(!(*callback)(false)) + spin=true; + } + } + } + + if(spin) + return RANGEFILE_ABORT_FAIL; +#ifdef _OPENMP + //Merge the arrays back together + for(unsigned int uk=0;ukdata.reserve(dSizes[ui]); + } + catch(std::bad_alloc) + { + for(size_t ui=0;uigetStreamType()) + { + 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::epsilon()); + } + else + { + ionSize=((const IonStreamData *)dataIn[ui])->ionSize; + haveIonSize=true; + } + + unsigned int curProg=NUM_CALLBACK; + const size_t off=d.size()-1; + + for(vector::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); + + //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); + } + + //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;uir=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;uiionSize=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;uidata.size())) + { + delete d[ui]; + std::swap(d[ui],d.back()); + d.pop_back(); + } + else + ui++; + } + + //====================================== + + //Having ranged all streams, merge them back into one ranged stream. + if(cache) + { + for(unsigned int ui=0;uicached=1; //IMPORTANT: ->cached must be set PRIOR to push back + filterOutputs.push_back(d[ui]); + } + } + else + { + for(unsigned int ui=0;uicached=0; //IMPORTANT: ->cached must be set PRIOR to push back + cacheOK=false; + } + + for(unsigned int ui=0;uiparent=this; + rngData->rangeFile=&rng; + + rngData->enabledRanges.resize(enabledRanges.size()); + std::copy(enabledRanges.begin(),enabledRanges.end(),rngData->enabledRanges.begin()); + rngData->enabledIons.resize(enabledIons.size()); + std::copy(enabledIons.begin(),enabledIons.end(),rngData->enabledIons.begin()); + + + rngData->cached=cache; + + if(cache) + filterOutputs.push_back(rngData); + + getOut.push_back(rngData); + + cacheOK=cache; + return 0; +} + +bool RangeFileFilter::updateRng() +{ + if(!rng.openGuessFormat(rngName.c_str())) + return false; + + unsigned int nRng = rng.getNumRanges(); + enabledRanges.resize(nRng); + unsigned int nIon = rng.getNumIons(); + enabledIons.resize(nIon); + //Turn all ranges to "on" + for(unsigned int ui=0;ui thisRange; + thisRange = rng.getRange(ui); + string rangeVal; + stream_cast(rangeVal,thisRange.first); + + prop.name=string(TRANS("Start rng "))+suffix; + 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; + p.addProperty(prop,curGroup); + + stream_cast(rangeVal,thisRange.second); + prop.name=string(TRANS("End rng "))+suffix; + 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; + p.addProperty(prop,curGroup); + } + p.setGroupTitle(curGroup,TRANS("Ranges")); + } + //---- + +} + +bool RangeFileFilter::setProperty(unsigned int key, + const std::string &value, bool &needUpdate) +{ + using std::string; + needUpdate=false; + + + switch(key) + { + case KEY_RANGE_FILENAME: + { + if(value != rngName) + { + std::string tmp; + tmp=rngName; + rngName=value; + + RangeFile tmpRange = rng; + + //Check to see if the new file can actually be opened + if(!updateRng()) + { + rngName=tmp; + rng=tmpRange; + + return false; + } + + needUpdate=true; + + } + else + return false; + + if(needUpdate) + clearCache(); + + break; + } + case KEY_DROP_UNRANGED: //Enable/disable unranged dropping + { + unsigned int valueInt; + if(stream_cast(valueInt,value)) + return false; + + if(valueInt ==0 || valueInt == 1) + { + if((int)dropUnranged!= valueInt) + { + needUpdate=true; + dropUnranged=valueInt; + } + else + needUpdate=false; + } + else + return false; + + if(needUpdate) + clearCache(); + + break; + } + case KEY_ENABLE_ALL_RANGES: + { + + bool allEnable; + if(value == "1") + allEnable=true; + else if ( value == "0") + allEnable=false; + else + return false; + + //set them to the opposite of whatever we have now + //if any single one needs a change, then we need to + //update + for(unsigned int ui=0;ui9 + for(unsigned int ui=0;ui rng.getNumRanges()) + return false; + + rng.setIonID(rangeId,newID); + needUpdate=true; + break; + } + //Range start + case 2: + { + + //Check for valid data type conversion + float newMass; + if(stream_cast(newMass,value)) + return false; + + //Ensure that it has actually changed + if(newMass == rng.getRange(rangeId).first) + return false; + + //Attempt to move the range to a new position + if(!rng.moveRange(rangeId,0,newMass)) + return false; + + needUpdate=true; + + break; + } + //Range end + case 3: + { + + //Check for valid data type conversion + float newMass; + if(stream_cast(newMass,value)) + return false; + + //Ensure that it has actually changed + if(newMass == rng.getRange(rangeId).second) + return false; + + //Attempt to move the range to a new position + if(!rng.moveRange(rangeId,1,newMass)) + return false; + + needUpdate=true; + + break; + } + } + + if(needUpdate) + clearCache(); + } + } + } + + return true; +} + + +std::string RangeFileFilter::getErrString(unsigned int code) const +{ + switch(code) + { + case RANGEFILE_ABORT_FAIL: + return std::string(TRANS("Ranging aborted by user")); + case RANGEFILE_BAD_ALLOC: + return std::string(TRANS("Insufficient memory for range")); + } + + return std::string("BUG(range file filter): Shouldn't see this!"); +} + +void RangeFileFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + +void RangeFileFilter::setFormat(unsigned int format) +{ + ASSERT(format < RANGE_FORMAT_END_OF_ENUM); + + assumedFileFormat=format; +} + +bool RangeFileFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << ""<< endl; + for(unsigned int ui=0;ui" << endl; + } + f << tabs(depth+1) << ""<< endl; + + f << tabs(depth+1) << ""<< endl; + + for(unsigned int ui=0;ui" << endl; + } + f << tabs(depth+1) << ""<< endl; + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + + //Retrieve user string + //== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //== + + //Retrieve file name + //== + //Retrieve file name + if(XMLHelpFwdToElem(nodePtr,"file")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); + if(!xmlString) + return false; + rngName=(char *)xmlString; + xmlFree(xmlString); + + //Override the string, as needed + if( (stateFileDir.size()) && + (rngName.size() > 2 && rngName.substr(0,2) == "./") ) + { + rngName=stateFileDir + rngName.substr(2); + } + + rngName=convertFileStringToNative(rngName); + + //try using the extension name of the file to guess format + if(!rng.openGuessFormat(rngName.c_str())) + return false; + + //== + + std::string tmpStr; + //Retrieve user string + //== + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"dropunranged","value")) + return false; + + if(tmpStr=="1") + dropUnranged=true; + else if(tmpStr=="0") + dropUnranged=false; + else + return false; + + //== + + + //Retrieve enabled ions + //=== + if(XMLHelpFwdToElem(nodePtr,"enabledions")) + return false; + xmlNodePtr tmpNode=nodePtr; + + nodePtr=nodePtr->xmlChildrenNode; + + unsigned int ionID; + bool enabled; + //By default, turn ions off, but use state file to turn them on + enabledIons.resize(rng.getNumIons(),false); + while(!XMLHelpFwdToElem(nodePtr,"ion")) + { + //Get ID value + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"id"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(ionID,tmpStr)) + return false; + + if(ionID>= rng.getNumIons()) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"enabled"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + enabled=false; + else if(tmpStr == "1") + enabled=true; + else + return false; + + enabledIons[ionID]=enabled; + xmlFree(xmlString); + + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"colour"); + if(!xmlString) + return false; + + + tmpStr=(char *)xmlString; + + unsigned char r,g,b,a; + if(!parseColString(tmpStr,r,g,b,a)) + return false; + + RGBf col; + col.red=(float)r/255.0f; + col.green=(float)g/255.0f; + col.blue=(float)b/255.0f; + rng.setColour(ionID,col); + xmlFree(xmlString); + } + + //=== + + + nodePtr=tmpNode; + //Retrieve enabled ranges + //=== + if(XMLHelpFwdToElem(nodePtr,"enabledranges")) + return false; + tmpNode=nodePtr; + + nodePtr=nodePtr->xmlChildrenNode; + + //By default, turn ranges off (cause there are lots of them), and use state to turn them on + enabledRanges.resize(rng.getNumRanges(),true); + unsigned int rngID; + while(!XMLHelpFwdToElem(nodePtr,"range")) + { + //Get ID value + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"id"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(rngID,tmpStr)) + return false; + + if(rngID>= rng.getNumRanges()) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"enabled"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(tmpStr == "0") + enabled=false; + else if(tmpStr == "1") + enabled=true; + else + return false; + + xmlFree(xmlString); + enabledRanges[rngID]=enabled; + } + //=== + + return true; +} + +void RangeFileFilter::getStateOverrides(std::vector &externalAttribs) const +{ + externalAttribs.push_back(rngName); +} + +unsigned int RangeFileFilter::getRefreshBlockMask() const +{ + return STREAM_TYPE_RANGE | STREAM_TYPE_IONS ; +} + +unsigned int RangeFileFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_RANGE | STREAM_TYPE_IONS ; +} + +unsigned int RangeFileFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS ; +} + +void RangeFileFilter::setPropFromRegion(unsigned int method, unsigned int regionID, float newPos) +{ + ASSERT(regionID < rng.getNumRanges()); + + unsigned int rangeID = regionID; + + switch(method) + { + case REGION_MOVE_EXTEND_XMINUS: + rng.moveRange(rangeID,false, newPos); + break; + case REGION_MOVE_TRANSLATE_X: + { + std::pair limits; + limits=rng.getRange(rangeID); + float delta; + delta = (limits.second-limits.first)/2; + rng.moveBothRanges(rangeID,newPos-delta,newPos+delta); + break; + } + case REGION_MOVE_EXTEND_XPLUS: + rng.moveRange(rangeID,true, newPos); + break; + default: + ASSERT(false); + } + + clearCache(); +} + +bool RangeFileFilter::writePackageState(std::ostream &f, unsigned int format, + const std::vector &valueOverrides, unsigned int depth) const +{ + ASSERT(valueOverrides.size() == 1); + + //Temporarily modify the state of the filter, then call writestate + string tmpFilename=rngName; + + + //override const -- naughty, but we know what we are doing... + const_cast(this)->rngName=valueOverrides[0]; + bool result; + result=writeState(f,format,depth); + const_cast(this)->rngName=tmpFilename; + + return result; +} + +#ifdef DEBUG + +bool testRanged(); +//bool testRangeWithOnOffs(); +bool testUnranged(); + +bool RangeFileFilter::runUnitTests() +{ + if(!testRanged()) + return false; + + return true; +} + +bool testUnranged() +{ + return true; +} + +bool testRanged() +{ + vector streamIn,streamOut; + //Synthesise data + //----- + IonStreamData *d = new IonStreamData; + + IonHit h; + h.setPos(Point3D(1,1,1)); + + for(unsigned int ui=0;ui<100; ui++) + { + h.setMassToCharge(ui); + d->data.push_back(h); + } + + streamIn.push_back(d); + + //Now build some range data + RangeFile rng; + + //Insert *non overlapping* ranges. + const unsigned int NUM[]={10,14}; + const unsigned int OFFSET[]={0,20}; + string longName,shortName; + + RGBf col; + col.red=col.green=col.blue=1; + shortName="Bl"; longName="Blahium"; + unsigned int ionID; + ionID=rng.addIon(shortName,longName,col); + rng.addRange((float)OFFSET[0],(float)(OFFSET[0]+NUM[0]-1),ionID); + + shortName="Pl"; longName="Palatherum"; + ionID=rng.addIon(shortName,longName,col); + rng.addRange((float)OFFSET[1],(float)(OFFSET[1]+NUM[1]-1),ionID); + + //----- + + //Run the range filter + //-- + RangeFileFilter *r = new RangeFileFilter; + r->setCaching(false); + r->setRangeData(rng); + + //Run the initialisation stage + ProgressData prog; + TEST(!r->refresh(streamIn,streamOut,prog,dummyCallback),"Refresh error code"); + //-- + + //Run the tests + //--- + vector numIons; + for(unsigned int ui=0; uigetStreamType() == STREAM_TYPE_IONS) + { + numIons.push_back(streamOut[ui]->getNumBasicObjects()); + const IonStreamData *dI; + dI = (IonStreamData*)streamOut[ui]; + for(unsigned int uj=0;ujdata[uj].getMassToCharge()), + "Range containment"); + } + } + + } + + //Ion stream output - ranges + unranged + TEST(numIons.size() == 2, "Ranged ionstream count"); + TEST(std::find(numIons.begin(),numIons.end(),NUM[0]) + != numIons.end(), "ion count test (1)"); + TEST(std::find(numIons.begin(),numIons.end(),NUM[1]) + != numIons.end(), "ion count test (2)"); + + for(unsigned int uj=0;uj. +*/ +#ifndef RANGEFILE_H +#define RANGEFILE_H + +#include "../filter.h" +#include "../../common/translation.h" + + +//!Range file filter +class RangeFileFilter : public Filter +{ + private: + std::string rngName; + //!Vector of chars stating if user has enabled a particular vector or not + std::vector enabledRanges; + //!Vector of chars stating if user has enabled a particular Ion or not. + std::vector enabledIons; + + //!Whether to drop unranged ions in our output + bool dropUnranged; + + //!Assumed file format when loading. + unsigned int assumedFileFormat; + + void guessFormat(const std::string &s); + + //!range file object + RangeFile rng; + + public: + const RangeFile &getRange() const { return rng;}; + + //!Set the format to assume when loading file + void setFormat(unsigned int format); + + std::vector getEnabledRanges() const {return enabledRanges;}; + void setEnabledRanges(vector i) {enabledRanges = i;}; + + + RangeFileFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + void setRangeFilename(std::string filename){rngName=filename;}; + + //!Returns -1, as range file cache size is dependant upon input. + virtual size_t numBytesForCache(size_t nObjects) const; + //!Returns FILTER_TYPE_RANGEFILE + unsigned int getType() const { return FILTER_TYPE_RANGEFILE;}; + + //!Propagates a range stream data through the filter init stage. Blocks any other range stream datas + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + //!Force a re-read of the rangefile, returning false on failure, true on success + bool updateRng(); + + //!Set the internal data using the specified range object + void setRangeData(const RangeFile &newRange); + + virtual std::string typeString() const { return std::string(TRANS("Ranging"));}; + + //Types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //Types that are emitted by filer during ::refrash + unsigned int getRefreshEmitMask() const; + + //Types that are possibly used by filer during ::refrash + unsigned int getRefreshUseMask() const; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + + //!Set a region update + virtual void setPropFromRegion(unsigned int method, unsigned int regionID, float newPos); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + + //!Modified version of writeState for packaging. By default simply calls writeState. + //value overrides override the values returned by getStateOverrides. In order. + virtual bool writePackageState(std::ostream &f, unsigned int format, + const std::vector &valueOverrides,unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!filter has state overrides + virtual void getStateOverrides(std::vector &overrides) const; + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + +#ifdef DEBUG + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/rdf.cpp 3depict-0.0.13/src/backend/filters/rdf.cpp --- 3depict-0.0.12/src/backend/filters/rdf.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/rdf.cpp 2013-04-10 20:35:09.000000000 +0000 @@ -0,0 +1,1005 @@ + /* + * rdf.cpp - Radial distribution function implentation + * 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 . + */ + +#include "rdf.h" + +#include "filterCommon.h" + +using std::vector; + +#ifdef _OPENMP +#include +#endif +//QHull library +//Build fix for qhull ; wx defines powerpc without +//assigning a value, causing build fail on powerpc +#ifdef __POWERPC__ + #pragma push_macro("__POWERPC__") + #define __POWERPC__ 1 +#endif +extern "C" +{ + #include +} +#ifdef __POWERPC__ + #pragma pop_macro("__POWERPC__") +#endif + +const unsigned int CALLBACK_REDUCE=5000; + +enum PointDir{ POINTDIR_TOGETHER =0, + POINTDIR_IN_COMMON, + POINTDIR_APART + }; +//!Check which way vectors attached to two 3D points "point", +/*! Two vectors may point "together", /__\ "apart" \__/ or + * "In common" /__/ or \__\ + */ +unsigned int vectorPointDir(const Point3D &pA, const Point3D &pB, + const Point3D &vC, const Point3D &vD) +{ + //Check which way vectors attached to two 3D points "point", + // - "together", "apart" or "in common" + + //calculate AB.CA, BA.DB + float dot1 = (pB-pA).dotProd(vC - pA); + float dot2= (pA - pB).dotProd(vD - pB); + + //We shall somewhat arbitrarily call perpendicular cases "together" + if(dot1 ==0.0f || dot2 == 0.0f) + return POINTDIR_TOGETHER; + + //If they have opposite signs, then they are "in common" + if(( dot1 < 0.0f && dot2 > 0.0f) || (dot1 > 0.0f && dot2 < 0.0f) ) + return POINTDIR_IN_COMMON; + + if( dot1 < 0.0f && dot2 <0.0f ) + return POINTDIR_APART; + + ASSERT(dot1 > 0.0f && dot2 > 0.0f ); + + return POINTDIR_TOGETHER; +} + +//! Returns the shortest distance between a line segment and a given point +/* The inputs are the ends of the line segment and the point. Uses the formula that + * \f$ + * D = \abs{\vec{PE}}\f$ + * \f[ + * \mathrm{~if~} \vec{PA} \cdot \vec{AB} > 0 + * \rightarrow \vec{PE} = \vec{A} + * \f] + * \f[ + * \mathrm{~if~} \vec{AB} \cdot \vec{PB} > 0 ~\&~ \vec{PA} \cdot \vec{AB} < 0 + * \rightarrow \vec{PB} \cdot \frac{\vec{AB}}{\abs{\vec{AB}}} + * \f] + * \f[ + * \mathrm{~if~} \vec{PB} \cdot \vec{AB} < 0 + * \rightarrow \vec{B} + * \f] + */ +float distanceToSegment(const Point3D &fA, const Point3D &fB, const Point3D &p) +{ + + //If the vectors a pointing "together" then use point-line formula + if(vectorPointDir(fA,fB,p,p) == POINTDIR_TOGETHER) + { + Point3D closestPt; + Point3D vAB= fB-fA; + + //Use formula d^2 = |(B-A)(cross)(A-P)|^2/|B-A|^2 + return sqrtf( (vAB.crossProd(fA-p)).sqrMag()/(vAB.sqrMag())); + } + + return sqrtf( std::min(fB.sqrDist(p), fA.sqrDist(p)) ); +} + + +//!Find the distance between a point, and a triangular facet -- may be positive or negative +/* The inputs are the facet points (ABC) and the point P. + * distance is shortest using standard plane version + * \f$ D = \vec{AB} \cdot \vec{n} \f$ + * iff dot products to each combination of \f$ \left( AP,BP,CP \right) \leq 0 \f$ + * otherwise closest point is on the boundary of the simplex. + * tested by shortest distance to each line segment (E is shortest pt. AB is line segement) + * \f$ \vec{E} = \frac{\vec{AB}}{|\vec{AB}|} + * ( \vec{PB} \cdot \vec{AB})\f$ + */ +float distanceToFacet(const Point3D &fA, const Point3D &fB, + const Point3D &fC, const Point3D &p, const Point3D &normal) +{ + + //This will check the magnitude of the incoming normal + ASSERT( fabs(sqrtf(normal.sqrMag()) - 1.0f) < 2.0* std::numeric_limits::epsilon()); + unsigned int pointDir[3]; + pointDir[0] = vectorPointDir(fA,fB,p,p); + pointDir[1] = vectorPointDir(fA,fC,p,p); + pointDir[2] = vectorPointDir(fB,fC,p,p); + + //They can never be "APART" if the + //vectors point to the same pt + ASSERT(pointDir[0] != POINTDIR_APART); + ASSERT(pointDir[1] != POINTDIR_APART); + ASSERT(pointDir[2] != POINTDIR_APART); + + //Check to see if any of them are "in common" + if(pointDir[0] > 0 || pointDir[1] >0 || pointDir[2] > 0) + { + //if so, we have to check each edge for its closest point + //then pick the best + float bestDist[3]; + bestDist[0] = distanceToSegment(fA,fB,p); + bestDist[1] = distanceToSegment(fA,fC,p); + bestDist[2] = distanceToSegment(fB,fC,p); + + + return std::min(bestDist[0],std::min(bestDist[1],bestDist[2])); + } + + float temp; + + temp = fabs((p-fA).dotProd(normal)); + + //check that the other points were not better than this! + ASSERT(sqrtf(fA.sqrDist(p)) >= temp - std::numeric_limits::epsilon()); + ASSERT(sqrtf(fB.sqrDist(p)) >= temp - std::numeric_limits::epsilon()); + ASSERT(sqrtf(fC.sqrDist(p)) >= temp - std::numeric_limits::epsilon()); + + //Point lies above/below facet, use plane formula + return temp; +} + + +//A bigger MAX_NN_DISTS is better because you will attempt to grab more ram +//however there is a chance that memory allocation can fail, which currently I do not grab safely +const unsigned int MAX_NN_DISTS = 0x8000000; //96 MB samples at a time + + + +//obtains all the input points from ions that lie inside the convex hull after +//it has been shrunk such that the closest distance from the hull to the original data +//is reductionDim +unsigned int GetReducedHullPts(const vector &points, float reductionDim, + unsigned int *progress, bool (*callback)(bool), vector &pointResult) +{ + //TODO: This could be made to use a fixed amount of ram, by + //partitioning the input points, and then + //computing multiple hulls. + //Take the resultant hull points, then hull again. This would be + //much more space efficient, and more easily parallellised + //Alternately, compute a for a randoms K set of points, and reject + //points that lie in the hull from further computation + + //Need at least 4 points to define a hull in 3D + if(points.size() < 4) + return 1; + + unsigned int dummyProg; + vector theHull; + if(computeConvexHull(points,progress,callback,theHull,false)) + return 2; + + Point3D midPoint(0,0,0); + for(size_t ui=0;uisimplicial); + vertex = (vertexT *)curFac->vertices->e[ui].p; + while(vertex) + { //copy the vertex info into the pt array + (ptArray[ui])[0] = vertex->point[0]; + (ptArray[ui])[1] = vertex->point[1]; + (ptArray[ui])[2] = vertex->point[2]; + + //aggregate pyramidal points + pyramidCentroid += ptArray[ui]; + + //increment before updating vertex + //to allow checking for NULL termination + ui++; + vertex = (vertexT *)curFac->vertices->e[ui].p; + + } + + //note that this counter has been post incremented. + ASSERT(ui ==3); + vol = pyramidVol(ptArray,midPoint); + + ASSERT(vol>=0); + + //Find the midpoint of the pyramid, this will be the + //same as its centre of mass. + pyramidCentroid*= 0.25f; + hullCentroid = hullCentroid + (pyramidCentroid*vol); + massPyramids+=vol; + + curFac=curFac->next; + } + + hullCentroid *= 1.0f/massPyramids; + + float minDist=std::numeric_limits::max(); + //find the smallest distance between the centroid and the + //convex hull + curFac=qh facet_list; + while(curFac != qh facet_tail) + { + float temp; + Point3D vertexPt[3]; + + //The shortest distance from the plane to the point + //is the dot product of the UNIT normal with + //A-B, where B is on plane, A is point in question + for(unsigned int ui=0; ui<3; ui++) + { + vertexT *vertex; + //grab vertex + vertex = ((vertexT *)curFac->vertices->e[ui].p); + vertexPt[ui] = Point3D(vertex->point[0],vertex->point[1],vertex->point[2]); + } + + //Find the distance between hull centroid and a given facet + temp = distanceToFacet(vertexPt[0],vertexPt[1],vertexPt[2],hullCentroid, + Point3D(curFac->normal[0],curFac->normal[1],curFac->normal[2])); + + if(temp < minDist) + minDist = temp; + + curFac=curFac->next; + } + + //shrink the convex hull such that it lies at + //least reductionDim from the original surface of + //the convex hull + float scaleFactor; + scaleFactor = 1 - reductionDim/ minDist; + + if(scaleFactor < 0.0f) + return RDF_ERR_NEGATIVE_SCALE_FACT; + + + //now scan through the input points and see if they + //lie in the reduced convex hull + vertexT *vertex = qh vertex_list; + + unsigned int ui=0; + while(vertex !=qh vertex_tail) + { + //Translate around hullCentroid before scaling, + //then undo translation after scale + //Modify the vertex data such that it is scaled around the hullCentroid + vertex->point[0] = (vertex->point[0] - hullCentroid[0])*scaleFactor + hullCentroid[0]; + vertex->point[1] = (vertex->point[1] - hullCentroid[1])*scaleFactor + hullCentroid[1]; + vertex->point[2] = (vertex->point[2] - hullCentroid[2])*scaleFactor + hullCentroid[2]; + + vertex = vertex->next; + ui++; + } + + //if the dot product of the normal with the point vector of the + //considered point P, to any vertex on all of the facets of the + //convex hull F1, F2, ... , Fn is negative, + //then P does NOT lie inside the convex hull. + pointResult.reserve(points.size()/2); + curFac = qh facet_list; + + //minimum distance from centroid to convex hull + for(unsigned int ui=points.size(); ui--;) + { + float fX,fY,fZ; + double *ptArr,*normalArr; + fX =points[ui][0]; + fY = points[ui][1]; + fZ = points[ui][2]; + + //loop through the facets + curFac = qh facet_list; + while(curFac != qh facet_tail) + { + //Dont ask. It just grabs the first coords of the vertex + //associated with this facet + ptArr = ((vertexT *)curFac->vertices->e[0].p)->point; + + normalArr = curFac->normal; + //if the dotproduct is negative, then the point vector from the + //point in question to the surface is in opposite to the outwards facing + //normal, which means the point lies outside the hull + if (dotProduct( (float)ptArr[0] - fX, + (float)ptArr[1] - fY, + (float)ptArr[2] - fZ, + normalArr[0], normalArr[1], + normalArr[2]) >= 0) + { + curFac=curFac->next; + continue; + } + goto reduced_loop_next; + } + //we passed all tests, point is inside convex hull + pointResult.push_back(points[ui]); + +reduced_loop_next: + ; + } + + FREE_QHULL(); + + return 0; +} + +//!Generate an NN histogram using NN-max cutoffs +unsigned int generateNNHist( const vector &pointList, + const K3DTree &tree,unsigned int nnMax, unsigned int numBins, + vector > &histogram, float *binWidth , unsigned int *progressPtr, + bool (*callback)(bool)) +{ + if(pointList.size() <=nnMax) + return RDF_ERR_INSUFFICIENT_INPUT_POINTS; + + //Disallow exact matching for NNs + float deadDistSqr; + deadDistSqr= std::numeric_limits::epsilon(); + + //calclate NNs + BoundCube cube; + cube.setBounds(pointList); + + //Allocate and assign the initial max distances + float *maxSqrDist= new float[nnMax]; + for(unsigned int ui=0; ui nnPoints; + tree.findKNearest(pointList[ui],cube, + nnMax,nnPoints,deadDistSqr); + + + + for(unsigned int uj=0; ujsqrDist(pointList[ui]); + if(temp > maxSqrDist[uj]) + maxSqrDist[uj] = temp; + } + + + //Callbacks to perform UI updates as needed + if(!(callbackReduce--)) + { +#ifdef _OPENMP + #pragma omp critical + { + numAnalysed+=CALLBACK_REDUCE; + *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + spin=true; + } +#else + *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*50.0f); + if(!(*callback)(false)) + { + delete[] maxSqrDist; + return RDF_ABORT_FAIL; + } +#endif + callbackReduce=CALLBACK_REDUCE; + } + + } +#ifdef _OPENMP + if(spin) + { + delete[] maxSqrDist; + return RDF_ABORT_FAIL; + } +#endif + + + float maxOfMaxDists=0; + float *maxDist=new float[nnMax]; + for(unsigned int ui=0; ui nnPoints; +#ifdef _OPENMP + if(spin) + continue; +#endif + + tree.findKNearest(pointList[ui],cube, + nnMax, nnPoints); + + for(unsigned int uj=0; ujsqrDist(pointList[ui])); + offsetTemp = (unsigned int)(temp/binWidth[uj]); + + //Prevent overflow due to temp/binWidth exceeding array dimension + //as (temp is <= binwidth, not < binWidth) + if(offsetTemp == numBins) + offsetTemp--; + ASSERT(offsetTemp < nnMax*numBins); + + (histogram[uj])[offsetTemp]++; + } + + + //Callbacks to perform UI updates as needed +#ifdef _OPENMP + if(!(callbackReduce--)) + { + #pragma omp critical + { + *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*50.0f + 50.0f); + if(!(*callback)(false)) + spin=true; + numAnalysed+=CALLBACK_REDUCE; + } + callbackReduce=CALLBACK_REDUCE; + } +#else + if(!(callbackReduce--)) + { + *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*50.0f + 50.0f); + if(!(*callback)(false)) + { + delete[] maxSqrDist; + return RDF_ABORT_FAIL; + } + callbackReduce=CALLBACK_REDUCE; + } +#endif + } + delete[] maxSqrDist; + +#ifdef _OPENMP + if(spin) + return RDF_ABORT_FAIL; +#endif + + return 0; +} + + +unsigned int generate1DAxialDistHist(const vector &pointList, const K3DTree &tree, + const Point3D &axisDir, unsigned int *histogram, float distMax, unsigned int numBins, + unsigned int *progressPtr, bool (*callback)(bool)) +{ + ASSERT(fabs(axisDir.sqrMag() -1.0f) < sqrt(std::numeric_limits::epsilon())); +#ifdef DEBUG + for(unsigned int ui=0;ui epsilon + deadDistSqr=std::numeric_limits::epsilon(); + sqrDist=0; + sourcePoint=pointList[ui]; + while(deadDistSqr < maxSqrDist) + { + + //Grab the nearest point + nearPt = tree.findNearest(sourcePoint, cube, + deadDistSqr); + + if(nearPt) + { + //Cacluate the sq of the distance to the point + sqrDist = nearPt->sqrDist(sourcePoint); + + //if sqrDist is = maxSqrdist then this will cause + //the histogram indexing to trash alternate memory + //- this is bad - prevent this please. + if(sqrDist < maxSqrDist) + { + //Compute the projection of + // the point onto the axis of the + // primary analysis direction + float distance; + distance=(*nearPt-sourcePoint).dotProd(axisDir); + + //update the histogram with the new position. + // centre of the distribution function lies at the analysis point, + // and can be either negative or positive. + // Shift the zero to the center of the histogram + int offset=(int)(((0.5f*distance)/distMax+0.5f)*(float)numBins); + if(offset < (int)numBins && offset >=0) + { +#pragma omp critical + histogram[offset]++; + } + } + + //increase the dead distance to the last distance + deadDistSqr = sqrDist+std::numeric_limits::epsilon(); + } + else + { + //Oh no, we had a problem, somehow we couldn't find enough +#pragma omp critical + warnBiasCount++; + break; + } + + } + + + //Run callbacks as needed + if(!(callbackReduce--)) + { +#pragma omp critical + { + numAnalysed+=CALLBACK_REDUCE_VAL; + *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + { +#ifdef _OPENMP + spin=true; +#else + return RDF_ABORT_FAIL; +#endif + } + } + callbackReduce=CALLBACK_REDUCE_VAL; + } + + } +#ifdef _OPENMP + if(spin) + return RDF_ABORT_FAIL; +#endif + *progressPtr=100; + return 0; +} + + +unsigned int generate1DAxialNNHist(const vector &pointList, const K3DTree &tree, + const Point3D &axisDir, unsigned int *histogram, float &binWidth, unsigned int nnMax, unsigned int numBins, + unsigned int *progressPtr, bool (*callback)(bool)) +{ +#ifdef DEBUG + for(unsigned int ui=0;ui::epsilon(); + + //calclate NNs + BoundCube cube; + cube.setBounds(pointList); + + //Allocate and assign the initial max distances + float *maxAxialDist= new float[nnMax]; + for(unsigned int ui=0; ui nnPoints; + tree.findKNearest(pointList[ui],cube, + nnMax,nnPoints,deadDistSqr); + + for(unsigned int uj=0; uj maxAxialDist[uj]) + maxAxialDist[uj] = temp; + } + + + //Callbacks to perform UI updates as needed + if(!(callbackReduce--)) + { +#ifdef _OPENMP + #pragma omp critical + { + numAnalysed+=CALLBACK_REDUCE; + *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + spin=true; + } +#else + *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + { + delete[] maxAxialDist; + return RDF_ABORT_FAIL; + } +#endif + callbackReduce=CALLBACK_REDUCE; + } + + } +#ifdef _OPENMP + if(spin) + { + delete[] maxAxialDist; + return RDF_ABORT_FAIL; + } +#endif + + + float maxOfMaxDists=0; + for(unsigned int ui=0; ui nnPoints; +#ifdef _OPENMP + if(spin) + continue; +#endif + + tree.findKNearest(pointList[ui],cube, + nnMax, nnPoints); + + for(unsigned int uj=0; uj=0) + { + //TODO: OpenMP could use multiple histograms + // rather than locking +#pragma omp critical + histogram[offset]++; + } + } + + + //Callbacks to perform UI updates as needed +#ifdef _OPENMP + if(!(callbackReduce--)) + { + #pragma omp critical + { + *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + spin=true; + numAnalysed+=CALLBACK_REDUCE; + } + callbackReduce=CALLBACK_REDUCE; + } +#else + if(!(callbackReduce--)) + { + *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + { + delete[] maxAxialDist; + return RDF_ABORT_FAIL; + } + callbackReduce=CALLBACK_REDUCE; + } +#endif + } + delete[] maxAxialDist; + +#ifdef _OPENMP + if(spin) + return RDF_ABORT_FAIL; +#endif + + return 0; +} + + +//!Generate an NN histogram using distance max cutoffs. Input histogram must be zeroed, +unsigned int generateDistHist(const vector &pointList, const K3DTree &tree, + unsigned int *histogram, float distMax, + unsigned int numBins, unsigned int &warnBiasCount, + unsigned int *progressPtr,bool (*callback)(bool)) +{ + + +#ifdef DEBUG + for(unsigned int ui=0;ui epsilon + deadDistSqr=std::numeric_limits::epsilon(); + sqrDist=0; + sourcePoint=pointList[ui]; + while(deadDistSqr < maxSqrDist) + { + + //Grab the nearest point + nearPt = tree.findNearest(sourcePoint, cube, + deadDistSqr); + + if(nearPt) + { + //Cacluate the sq of the distance to the point + sqrDist = nearPt->sqrDist(sourcePoint); + + //if sqrDist is = maxSqrdist then this will cause + //the histogram indexing to trash alternate memory + //- this is bad - prevent this please. + if(sqrDist < maxSqrDist) + { + //Add the point to the histogram +#ifdef _OPENMP + threadHist[(size_t) ((sqrtf(sqrDist/maxSqrDist)*(float)numBins))] [omp_get_thread_num()]++; +#else + histogram[(size_t)((sqrtf(sqrDist/maxSqrDist)*(float)numBins))]++; +#endif + } + + //increase the dead distance to the last distance + deadDistSqr = sqrDist+std::numeric_limits::epsilon(); + } + else + { + //Oh no, we had a problem, somehow we couldn't find enough +#pragma omp critical + warnBiasCount++; + break; + } + + + if(!(callbackReduce--)) + { +#ifdef _OPENMP + #pragma omp critical + { + numAnalysed+=numAnalysedThread; + *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + spin=true; + } + if(spin) + break; + numAnalysedThread=0; +#else + *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*100.0f); + if(!(*callback)(false)) + return RDF_ABORT_FAIL; +#endif + callbackReduce=CALLBACK_REDUCE; + } + } +#ifdef _OPENMP + numAnalysedThread++; +#endif + } + +#ifdef _OPENMP + if(spin) + return RDF_ABORT_FAIL; + + for (size_t i = 0; i < numBins; i++) + { + for (size_t j = 0; j < omp_get_max_threads(); j++) + histogram[i] += threadHist[i][j]; + } +#endif + + //Calculations complete! + return 0; +} diff -Nru 3depict-0.0.12/src/backend/filters/rdf.h 3depict-0.0.13/src/backend/filters/rdf.h --- 3depict-0.0.12/src/backend/filters/rdf.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/rdf.h 2013-03-22 20:24:41.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * rdf.h - Radial distribution function implementation 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 . + */ + +#ifndef RDF_H +#define RDF_H + +#include "K3DTree.h" + + +//RDF error codes +enum +{ + RDF_ERR_NEGATIVE_SCALE_FACT=1, + RDF_ERR_INSUFFICIENT_INPUT_POINTS, + RDF_FILE_OPEN_FAIL, + RDF_ABORT_FAIL +}; + +//!Generate the NN histogram specified up to a given NN +unsigned int generateNNHist( const std::vector &pointList, + const K3DTree &tree,unsigned int nnMax, unsigned int numBins, + std::vector > &histogram, float *binWidth, + unsigned int *progressPtr,bool (*callback)(bool)); + +//!Generate an NN histogram using distance max cutoffs. Input histogram must be zeroed, +//if a voxelsname is given, a 3D RDF will be recorded. in this case voxelBins must be nonzero +unsigned int generateDistHist(const std::vector &pointList, const K3DTree &tree, + unsigned int *histogram, float distMax, + unsigned int numBins, unsigned int &warnBiasCount, + unsigned int *progressPtr,bool (*callback)(bool)); + +//!Returns a subset of points guaranteed to lie at least reductionDim inside hull of input points +/*! Calculates the hull of the input ions and then scales the hull such that the + * smallest distance between the scaled hull and the original hull is exactly + * reductionDim + */ +unsigned int GetReducedHullPts(const std::vector &pts, float reductionDim, + unsigned int *progress, bool (callback)(bool),std::vector &returnIons ); + + +//Return a 1D histogram of NN frequencies, by projecting the NNs within a given search onto a specified axis, stopping at some fixed sstance +// radius onto a specified vector prior to histogram summation. +// - axisDir must be normalised. +unsigned int generate1DAxialDistHist(const std::vector &pointList, const K3DTree &tree, + const Point3D &axisDir, unsigned int *histogram, float distMax, unsigned int numBins, + unsigned int *progressPtr, bool (*callback)(bool)); + + +//Generate a 1D distribution of NN distances s projected onto a specified axis +// Inputs are the axis to project onto, a prezeroed 1D histogram array (size numBIns), +// and the input data points (search src) and tree (search target) +// Outputs are the histogram values , and the bin width for the histogram +unsigned int generate1DAxialNNHist(const std::vector &pointList, const K3DTree &tree, + const Point3D &axisDir, unsigned int *histogram, + float &binWidth, unsigned int nnMax, unsigned int numBins, + unsigned int *progressPtr, bool (*callback)(bool)); +#endif diff -Nru 3depict-0.0.12/src/backend/filters/spatialAnalysis.cpp 3depict-0.0.13/src/backend/filters/spatialAnalysis.cpp --- 3depict-0.0.12/src/backend/filters/spatialAnalysis.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/spatialAnalysis.cpp 2013-04-10 19:22:09.000000000 +0000 @@ -0,0 +1,2929 @@ +/* + * spatialAnalysis.cpp - Perform various data analysis on 3D point clouds + * 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 . +*/ +#include "spatialAnalysis.h" + + + +#include "rdf.h" +#include "geometryHelpers.h" +#include "filterCommon.h" + + + +enum +{ + KEY_STOPMODE, + KEY_ALGORITHM, + KEY_DISTMAX, + KEY_NNMAX, + KEY_NUMBINS, + KEY_REMOVAL, + KEY_REDUCTIONDIST, + KEY_RETAIN_UPPER, + KEY_CUTOFF, + KEY_COLOUR, + KEY_ENABLE_SOURCE, + KEY_ENABLE_TARGET, + KEY_ORIGIN, + KEY_NORMAL, + KEY_RADIUS +}; + +enum { + ALGORITHM_DENSITY, //Local density analysis + ALGORITHM_DENSITY_FILTER, //Local density filtering + ALGORITHM_RDF, //Radial Distribution Function + ALGORITHM_AXIAL_DF, //Axial Distribution Function (aka atomvicinity, sdm, 1D rdf) + ALGORITHM_ENUM_END, +}; + +enum{ + STOP_MODE_NEIGHBOUR, + STOP_MODE_RADIUS, + STOP_MODE_ENUM_END +}; + +//!Error codes +enum +{ + ABORT_ERR=1, + INSUFFICIENT_SIZE_ERR, +}; +// == NN analysis filter == + + +//User visible names for the different algorithms +const char *SPATIAL_ALGORITHMS[] = { + NTRANS("Local Density"), + NTRANS("Density Filtering"), + NTRANS("Radial Distribution"), + NTRANS("Axial Distribution") + }; + +const char *STOP_MODES[] = { + NTRANS("Fixed Neighbour Count"), + NTRANS("Fixed Radius") +}; + +//Switch to determine if algorithms need range propagation or not +const bool WANT_RANGE_PROPAGATION[] = { false, + true, + false, + false + }; + + +//Default distance to use when performing axial distance computations +const float DEFAULT_AXIAL_DISTANCE = 1.0f; + +template +bool xorFunc(const T a, const T b) +{ + return (a || b) && !(a && b); +} + + + +SpatialAnalysisFilter::SpatialAnalysisFilter() +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(STOP_MODES) == STOP_MODE_ENUM_END); + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(SPATIAL_ALGORITHMS) == ALGORITHM_ENUM_END); + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(WANT_RANGE_PROPAGATION) == ALGORITHM_ENUM_END); + algorithm=ALGORITHM_DENSITY; + nnMax=1; + distMax=1; + stopMode=STOP_MODE_NEIGHBOUR; + + haveRangeParent=false; + + //Default colour is red + r=a=1.0f; + g=b=0.0f; + + //RDF params + numBins=100; + excludeSurface=false; + + //Density filtering params + densityCutoff=1.0f; + keepDensityUpper=true; + + reductionDistance=distMax; + + cacheOK=false; + cache=true; //By default, we should cache, but decision is made higher up + +} + +Filter *SpatialAnalysisFilter::cloneUncached() const +{ + SpatialAnalysisFilter *p=new SpatialAnalysisFilter; + + p->r=r; + p->g=g; + p->b=b; + p->a=a; + + p->algorithm=algorithm; + p->stopMode=stopMode; + p->nnMax=nnMax; + p->distMax=distMax; + + p->numBins=numBins; + p->excludeSurface=excludeSurface; + p->reductionDistance=reductionDistance; + + p->keepDensityUpper=keepDensityUpper; + p->densityCutoff=densityCutoff; + + + //We are copying whether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + + p->vectorParams=vectorParams; + p->scalarParams=scalarParams; + + return p; +} + +size_t SpatialAnalysisFilter::numBytesForCache(size_t nObjects) const +{ + return nObjects*IONDATA_SIZE; +} + +void SpatialAnalysisFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + //Check for range file parent + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) + { + const RangeStreamData *r; + r = (const RangeStreamData *)dataIn[ui]; + + if(WANT_RANGE_PROPAGATION[algorithm]) + dataOut.push_back(dataIn[ui]); + + bool different=false; + if(!haveRangeParent) + { + //well, things have changed, we didn't have a + //range parent before. + different=true; + } + else + { + //OK, last time we had a range parent. Check to see + //if the ion names are the same. If they are, keep the + //current bools, iff the ion names are all the same + unsigned int numEnabled=std::count(r->enabledIons.begin(), + r->enabledIons.end(),1); + if(ionNames.size() == numEnabled) + { + unsigned int pos=0; + for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) + { + //Only look at parent-enabled ranges + if(r->enabledIons[uj]) + { + if(r->rangeFile->getName(uj) != ionNames[pos]) + { + different=true; + break; + } + pos++; + } + } + } + } + haveRangeParent=true; + + if(different) + { + //OK, its different. we will have to re-assign, + //but only allow the ranges enabled in the parent filter + ionNames.clear(); + ionNames.reserve(r->rangeFile->getNumRanges()); + for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) + { + + if(r->enabledIons[uj]) + ionNames.push_back(r->rangeFile->getName(uj)); + } + + ionSourceEnabled.resize(ionNames.size(),true); + ionTargetEnabled.resize(ionNames.size(),true); + } + + return; + } + } + haveRangeParent=false; +} + +unsigned int SpatialAnalysisFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + //use the cached copy if we have it. + if(cacheOK) + { + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) + { + //Only propagate ranges if we want range propagation + if(dataIn[ui]->getStreamType() !=STREAM_TYPE_RANGE + || WANT_RANGE_PROPAGATION[algorithm]) + getOut.push_back(dataIn[ui]); + } + } + for(unsigned int ui=0;ui *s; + DrawStreamData *d= new DrawStreamData; + d->parent=this; + d->cached=0; + + createCylinder(d,s); + devices.push_back(s); + getOut.push_back(d); + break; + } + default: + ; + } + return 0; + } + + + //Find out how much total size we need in points vector + size_t totalDataSize=numElements(dataIn,STREAM_TYPE_IONS); + + //Nothing to do, but propagate inputs + if(!totalDataSize) + { + //Propagate any inputs that we don't normally block + for(size_t ui=0;uigetStreamType() & getRefreshBlockMask())) + getOut.push_back(dataIn[ui]); + } + return 0; + } + + const RangeFile *rngF=0; + if(haveRangeParent) + { + //Check we actually have something to do + if(!std::count(ionSourceEnabled.begin(), + ionSourceEnabled.end(),true)) + return 0; + if(!std::count(ionTargetEnabled.begin(), + ionTargetEnabled.end(),true)) + return 0; + + rngF=getRangeFile(dataIn); + } + + + size_t result; + + //Run the algorithm + switch(algorithm) + { + case ALGORITHM_DENSITY: + result=algorithmDensity(progress,callback,totalDataSize, + dataIn,getOut); + break; + case ALGORITHM_RDF: + result=algorithmRDF(progress,callback,totalDataSize, + dataIn,getOut,rngF); + break; + case ALGORITHM_DENSITY_FILTER: + result=algorithmDensityFilter(progress,callback,totalDataSize, + dataIn,getOut); + break; + case ALGORITHM_AXIAL_DF: + result=algorithmAxialDf(progress,callback,totalDataSize, + dataIn,getOut,rngF); + break; + default: + ASSERT(false); + } + + return result; +} + +void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const +{ + FilterProperty p; + size_t curGroup=0; + + string tmpStr; + vector > choices; + + for(unsigned int ui=0;ui=ALGORITHM_ENUM_END) + return false; + + algorithm=ltmp; + resetParamsAsNeeded(); + needUpdate=true; + clearCache(); + + break; + } + case KEY_STOPMODE: + { + switch(algorithm) + { + case ALGORITHM_DENSITY: + case ALGORITHM_DENSITY_FILTER: + case ALGORITHM_RDF: + case ALGORITHM_AXIAL_DF: + { + size_t ltmp=STOP_MODE_ENUM_END; + + for(unsigned int ui=0;ui=STOP_MODE_ENUM_END) + return false; + + stopMode=ltmp; + needUpdate=true; + clearCache(); + break; + } + default: + //Should know what algorithm we use. + ASSERT(false); + break; + } + break; + } + case KEY_DISTMAX: + { + float ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp<= 0.0) + return false; + + distMax=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case KEY_NNMAX: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp==0) + return false; + + nnMax=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case KEY_NUMBINS: + { + unsigned int ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp==0) + return false; + + numBins=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case KEY_REDUCTIONDIST: + { + float ltmp; + if(stream_cast(ltmp,value)) + return false; + + if(ltmp<= 0.0) + return false; + + reductionDistance=ltmp; + needUpdate=true; + clearCache(); + + break; + } + case KEY_REMOVAL: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + bool lastVal=excludeSurface; + excludeSurface=(stripped=="1"); + + //if the result is different, the + //cache should be invalidated + if(lastVal!=excludeSurface) + { + needUpdate=true; + clearCache(); + } + + break; + } + case KEY_COLOUR: + { + unsigned char newR,newG,newB,newA; + + parseColString(value,newR,newG,newB,newA); + + if(newB != b || newR != r || + newG !=g || newA != a) + { + r=newR/255.0; + g=newG/255.0; + b=newB/255.0; + a=newA/255.0; + + if(cacheOK) + { + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + PlotStreamData *p; + p =(PlotStreamData*)filterOutputs[ui]; + + p->r=r; + p->g=g; + p->b=b; + } + } + + } + + needUpdate=true; + } + + + break; + } + case KEY_ENABLE_SOURCE: + { + ASSERT(haveRangeParent); + bool allEnabled=true; + for(unsigned int ui=0;ui=KEY_ENABLE_SOURCE*1000 && + key < KEY_ENABLE_TARGET*1000) + { + size_t offset; + offset = key-KEY_ENABLE_SOURCE*1000; + + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + bool lastVal = ionSourceEnabled[offset]; + + + if(stripped=="1") + ionSourceEnabled[offset]=true; + else + ionSourceEnabled[offset]=false; + + //if the result is different, the + //cache should be invalidated + if(lastVal!=ionSourceEnabled[offset]) + { + needUpdate=true; + clearCache(); + } + + + + } + else if ( key >=KEY_ENABLE_TARGET*1000) + { + size_t offset; + offset = key-KEY_ENABLE_TARGET*1000; + + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + bool lastVal = ionTargetEnabled[offset]; + + + if(stripped=="1") + ionTargetEnabled[offset]=true; + else + ionTargetEnabled[offset]=false; + + //if the result is different, the + //cache should be invalidated + if(lastVal!=ionTargetEnabled[offset]) + { + needUpdate=true; + clearCache(); + } + } + else + { + ASSERT(false); + } + + } + + } + return true; +} + +std::string SpatialAnalysisFilter::getErrString(unsigned int code) const +{ + //Currently the only error is aborting + + + switch(code) + { + case ABORT_ERR: + return std::string(TRANS("Spatial analysis aborted by user")); + case INSUFFICIENT_SIZE_ERR: + return std::string(TRANS("Insufficient data to complete analysis.")); + default: + ASSERT(false); + + } + + return std::string("Bug! (Spatial analysis filter) Shouldn't see this"); +} + +void SpatialAnalysisFilter::setUserString(const std::string &str) +{ + const bool ALGORITHM_HAS_PLOTS[] = { false,false,true,true}; + + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(ALGORITHM_HAS_PLOTS) == ALGORITHM_ENUM_END); + + if(userString != str && ALGORITHM_HAS_PLOTS[algorithm]) + { + userString=str; + clearCache(); + } + else + userString=str; +} + +unsigned int SpatialAnalysisFilter::getRefreshBlockMask() const +{ + //Anything but ions and ranges can go through this filter. + if(!WANT_RANGE_PROPAGATION[algorithm]) + return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; + else + return STREAM_TYPE_IONS; + +} + +unsigned int SpatialAnalysisFilter::getRefreshEmitMask() const +{ + switch(algorithm) + { + case ALGORITHM_RDF: + return STREAM_TYPE_IONS | STREAM_TYPE_PLOT; + case ALGORITHM_AXIAL_DF: + return STREAM_TYPE_IONS | STREAM_TYPE_PLOT | STREAM_TYPE_DRAW; + default: + return STREAM_TYPE_IONS; + } +} + +unsigned int SpatialAnalysisFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS; +} + +bool SpatialAnalysisFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" <" << endl; + f << tabs(depth+1) << "" << endl; + + writeVectorsXML(f,"vectorparams",vectorParams,depth); + writeScalarsXML(f,"scalarparams",scalarParams,depth); + + writeIonsEnabledXML(f,"source",ionSourceEnabled,ionNames,depth); + writeIonsEnabledXML(f,"target",ionTargetEnabled,ionNames,depth); + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool SpatialAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + using std::string; + string tmpStr; + + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Retrieve algorithm + //====== + if(!XMLGetNextElemAttrib(nodePtr,algorithm,"algorithm","value")) + return false; + if(algorithm >=ALGORITHM_ENUM_END) + return false; + //=== + + //Retrieve stop mode + //=== + if(!XMLGetNextElemAttrib(nodePtr,stopMode,"stopmode","value")) + return false; + if(stopMode >=STOP_MODE_ENUM_END) + return false; + //=== + + //Retrieve nnMax val + //====== + if(!XMLGetNextElemAttrib(nodePtr,nnMax,"nnmax","value")) + return false; + if(!nnMax) + return false; + //=== + + //Retrieve distMax val + //====== + if(!XMLGetNextElemAttrib(nodePtr,distMax,"distmax","value")) + return false; + if(distMax <=0.0) + return false; + //=== + + //Retrieve numBins val + //====== + if(!XMLGetNextElemAttrib(nodePtr,numBins,"numbins","value")) + return false; + if(!numBins) + return false; + //=== + + //Retreive exclude surface on/off + //=== + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"excludesurface","value")) + return false; + //check that new value makes sense + if(tmpStr == "1") + excludeSurface=true; + else if( tmpStr == "0") + excludeSurface=false; + else + return false; + //=== + + + //Get reduction distance + //=== + if(!XMLGetNextElemAttrib(nodePtr,reductionDistance,"reductiondistance","value")) + return false; + if(reductionDistance < 0.0f) + return false; + //=== + + //Retrieve colour + //==== + if(XMLHelpFwdToElem(nodePtr,"colour")) + return false; + if(!parseXMLColour(nodePtr,r,g,b,a)) + return false; + //==== + + + //Retrieve density cutoff & upper + if(!XMLGetNextElemAttrib(nodePtr,densityCutoff,"densitycutoff","value")) + return false; + if(densityCutoff< 0.0f) + return false; + + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"keepdensityupper","value")) + return false; + //check that new value makes sense + if(tmpStr == "1") + keepDensityUpper=true; + else if( tmpStr == "0") + keepDensityUpper=false; + else + return false; + + + //FIXME: Earlier versions of the state file <= 1441:adaa3a3daa80 + // do not contain this section, so we must be fault tolerant + // when we bin backwards compatability, do this one too. + xmlNodePtr tmpNode; + + tmpNode=nodePtr; + if(!XMLHelpFwdToElem(nodePtr,"scalarparams")) + readScalarsXML(nodePtr,scalarParams); + nodePtr=tmpNode; + if(!XMLHelpFwdToElem(nodePtr,"vectorparams")) + readVectorsXML(nodePtr,vectorParams); + + resetParamsAsNeeded(); + + return true; +} + +void SpatialAnalysisFilter::setPropFromBinding(const SelectionBinding &b) +{ + + switch(b.getID()) + { + case BINDING_CYLINDER_RADIUS: + b.getValue(scalarParams[0]); + break; + case BINDING_CYLINDER_DIRECTION: + b.getValue(vectorParams[1]); + break; + case BINDING_CYLINDER_ORIGIN: + b.getValue(vectorParams[0]); + break; + default: + ASSERT(false); + } + + clearCache(); +} + +void SpatialAnalysisFilter::resetParamsAsNeeded() +{ + //Perform any needed + // transformations to internal vars + switch(algorithm) + { + case ALGORITHM_AXIAL_DF: + { + if(vectorParams.size() !=2) + { + size_t oldSize=vectorParams.size(); + vectorParams.resize(2); + + if(oldSize== 0) + vectorParams[0]=Point3D(0,0,0); + if(oldSize < 2) + vectorParams[1]=Point3D(0,0,1); + } + + if(scalarParams.size() !=1) + { + size_t oldSize=scalarParams.size(); + scalarParams.resize(1); + if(!oldSize) + scalarParams[0]=DEFAULT_AXIAL_DISTANCE; + } + break; + } + default: + //fall through + ; + } +} +//Scan input datstreams to build a two point vectors, +// one of those with points specified as "target" +// which is a copy of the input points +//Returns 0 on no error, otherwise nonzero +size_t SpatialAnalysisFilter::buildSplitPoints(const vector &dataIn, + ProgressData &progress, size_t totalDataSize, + const RangeFile *rngF, bool (*callback)(bool), + vector &pSource, vector &pTarget + ) const +{ + size_t sizeNeeded[2]; + sizeNeeded[0]=sizeNeeded[1]=0; + + //Presize arrays + for(unsigned int ui=0; uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + unsigned int ionID; + + const IonStreamData *d; + d=((const IonStreamData *)dataIn[ui]); + ionID=getIonstreamIonID(d,rngF); + + if(ionID == (unsigned int)-1) + { + //FIXME: Fallback handling to re-range data + // - this can technically fail for inputs that are + // not homogenously ranged! + break; + } + + if(ionSourceEnabled[ionID]) + sizeNeeded[0]+=d->data.size(); + + if(ionTargetEnabled[ionID]) + sizeNeeded[1]+=d->data.size(); + + break; + } + default: + break; + } + } + + pSource.resize(sizeNeeded[0]); + pTarget.resize(sizeNeeded[1]); + + //Fill arrays + size_t curPos[2]; + curPos[0]=curPos[1]=0; + + for(unsigned int ui=0; uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + unsigned int ionID; + const IonStreamData *d; + d=((const IonStreamData *)dataIn[ui]); + ionID=getIonstreamIonID(d,rngF); + + if(ionID==(unsigned int)(-1)) + break; + + if(ionSourceEnabled[ionID]) + { + if(extendPointVector(pSource,d->data,callback, + progress.filterProgress,curPos[0])) + return ABORT_ERR; + + curPos[0]+=d->data.size(); + } + + if(ionTargetEnabled[ionID]) + { + if(extendPointVector(pTarget,d->data,callback, + progress.filterProgress,curPos[1])) + return ABORT_ERR; + + curPos[1]+=d->data.size(); + } + + break; + } + default: + break; + } + } + +} + +void SpatialAnalysisFilter::filterSelectedRanges(const vector &ions, bool sourceFilter, const RangeFile *rngF, + vector &output) const +{ + ASSERT(rngF); + + if(sourceFilter) + { + for(size_t ui=0;uigetIonID(ions[ui].getMassToCharge()); + if(id == -1) + continue; + if(ionSourceEnabled[id]) + output.push_back(ions[ui]); + } + } + else + { + for(size_t ui=0;uigetIonID(ions[ui].getMassToCharge()); + if(id == -1) + continue; + if(ionTargetEnabled[id]) + output.push_back(ions[ui]); + } + } +} + +//Scan input datastreams to build a single point vector, +// which is a copy of the input points +//Returns 0 on no error, otherwise nonzero +size_t buildMonolithicPoints(const vector &dataIn, + ProgressData &progress, size_t totalDataSize, + bool (*callback)(bool), vector &p) +{ + //Build monolithic point set + //--- + p.resize(totalDataSize); + + size_t dataSize=0; + + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *d; + d=((const IonStreamData *)dataIn[ui]); + + if(extendPointVector(p,d->data, + callback,progress.filterProgress, + dataSize)) + return ABORT_ERR; + + dataSize+=d->data.size(); + } + break; + default: + break; + } + } + //--- + + return 0; +} + +size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut,const RangeFile *rngF) +{ + progress.step=1; + progress.stepName=TRANS("Collate"); + progress.filterProgress=0; + if(excludeSurface) + progress.maxStep=4; + else + progress.maxStep=3; + + if(!(*callback)(true)) + return ABORT_ERR; + + K3DTree kdTree; + kdTree.setCallbackMethod(callback); + kdTree.setProgressPointer(&(progress.filterProgress)); + + //Source points + vector p; + bool needSplitting; + + needSplitting=false; + //We only need to split up the data if we have to + if(std::count(ionSourceEnabled.begin(),ionSourceEnabled.end(),true)!=ionSourceEnabled.size() + || std::count(ionTargetEnabled.begin(),ionTargetEnabled.end(),true)!=ionTargetEnabled.size() ) + needSplitting=true; + + if(haveRangeParent && needSplitting) + { + vector pts[2]; + ASSERT(ionNames.size()); + size_t errCode; + if((errCode=buildSplitPoints(dataIn,progress,totalDataSize, + rngF,callback,pts[0],pts[1]))) + return errCode; + + progress.step=2; + progress.stepName=TRANS("Build"); + + //Build the tree using the target ions + //(its roughly nlogn timing, but worst case n^2) + kdTree.buildByRef(pts[1]); + pts[1].clear(); + + //Remove surface points from sources if desired + if(excludeSurface) + { + ASSERT(reductionDistance > 0); + progress.step++; + progress.stepName=TRANS("Surface"); + + if(!(*callback)(true)) + return ABORT_ERR; + + + //Take the input points, then use them + //to compute the convex hull reduced + //volume. + vector returnPoints; + if(GetReducedHullPts(pts[0],reductionDistance, + &progress.filterProgress,callback,returnPoints)) + { + if(errCode ==1) + return INSUFFICIENT_SIZE_ERR; + else if(errCode ==2) + return ABORT_ERR; + else + { + ASSERT(false); + return ABORT_ERR; + } + } + + if(!(*callback)(true)) + return ABORT_ERR; + + pts[0].clear(); + //Forget the original points, and use the new ones + p.swap(returnPoints); + } + else + p.swap(pts[0]); + + } + else + { + size_t errCode; + if((errCode=buildMonolithicPoints(dataIn,progress,totalDataSize,callback,p))) + return errCode; + + progress.step=2; + progress.stepName=TRANS("Build"); + BoundCube treeDomain; + treeDomain.setBounds(p); + + //Build the tree (its roughly nlogn timing, but worst case n^2) + kdTree.buildByRef(p); + + //Remove surface points if desired + if(excludeSurface) + { + ASSERT(reductionDistance > 0); + progress.step++; + progress.stepName=TRANS("Surface"); + + if(!(*callback)(true)) + return ABORT_ERR; + + + //Take the input points, then use them + //to compute the convex hull reduced + //volume. + vector returnPoints; + size_t errCode; + if((errCode=GetReducedHullPts(p,reductionDistance, + &progress.filterProgress,callback, + returnPoints)) ) + { + if(errCode ==1) + return INSUFFICIENT_SIZE_ERR; + else if(errCode ==2) + return ABORT_ERR; + else + { + ASSERT(false); + return ABORT_ERR; + } + } + + + + //Forget the original points, and use the new ones + p.swap(returnPoints); + + if(!(*callback)(true)) + return ABORT_ERR; + + } + + } + + //Let us perform the desired analysis + progress.step++; + progress.stepName=TRANS("Analyse"); + + //If there is no data, there is nothing to do. + if(p.empty() || !kdTree.nodeCount()) + return 0; + + //OK, at this point, the KD tree contains the target points + //of interest, and the vector "p" contains the source points + //of interest, whatever they might be. + switch(stopMode) + { + case STOP_MODE_NEIGHBOUR: + { + //User is after an NN histogram analysis + + //Histogram is output as a per-NN histogram of frequency. + vector > histogram; + + //Bin widths for the NN histograms (each NN hist + //is scaled separately). The +1 is due to the tail bin + //being the totals + float *binWidth = new float[nnMax]; + + + unsigned int errCode; + //Run the analysis + errCode=generateNNHist(p,kdTree,nnMax, + numBins,histogram,binWidth, + &(progress.filterProgress),callback); + switch(errCode) + { + case 0: + break; + case RDF_ERR_INSUFFICIENT_INPUT_POINTS: + { + delete[] binWidth; + return INSUFFICIENT_SIZE_ERR; + } + case RDF_ABORT_FAIL: + { + delete[] binWidth; + return ABORT_ERR; + } + default: + ASSERT(false); + } + + //Alright then, we have the histogram in x-{y1,y2,y3...y_n} form + //lets make some plots shall we? + PlotStreamData *plotData[nnMax]; + + for(unsigned int ui=0;uiindex=ui; + plotData[ui]->parent=this; + plotData[ui]->plotMode=PLOT_MODE_1D; + plotData[ui]->xLabel=TRANS("Radial Distance"); + plotData[ui]->yLabel=TRANS("Count"); + std::string tmpStr; + stream_cast(tmpStr,ui+1); + plotData[ui]->dataLabel=getUserString() + string(" ") +tmpStr + TRANS("NN Freq."); + + //Red plot. + plotData[ui]->r=r; + plotData[ui]->g=g; + plotData[ui]->b=b; + plotData[ui]->xyData.resize(numBins); + + for(unsigned int uj=0;ujxyData[uj] = std::make_pair(dist, + histogram[ui][uj]); + } + + if(cache) + { + plotData[ui]->cached=1; + filterOutputs.push_back(plotData[ui]); + cacheOK=true; + } + else + { + plotData[ui]->cached=0; + } + + getOut.push_back(plotData[ui]); + } + + delete[] binWidth; + break; + } + case STOP_MODE_RADIUS: + { + unsigned int warnBiasCount=0; + + //Histogram is output as a histogram of frequency vs distance + unsigned int *histogram = new unsigned int[numBins]; + for(unsigned int ui=0;uiplotMode=PLOT_MODE_1D; + plotData->index=0; + plotData->parent=this; + plotData->xLabel=TRANS("Radial Distance"); + plotData->yLabel=TRANS("Count"); + plotData->dataLabel=getUserString() + TRANS(" RDF"); + + plotData->r=r; + plotData->g=g; + plotData->b=b; + plotData->xyData.resize(numBins); + + for(unsigned int uj=0;ujxyData[uj] = std::make_pair(dist, + histogram[uj]); + } + + delete[] histogram; + + if(cache) + { + plotData->cached=1; + filterOutputs.push_back(plotData); + cacheOK=true; + } + else + plotData->cached=0; + + getOut.push_back(plotData); + + //Propagate non-ion/range data + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + case STREAM_TYPE_RANGE: + //Do not propagate ranges, or ions + break; + default: + getOut.push_back(dataIn[ui]); + break; + } + + } + + break; + } + default: + ASSERT(false); + } + + return 0; +} + +size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress, + bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut) +{ + vector p; + size_t errCode; + progress.step=1; + progress.stepName=TRANS("Collate"); + progress.maxStep=3; + if((errCode=buildMonolithicPoints(dataIn,progress,totalDataSize,callback,p))) + return errCode; + + progress.step=2; + progress.stepName=TRANS("Build"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + BoundCube treeDomain; + treeDomain.setBounds(p); + + //Build the tree (its roughly nlogn timing, but worst case n^2) + K3DTree kdTree; + kdTree.setCallbackMethod(callback); + kdTree.setProgressPointer(&(progress.filterProgress)); + + kdTree.buildByRef(p); + p.clear(); //We don't need pts any more, as tree *is* a copy. + + + //Update progress & User interface by calling callback + if(!(*callback)(false)) + return ABORT_ERR; + + + //Its algorithm time! + //---- + //Update progress stuff + size_t n=0; + progress.step=3; + progress.stepName=TRANS("Analyse"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + //List of points for which there was a failure + //first entry is the point Id, second is the + //dataset id. + std::list > badPts; + for(size_t ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *d; + d=((const IonStreamData *)dataIn[ui]); + IonStreamData *newD = new IonStreamData; + newD->parent=this; + + //Adjust this number to provide more update than usual, because we + //are not doing an o(1) task between updates; yes, it is a hack + unsigned int curProg=NUM_CALLBACK/(10*nnMax); + newD->data.resize(d->data.size()); + if(stopMode == STOP_MODE_NEIGHBOUR) + { + bool spin=false; + #pragma omp parallel for shared(spin) + for(size_t uj=0;ujdata.size();uj++) + { + if(spin) + continue; + Point3D r; + vector res; + r=d->data[uj].getPosRef(); + + //Assign the mass to charge using nn density estimates + kdTree.findKNearest(r,treeDomain,nnMax,res); + + if(res.size()) + { + float maxSqrRad; + + //Get the radius as the furthest object + maxSqrRad= (res[res.size()-1]->sqrDist(r)); + + //Set the mass as the volume of sphere * the number of NN + newD->data[uj].setMassToCharge(res.size()/(4.0/3.0*M_PI*powf(maxSqrRad,3.0/2.0))); + //Keep original position + newD->data[uj].setPos(r); + } + else + { + #pragma omp critical + badPts.push_back(make_pair(uj,ui)); + } + + res.clear(); + + //Update callback as needed + if(!curProg--) + { + #pragma omp critical + { + n+=NUM_CALLBACK/(nnMax); + progress.filterProgress= (unsigned int)(((float)n/(float)totalDataSize)*100.0f); + if(!(*callback)(false)) + spin=true; + curProg=NUM_CALLBACK/(nnMax); + } + } + } + + if(spin) + { + delete newD; + return ABORT_ERR; + } + + + } + else if(stopMode == STOP_MODE_RADIUS) + { +#ifdef _OPENMP + bool spin=false; +#endif + float maxSqrRad = distMax*distMax; + float vol = 4.0/3.0*M_PI*maxSqrRad*distMax; //Sphere volume=4/3 Pi R^3 + #pragma omp parallel for shared(spin) firstprivate(treeDomain,curProg) + for(size_t uj=0;ujdata.size();uj++) + { + Point3D r; + const Point3D *res; + float deadDistSqr; + unsigned int numInRad; +#ifdef _OPENMP + if(spin) + continue; +#endif + r=d->data[uj].getPosRef(); + numInRad=0; + deadDistSqr=0; + + //Assign the mass to charge using nn density estimates + do + { + res=kdTree.findNearest(r,treeDomain,deadDistSqr); + + //Check to see if we found something + if(!res) + { +#pragma omp critical + badPts.push_back(make_pair(uj, ui)); + break; + } + + if(res->sqrDist(r) >maxSqrRad) + break; + numInRad++; + //Advance ever so slightly beyond the next ion + deadDistSqr = res->sqrDist(r)+std::numeric_limits::epsilon(); + //Update callback as needed + if(!curProg--) + { +#pragma omp critical + { + progress.filterProgress= (unsigned int)((float)n/(float)totalDataSize*100.0f); + if(!(*callback)(false)) + { +#ifdef _OPENMP + spin=true; +#else + delete newD; + return ABORT_ERR; +#endif + } + } +#ifdef _OPENMP + if(spin) + break; +#endif + curProg=NUM_CALLBACK/(10*nnMax); + } + }while(true); + + n++; + //Set the mass as the volume of sphere * the number of NN + newD->data[uj].setMassToCharge(numInRad/vol); + //Keep original position + newD->data[uj].setPos(r); + + } + +#ifdef _OPENMP + if(spin) + { + delete newD; + return ABORT_ERR; + } +#endif + } + else + { + //Should not get here. + ASSERT(false); + } + + + //move any bad points from the array to the end, then drop them + //To do this, we have to reverse sort the array, then + //swap the output ion vector entries with the end, + //then do a resize. + ComparePairFirst cmp; + badPts.sort(cmp); + badPts.reverse(); + + //Do some swappage + size_t pos=1; + for(std::list >::iterator it=badPts.begin(); it!=badPts.end();++it) + { + newD->data[(*it).first]=newD->data[newD->data.size()-pos]; + } + + //Trim the tail of bad points, leaving only good points + newD->data.resize(newD->data.size()-badPts.size()); + + + if(newD->data.size()) + { + //Use default colours + newD->r=d->r; + newD->g=d->g; + newD->b=d->b; + newD->a=d->a; + newD->ionSize=d->ionSize; + newD->representationType=d->representationType; + newD->valueType=TRANS("Number Density (\\#/Vol^3)"); + + //Cache result as needed + if(cache) + { + newD->cached=1; + filterOutputs.push_back(newD); + cacheOK=true; + } + else + newD->cached=0; + getOut.push_back(newD); + } + } + break; + case STREAM_TYPE_RANGE: + break; + default: + getOut.push_back(dataIn[ui]); + break; + } + } + //If we have bad points, let the user know. + if(!badPts.empty()) + { + std::string sizeStr; + stream_cast(sizeStr,badPts.size()); + consoleOutput.push_back(std::string(TRANS("Warning,")) + sizeStr + + TRANS(" points were un-analysable. These have been dropped")); + + //Print out a list of points if we can + + size_t maxPrintoutSize=std::min(badPts.size(),(size_t)200); + list >::iterator it; + it=badPts.begin(); + while(maxPrintoutSize--) + { + std::string s; + const IonStreamData *d; + d=((const IonStreamData *)dataIn[it->second]); + + Point3D getPos; + getPos= d->data[it->first].getPosRef(); + stream_cast(s,getPos); + consoleOutput.push_back(s); + ++it; + } + + if(badPts.size() > 200) + { + consoleOutput.push_back(TRANS("And so on...")); + } + + + } + + return 0; +} + +size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress, + bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut) +{ + vector p; + size_t errCode; + progress.step=1; + progress.stepName=TRANS("Collate"); + progress.maxStep=3; + if((errCode=buildMonolithicPoints(dataIn,progress,totalDataSize,callback,p))) + return errCode; + + progress.step=2; + progress.stepName=TRANS("Build"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + BoundCube treeDomain; + treeDomain.setBounds(p); + + //Build the tree (its roughly nlogn timing, but worst case n^2) + K3DTree kdTree; + kdTree.setCallbackMethod(callback); + kdTree.setProgressPointer(&(progress.filterProgress)); + + kdTree.buildByRef(p); + + + //Update progress & User interface by calling callback + if(!(*callback)(false)) + return ABORT_ERR; + p.clear(); //We don't need pts any more, as tree *is* a copy. + + + //Its algorithim time! + //---- + //Update progress stuff + size_t n=0; + progress.step=3; + progress.stepName=TRANS("Analyse"); + progress.filterProgress=0; + if(!(*callback)(true)) + return ABORT_ERR; + + //List of points for which there was a failure + //first entry is the point Id, second is the + //dataset id. + std::list > badPts; + for(size_t ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *d; + d=((const IonStreamData *)dataIn[ui]); + IonStreamData *newD = new IonStreamData; + newD->parent=this; + + //Adjust this number to provide more update thanusual, because we + //are not doing an o(1) task between updates; yes, it is a hack + unsigned int curProg=NUM_CALLBACK/(10*nnMax); + newD->data.reserve(d->data.size()); + if(stopMode == STOP_MODE_NEIGHBOUR) + { + bool spin=false; + #pragma omp parallel for shared(spin) + for(size_t uj=0;ujdata.size();uj++) + { + if(spin) + continue; + Point3D r; + vector res; + r=d->data[uj].getPosRef(); + + //Assign the mass to charge using nn density estimates + kdTree.findKNearest(r,treeDomain,nnMax,res); + + if(res.size()) + { + float maxSqrRad; + + //Get the radius as the furtherst object + maxSqrRad= (res[res.size()-1]->sqrDist(r)); + + + float density; + density = res.size()/(4.0/3.0*M_PI*powf(maxSqrRad,3.0/2.0)); + + if(xorFunc((density <=densityCutoff), keepDensityUpper)) + { +#pragma omp critical + newD->data.push_back(d->data[uj]); + } + + } + else + { + #pragma omp critical + badPts.push_back(make_pair(uj,ui)); + } + + res.clear(); + + //Update callback as needed + if(!curProg--) + { + #pragma omp critical + { + n+=NUM_CALLBACK/(nnMax); + progress.filterProgress= (unsigned int)(((float)n/(float)totalDataSize)*100.0f); + if(!(*callback)(false)) + spin=true; + curProg=NUM_CALLBACK/(nnMax); + } + } + } + + if(spin) + { + delete newD; + return ABORT_ERR; + } + + + } + else if(stopMode == STOP_MODE_RADIUS) + { +#ifdef _OPENMP + bool spin=false; +#endif + float maxSqrRad = distMax*distMax; + float vol = 4.0/3.0*M_PI*maxSqrRad*distMax; //Sphere volume=4/3 Pi R^3 + #pragma omp parallel for shared(spin) firstprivate(treeDomain,curProg) + for(size_t uj=0;ujdata.size();uj++) + { + Point3D r; + const Point3D *res; + float deadDistSqr; + unsigned int numInRad; +#ifdef _OPENMP + if(spin) + continue; +#endif + r=d->data[uj].getPosRef(); + numInRad=0; + deadDistSqr=0; + + //Assign the mass to charge using nn density estimates + do + { + res=kdTree.findNearest(r,treeDomain,deadDistSqr); + + //Check to see if we found something + if(!res) + { +#pragma omp critical + badPts.push_back(make_pair(uj, ui)); + break; + } + + if(res->sqrDist(r) >maxSqrRad) + break; + numInRad++; + //Advance ever so slightly beyond the next ion + deadDistSqr = res->sqrDist(r)+std::numeric_limits::epsilon(); + //Update callback as needed + if(!curProg--) + { +#pragma omp critical + { + progress.filterProgress= (unsigned int)((float)n/(float)totalDataSize*100.0f); + if(!(*callback)(false)) + { +#ifdef _OPENMP + spin=true; +#else + delete newD; + return ABORT_ERR; +#endif + } + } +#ifdef _OPENMP + if(spin) + break; +#endif + curProg=NUM_CALLBACK/(10*nnMax); + } + }while(true); + + n++; + float density; + density = numInRad/vol; + + if(xorFunc((density <=densityCutoff), keepDensityUpper)) + { +#pragma omp critical + newD->data.push_back(d->data[uj]); + } + + } + +#ifdef _OPENMP + if(spin) + { + delete newD; + return ABORT_ERR; + } +#endif + } + else + { + //Should not get here. + ASSERT(false); + } + + + //move any bad points from the array to the end, then drop them + //To do this, we have to reverse sort the array, then + //swap the output ion vector entries with the end, + //then do a resize. + ComparePairFirst cmp; + badPts.sort(cmp); + badPts.reverse(); + + //Do some swappage + size_t pos=1; + for(std::list >::iterator it=badPts.begin(); it!=badPts.end();++it) + { + newD->data[(*it).first]=newD->data[newD->data.size()-pos]; + } + + //Trim the tail of bad points, leaving only good points + newD->data.resize(newD->data.size()-badPts.size()); + + + if(newD->data.size()) + { + //Use default colours + newD->r=d->r; + newD->g=d->g; + newD->b=d->b; + newD->a=d->a; + newD->ionSize=d->ionSize; + newD->representationType=d->representationType; + newD->valueType=TRANS("Number Density (\\#/Vol^3)"); + + //Cache result as needed + if(cache) + { + newD->cached=1; + filterOutputs.push_back(newD); + cacheOK=true; + } + else + newD->cached=0; + getOut.push_back(newD); + } + } + break; + default: + getOut.push_back(dataIn[ui]); + break; + } + } + //If we have bad points, let the user know. + if(!badPts.empty()) + { + std::string sizeStr; + stream_cast(sizeStr,badPts.size()); + consoleOutput.push_back(std::string(TRANS("Warning,")) + sizeStr + + TRANS(" points were un-analysable. These have been dropped")); + + //Print out a list of points if we can + + size_t maxPrintoutSize=std::min(badPts.size(),(size_t)200); + list >::iterator it; + it=badPts.begin(); + while(maxPrintoutSize--) + { + std::string s; + const IonStreamData *d; + d=((const IonStreamData *)dataIn[it->second]); + + Point3D getPos; + getPos= d->data[it->first].getPosRef(); + stream_cast(s,getPos); + consoleOutput.push_back(s); + ++it; + } + + if(badPts.size() > 200) + { + consoleOutput.push_back(TRANS("And so on...")); + } + + + } + + return 0; +} + +void SpatialAnalysisFilter::createCylinder(DrawStreamData * &drawData, + SelectionDevice * &s) const +{ + //Origin + normal + ASSERT(vectorParams.size() == 2); + //Add drawable components + DrawCylinder *dC = new DrawCylinder; + dC->setOrigin(vectorParams[0]); + dC->setRadius(scalarParams[0]); + dC->setColour(0.5,0.5,0.5,0.3); + dC->setSlices(40); + dC->setLength(sqrt(vectorParams[1].sqrMag())*2.0f); + dC->setDirection(vectorParams[1]); + dC->wantsLight=true; + drawData->drawables.push_back(dC); + + + //Set up selection "device" for user interaction + //==== + //The object is selectable + dC->canSelect=true; + //Start and end radii must be the same (not a + //tapered cylinder) + dC->lockRadii(); + + s = new SelectionDevice(this); + SelectionBinding b; + //Bind the drawable object to the properties we wish + //to be able to modify + + //Bind left + command button to move + b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_CYLINDER_BIND_ORIGIN, + BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + //Bind left + shift to change orientation + b.setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_CYLINDER_BIND_DIRECTION, + BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); + s->addBinding(b); + + //Bind right button to changing position + b.setBinding(SELECT_BUTTON_RIGHT,0,DRAW_CYLINDER_BIND_ORIGIN, + BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + //Bind middle button to changing orientation + b.setBinding(SELECT_BUTTON_MIDDLE,0,DRAW_CYLINDER_BIND_DIRECTION, + BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); + b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); + s->addBinding(b); + + //Bind left button to changing radius + b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_CYLINDER_BIND_RADIUS, + BINDING_CYLINDER_RADIUS,dC->getRadius(),dC); + b.setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); + b.setFloatLimits(0,std::numeric_limits::max()); + s->addBinding(b); + + //===== + +} + +size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress, + bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut,const RangeFile *rngF) +{ + progress.step=1; + progress.stepName=TRANS("Extract"); + progress.filterProgress=0; + progress.maxStep=4; + + //Ions inside the selected cylinder, + // which are to be used as source points for dist. function query + vector ionsInside; + { + //Crop out a cylinder as the source data + CropHelper cropHelp(callback,&progress.filterProgress, + totalDataSize, CROP_CYLINDER_INSIDE, + vectorParams,scalarParams); + + //Run cropping over the input datastreams + for(size_t ui=0; uigetStreamType() == STREAM_TYPE_IONS) + { + const IonStreamData* d; + d=(const IonStreamData *)dataIn[ui]; + cropHelp.runFilter(d->data,ionsInside); + } + } + } + + //Now, the ions outside the targeting volume may be reduced + vector ionsOutside; + ionsOutside.resize(totalDataSize); + //Build complete set of input data + { + size_t offset=0; + + for(size_t ui=0;uigetStreamType() != STREAM_TYPE_IONS) + continue; + + + //Copy input data in its entirety into a single vector + const IonStreamData *d; + d=(const IonStreamData*)dataIn[ui]; + for(size_t uj=0;ujdata.size();uj++) + { + ionsOutside[offset]=d->data[uj]; + offset++; + } + + } + } + + progress.step=2; + progress.stepName=TRANS("Reduce"); + progress.filterProgress=0; + + switch(stopMode) + { + case STOP_MODE_RADIUS: + { + //In this case we can pull a small trick - + // do an O(n) pass to crop out the data we want, before doing the O(nlogn) tree build. + // We however must build a slightly larger cylinder to do the crop + + vector vP; + vector sP; + vP=vectorParams; + sP=scalarParams; + + //Expand radius to encapsulate cylinder contents+dMax + sP[0]+= distMax; + //Similarly expand axis (vp[0] is origin, vp[1] is zis) + vP[1].extend(distMax); + + //Crop out a cylinder as the source data + CropHelper cropHelp(callback,&progress.filterProgress, + totalDataSize, CROP_CYLINDER_INSIDE, + vP,sP); + + vector tmp; + cropHelp.runFilter(ionsOutside,tmp); + tmp.swap(ionsOutside); + break; + } + case STOP_MODE_NEIGHBOUR: + { + //Nothing to do here! + break; + } + default: + ASSERT(false); + } + + //We only need to slice down the data if required + if(haveRangeParent) + { + +#pragma omp parallel + { + //For the ions "inside", we only care about the + // source data, not the target. Filter further using this info + #pragma omp task + { + bool sourceReduce; + sourceReduce=(std::count(ionSourceEnabled.begin(),ionSourceEnabled.end(),true) + !=ionSourceEnabled.size()); + if(sourceReduce) + { + vector tmp; + filterSelectedRanges(ionsInside,true,rngF,tmp); + ionsInside.swap(tmp); + } + } + + #pragma omp task + { + bool targetReduce; + targetReduce=(std::count(ionTargetEnabled.begin(),ionTargetEnabled.end(),true) + !=ionTargetEnabled.size() ); + if(targetReduce) + { + vector tmp; + filterSelectedRanges(ionsOutside,false,rngF,tmp); + ionsOutside.swap(tmp); + } + } + } + } + + progress.step=3; + progress.stepName=TRANS("Build"); + progress.filterProgress=0; + + //Strip away the real value information, leaving just point data + vector src,dest; + getPointsFromIons(ionsInside,src); + ionsInside.clear(); + + getPointsFromIons(ionsOutside,dest); + ionsOutside.clear(); + + K3DTree tree; + tree.setProgressPointer(&progress.filterProgress); + tree.setCallbackMethod(callback); + tree.buildByRef(dest); + + progress.step=4; + progress.stepName=TRANS("Compute"); + progress.filterProgress=0; + unsigned int *histogram = new unsigned int[numBins]; + for(unsigned int ui=0;uiplotMode=PLOT_MODE_1D; + plotData->index=0; + plotData->parent=this; + plotData->xLabel=TRANS("Axial Distance"); + plotData->yLabel=TRANS("Count"); + plotData->dataLabel=getUserString() + TRANS(" 1D Dist. Func."); + + plotData->r=r; + plotData->g=g; + plotData->b=b; + plotData->xyData.resize(numBins); + + for(unsigned int uj=0;ujxyData[uj] = std::make_pair(dist, + histogram[uj]); + } + + delete[] histogram; + + + if(cache) + { + plotData->cached=1; + filterOutputs.push_back(plotData); + cacheOK=true; + } + else + plotData->cached=0; + getOut.push_back(plotData); + + + //Propagate non-ion/range data + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + case STREAM_TYPE_RANGE: + //Do not propagate ranges, or ions + break; + default: + getOut.push_back(dataIn[ui]); + break; + } + + } + + //Create the user interaction device required for the user + // to interact with the algorithm parameters + SelectionDevice *s; + DrawStreamData *d= new DrawStreamData; + d->parent=this; + d->cached=0; + + createCylinder(d,s); + devices.push_back(s); + getOut.push_back(d); + return 0; +} + +#ifdef DEBUG + +bool densityPairTest(); +bool nnHistogramTest(); +bool rdfPlotTest(); + +bool SpatialAnalysisFilter::runUnitTests() +{ + if(!densityPairTest()) + return false; + + if(!nnHistogramTest()) + return false; + + if(!rdfPlotTest()) + return false; + + return true; +} + + +bool densityPairTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + + + IonStreamData*d = new IonStreamData; + IonHit h; + h.setMassToCharge(1); + + //create two points, 1 unit apart + h.setPos(Point3D(0,0,0)); + d->data.push_back(h); + + h.setPos(Point3D(0,0,1)); + d->data.push_back(h); + + streamIn.push_back(d); + //--------- + + //Create a spatial analysis filter + SpatialAnalysisFilter *f=new SpatialAnalysisFilter; + f->setCaching(false); + //Set it to do an NN terminated density computation + bool needUp; + string s; + s=TRANS(STOP_MODES[STOP_MODE_NEIGHBOUR]); + TEST(f->setProperty(KEY_STOPMODE,s,needUp),"Set prop"); + s=TRANS(SPATIAL_ALGORITHMS[ALGORITHM_DENSITY]); + TEST(f->setProperty(KEY_ALGORITHM,s,needUp),"Set prop"); + + + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK"); + delete f; + //Kill the input ion stream + delete d; + streamIn.clear(); + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + + const IonStreamData* dOut = (const IonStreamData*)streamOut[0]; + + TEST(dOut->data.size() == 2, "ion count"); + + for(unsigned int ui=0;ui<2;ui++) + { + TEST( fabs( dOut->data[0].getMassToCharge() - 1.0/(4.0/3.0*M_PI)) + < sqrt(std::numeric_limits::epsilon()),"NN density test"); + } + + + delete streamOut[0]; + + return true; +} + +bool nnHistogramTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + + + IonStreamData*d = new IonStreamData; + IonHit h; + h.setMassToCharge(1); + + //create two points, 1 unit apart + h.setPos(Point3D(0,0,0)); + d->data.push_back(h); + + h.setPos(Point3D(0,0,1)); + d->data.push_back(h); + + streamIn.push_back(d); + + //Create a spatial analysis filter + SpatialAnalysisFilter *f=new SpatialAnalysisFilter; + f->setCaching(false); + //Set it to do an NN terminated density computation + bool needUp; + TEST(f->setProperty(KEY_STOPMODE, + STOP_MODES[STOP_MODE_NEIGHBOUR],needUp),"set stop mode"); + TEST(f->setProperty(KEY_ALGORITHM, + SPATIAL_ALGORITHMS[ALGORITHM_RDF],needUp),"set Algorithm"); + TEST(f->setProperty(KEY_NNMAX,"1",needUp),"Set NNmax"); + + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK"); + delete f; + + streamIn.clear(); + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_PLOT,"plot outputting"); + const PlotStreamData* dPlot=(const PlotStreamData *)streamOut[0]; + + + float fMax=0; + for(size_t ui=0;uixyData.size();ui++) + { + fMax=std::max(fMax,dPlot->xyData[ui].second); + } + + TEST(fMax > 0 , "plot has nonzero contents"); + //Kill the input ion stream + delete d; + + delete dPlot; + + return true; +} + +bool rdfPlotTest() +{ + //Build some points to pass to the filter + vector streamIn,streamOut; + + IonStreamData*d = new IonStreamData; + IonHit h; + h.setMassToCharge(1); + + //create two points, 1 unit apart + h.setPos(Point3D(0,0,0)); + d->data.push_back(h); + + h.setPos(Point3D(0,0,1)); + d->data.push_back(h); + + streamIn.push_back(d); + + //Create a spatial analysis filter + SpatialAnalysisFilter *f=new SpatialAnalysisFilter; + f->setCaching(false); + //Set it to do an NN terminated density computation + bool needUp; + TEST(f->setProperty(KEY_STOPMODE, + TRANS(STOP_MODES[STOP_MODE_RADIUS]),needUp),"set stop mode"); + TEST(f->setProperty(KEY_ALGORITHM, + TRANS(SPATIAL_ALGORITHMS[ALGORITHM_RDF]),needUp),"set Algorithm"); + TEST(f->setProperty(KEY_DISTMAX,"2",needUp),"Set NNmax"); + + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK"); + delete f; + + + streamIn.clear(); + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_PLOT,"plot outputting"); + const PlotStreamData* dPlot=(const PlotStreamData *)streamOut[0]; + + + float fMax=0; + for(size_t ui=0;uixyData.size();ui++) + { + fMax=std::max(fMax,dPlot->xyData[ui].second); + } + + TEST(fMax > 0 , "plot has nonzero contents"); + + + //kill output data + delete dPlot; + + //Kill the input ion stream + delete d; + + return true; +} + + +#endif + diff -Nru 3depict-0.0.12/src/backend/filters/spatialAnalysis.h 3depict-0.0.13/src/backend/filters/spatialAnalysis.h --- 3depict-0.0.12/src/backend/filters/spatialAnalysis.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/spatialAnalysis.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,179 @@ +/* + * spatialAnalysis.h - Perform various data analysis on 3D point clouds + * 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 . +*/ +#ifndef SPATIALANALYSIS_H +#define SPATIALANALYSIS_H +#include "../filter.h" +#include "../../common/translation.h" + +//!Spatial analysis filter +class SpatialAnalysisFilter : public Filter +{ + private: + //!Colour to use for output plots + float r,g,b,a; + + //!Which algorithm to use + unsigned int algorithm; + + //!Stopping criterion + unsigned int stopMode; + + //!NN stopping criterion (max) + unsigned int nnMax; + + //!Distance maximum + float distMax; + + //!Do we have range data to use (is nonzero) + bool haveRangeParent; + //!The names of the incoming ions + std::vector ionNames; + //!Are the sources/targets enabled for a particular incoming range? + std::vector ionSourceEnabled,ionTargetEnabled; + + //RDF specific params + //-------- + //RDF bin count + unsigned int numBins; + + //!Optional convex hull reduction + bool excludeSurface; + + //!Surface reduction distance (convex hull) + float reductionDistance; + //-------- + + //Density filtering specific params + //------- + //Do we keep points with density >= cutoff (true), or + // points with density < cutoff (false) + bool keepDensityUpper; + + //Cutoff value when performing density filtering + float densityCutoff; + + //!Vector paramaters for different primitives + vector vectorParams; + //!Scalar paramaters for different primitives + vector scalarParams; + + //Reset the scalar and vector parameters + // to their defaults, if the required parameters + // are not available + void resetParamsAsNeeded(); + //------- + + + + + //Radial distribution function - creates a 1D histogram of spherical atom counts, centered around each atom + size_t algorithmRDF(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut,const RangeFile *rngF); + + + //Local density function - places a sphere around each point to compute per-point density + size_t algorithmDensity(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut); + + //Density filter function - same as density function, but then drops points from output + // based upon their local density and some density cutoff data + size_t algorithmDensityFilter(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut); + + size_t algorithmAxialDf(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, + const vector &dataIn, + vector &getOut,const RangeFile *rngF); + + //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 * &s) const; + + //Scan input datstreams to build a two point vectors, + // one of those with points specified as "target" + // which is a copy of the input points + //Returns 0 on no error, otherwise nonzero + size_t buildSplitPoints(const vector &dataIn, + ProgressData &progress, size_t totalDataSize, + const RangeFile *rngF, bool (*callback)(bool), + vector &pSource, vector &pTarget) const; + + + //From the given input ions, filter them down using the user + // selection for ranges. If sourceFilter is true, filter by user + // source selection, otherwise by user target selection + void filterSelectedRanges(const vector &ions, bool sourceFilter, const RangeFile *rngF, vector &output) const; + public: + SpatialAnalysisFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //!Initialise filter prior to tree propagation + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + + //!Returns -1, as range file cache size is dependant upon input. + virtual size_t numBytesForCache(size_t nObjects) const; + //!Returns FILTER_TYPE_SPATIAL_ANALYSIS + unsigned int getType() const { return FILTER_TYPE_SPATIAL_ANALYSIS;}; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + //!Get the type string for this fitler + virtual std::string typeString() const { return std::string(TRANS("Spat. Analysis"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be possibly used during ::refresh + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding + void setPropFromBinding(const SelectionBinding &b) ; + + //Set the filter's Title "user string" + void setUserString(const std::string &s); +#ifdef DEBUG + bool runUnitTests(); +#endif +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/spectrumPlot.cpp 3depict-0.0.13/src/backend/filters/spectrumPlot.cpp --- 3depict-0.0.12/src/backend/filters/spectrumPlot.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/spectrumPlot.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,964 @@ +/* + * spectrumPlot.cpp - Compute histograms of values for valued 3D point data + * 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 . +*/ +#include "spectrumPlot.h" + +#include "../plot.h" + +#include "filterCommon.h" + +//!Error codes +enum +{ + SPECTRUM_BAD_ALLOC=1, + SPECTRUM_BAD_BINCOUNT, + SPECTRUM_ABORT_FAIL, +}; + +enum +{ + KEY_SPECTRUM_BINWIDTH, + KEY_SPECTRUM_AUTOEXTREMA, + KEY_SPECTRUM_MIN, + KEY_SPECTRUM_MAX, + KEY_SPECTRUM_LOGARITHMIC, + KEY_SPECTRUM_PLOTTYPE, + KEY_SPECTRUM_COLOUR +}; + +//Limit user to one :million: bins +const unsigned int SPECTRUM_MAX_BINS=1000000; + +const unsigned int SPECTRUM_AUTO_MAX_BINS=25000; + +SpectrumPlotFilter::SpectrumPlotFilter() +{ + minPlot=0; + maxPlot=150; + autoExtrema=true; + binWidth=0.5; + plotStyle=0; + logarithmic=1; + + //Default to blue plot + r=g=0; + b=a=1; +} + +Filter *SpectrumPlotFilter::cloneUncached() const +{ + SpectrumPlotFilter *p = new SpectrumPlotFilter(); + + p->minPlot=minPlot; + p->maxPlot=maxPlot; + p->binWidth=binWidth; + p->autoExtrema=autoExtrema; + p->r=r; + p->g=g; + p->b=b; + p->a=a; + p->plotStyle=plotStyle; + p->logarithmic = logarithmic; + + + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +//!Get approx number of bytes for caching output +size_t SpectrumPlotFilter::numBytesForCache(size_t nObjects) const +{ + //Check that we have good plot limits, and bin width. if not, we cannot estimate cache size + if(minPlot ==std::numeric_limits::max() || + maxPlot==-std::numeric_limits::max() || + binWidth < sqrt(std::numeric_limits::epsilon())) + { + return (size_t)(-1); + } + + return (size_t)((float)(maxPlot- minPlot)/(binWidth))*2*sizeof(float); +} + +unsigned int SpectrumPlotFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + + if(cacheOK) + { + //Only report the spectrum plot + for(unsigned int ui=0;ui::max(); + maxPlot =-std::numeric_limits::max(); + //Loop through each type of data + + unsigned int curProg=NUM_CALLBACK; + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + IonStreamData *ions; + ions = (IonStreamData *)dataIn[ui]; + for(unsigned int uj=0;ujdata.size(); uj++) + { + minPlot = std::min(minPlot, + ions->data[uj].getMassToCharge()); + maxPlot = std::max(maxPlot, + ions->data[uj].getMassToCharge()); + + + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + curProg=NUM_CALLBACK; + if(!(*callback)(false)) + return SPECTRUM_ABORT_FAIL; + } + } + + } + + } + + //Check that the plot values have been set (ie not same as initial values) + if(minPlot !=std::numeric_limits::max() && + maxPlot!=-std::numeric_limits::max() ) + { + //push them out a bit to make the edges visible + maxPlot=maxPlot+1; + minPlot=minPlot-1; + } + + //Time to move to phase 2 + progress.step=2; + progress.stepName=TRANS("count"); + } + + + + double delta = ((double)maxPlot - (double)(minPlot))/(double)binWidth; + + + //Check that we have good plot limits. + if(minPlot ==std::numeric_limits::max() || + minPlot ==-std::numeric_limits::max() || + fabs(delta) > std::numeric_limits::max() || // Check for out-of-range + binWidth < sqrt(std::numeric_limits::epsilon()) ) + { + //If not, then simply set it to "1". + minPlot=0; maxPlot=1.0; binWidth=0.1; + } + + + + //Estimate number of bins in floating point, and check for potential overflow . + float tmpNBins = (float)((maxPlot-minPlot)/binWidth); + + //If using autoextrema, use a lower limit for max bins, + //as we may just hit a nasty data point + if(autoExtrema) + tmpNBins = std::min(SPECTRUM_AUTO_MAX_BINS,(unsigned int)tmpNBins); + else + tmpNBins = std::min(SPECTRUM_MAX_BINS,(unsigned int)tmpNBins); + + nBins = (unsigned int)tmpNBins; + + if (!nBins) + { + nBins = 10; + binWidth = (maxPlot-minPlot)/nBins; + } + } + + + PlotStreamData *d; + d=new PlotStreamData; + try + { + d->xyData.resize(nBins); + } + catch(std::bad_alloc) + { + + delete d; + return SPECTRUM_BAD_ALLOC; + } + + + d->r = r; + d->g = g; + d->b = b; + d->a = a; + + d->logarithmic=logarithmic; + d->plotStyle = plotStyle; + d->plotMode=PLOT_MODE_1D; + + d->index=0; + d->parent=this; + d->dataLabel = getUserString(); + d->yLabel= TRANS("Count"); + + //Check all the incoming ion data's type name + //and if it is all the same, use it for the plot X-axis + std::string valueName; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *ionD; + ionD=(const IonStreamData *)dataIn[ui]; + if(!valueName.size()) + valueName=ionD->valueType; + else + { + if(ionD->valueType != valueName) + { + valueName=TRANS("Mixed data"); + break; + } + } + } + } + } + + d->xLabel=valueName; + + + //Look for any ranges in input stream, and add them to the plot + //while we are doing that, count the number of ions too + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_RANGE: + { + const RangeStreamData *rangeD; + rangeD=(const RangeStreamData *)dataIn[ui]; + for(unsigned int uj=0;ujrangeFile->getNumRanges();uj++) + { + unsigned int ionId; + ionId=rangeD->rangeFile->getIonID(uj); + //Only append the region if both the range + //and the ion are enabled + if((rangeD->enabledRanges)[uj] && + (rangeD->enabledIons)[ionId]) + { + //save the range as a "region" + d->regions.push_back(rangeD->rangeFile->getRange(uj)); + d->regionID.push_back(uj); + d->parent=this; + //FIXME: Const correctness + d->regionParent=(Filter*)rangeD->parent; + + RGBf colour; + //Use the ionID to set the range colouring + colour=rangeD->rangeFile->getColour(ionId); + + //push back the range colour + d->regionR.push_back(colour.red); + d->regionG.push_back(colour.green); + d->regionB.push_back(colour.blue); + } + } + break; + } + default: + break; + } + } + +#pragma omp parallel for + for(unsigned int ui=0;uixyData[ui].first = minPlot + ui*binWidth; + d->xyData[ui].second=0; + } + //Compute the plot bounds + d->autoSetHardBounds(); + //Limit them to 1.0 or greater (due to log) + d->hardMinY=std::min(1.0f,d->hardMaxY); + + + //Number of ions currently processed + size_t n=0; + unsigned int curProg=NUM_CALLBACK; + //Loop through each type of data + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *ions; + ions = (const IonStreamData *)dataIn[ui]; + + + + //Sum the data bins as needed + for(unsigned int uj=0;ujdata.size(); uj++) + { + unsigned int bin; + bin = (unsigned int)((ions->data[uj].getMassToCharge()-minPlot)/binWidth); + //Dependant upon the bounds, + //actual data could be anywhere. + if( bin < d->xyData.size()) + d->xyData[bin].second++; + + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)(((float)(n)/((float)totalSize))*100.0f); + curProg=NUM_CALLBACK; + if(!(*callback)(false)) + { + delete d; + return SPECTRUM_ABORT_FAIL; + } + } + } + + break; + } + default: + //Don't propagate any type. + break; + } + + } + + if(cache) + { + d->cached=1; //IMPORTANT: cached must be set PRIOR to push back + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + + return 0; +} + +void SpectrumPlotFilter::getProperties(FilterPropGroup &propertyList) const +{ + + FilterProperty p; + size_t curGroup=0; + string str; + + stream_cast(str,binWidth); + p.name=TRANS("Bin width"); + p.data=str; + p.key=KEY_SPECTRUM_BINWIDTH; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Step size for spectrum"); + propertyList.addProperty(p,curGroup); + + if(autoExtrema) + str = "1"; + else + str = "0"; + + + p.name=TRANS("Auto Min/max"); + p.data=str; + p.key=KEY_SPECTRUM_AUTOEXTREMA; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Automatically compute spectrum upper and lower bound"); + propertyList.addProperty(p,curGroup); + + stream_cast(str,minPlot); + p.data=str; + p.name=TRANS("Min"); + p.key=KEY_SPECTRUM_MIN; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Starting position for spectrum"); + propertyList.addProperty(p,curGroup); + + stream_cast(str,maxPlot); + p.key=KEY_SPECTRUM_MAX; + p.name=TRANS("Max"); + p.data=str; + p.type=PROPERTY_TYPE_REAL; + p.helpText=TRANS("Ending position for spectrum"); + propertyList.addProperty(p,curGroup); + + if(logarithmic) + str = "1"; + else + str = "0"; + p.key=KEY_SPECTRUM_LOGARITHMIC; + p.name=TRANS("Logarithmic"); + p.data=str; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Convert the plot to logarithmic mode"); + propertyList.addProperty(p,curGroup); + + //Let the user know what the valid values for plot type are + vector > choices; + + + string tmpStr; + tmpStr=plotString(PLOT_TRACE_LINES); + choices.push_back(make_pair((unsigned int) PLOT_TRACE_LINES,tmpStr)); + tmpStr=plotString(PLOT_TRACE_BARS); + choices.push_back(make_pair((unsigned int)PLOT_TRACE_BARS,tmpStr)); + tmpStr=plotString(PLOT_TRACE_STEPS); + choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEPS,tmpStr)); + tmpStr=plotString(PLOT_TRACE_STEM); + choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEM,tmpStr)); + + + tmpStr= choiceString(choices,plotStyle); + p.name=TRANS("Plot Type"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_CHOICE; + p.helpText=TRANS("Visual style of plot"); + p.key=KEY_SPECTRUM_PLOTTYPE; + propertyList.addProperty(p,curGroup); + + string thisCol; + + //Convert the colour to a hex string + genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0), + (unsigned char)(b*255.0),(unsigned char)(a*255.0),thisCol); + + p.name=TRANS("Colour"); + p.data=thisCol; + p.type=PROPERTY_TYPE_COLOUR; + p.helpText=TRANS("Colour of plotted spectrum"); + p.key=KEY_SPECTRUM_COLOUR; + propertyList.addProperty(p,curGroup); +} + +bool SpectrumPlotFilter::setProperty( unsigned int key, + const std::string &value, bool &needUpdate) +{ + needUpdate=false; + switch(key) + { + //Bin width + case KEY_SPECTRUM_BINWIDTH: + { + float newWidth; + if(stream_cast(newWidth,value)) + return false; + + if(newWidth < std::numeric_limits::epsilon()) + return false; + + //Prevent overflow on next line + if(maxPlot == std::numeric_limits::max() || + minPlot == std::numeric_limits::min()) + return false; + + if(newWidth < 0.0f || newWidth > (maxPlot - minPlot)) + return false; + + + + needUpdate=true; + binWidth=newWidth; + clearCache(); + + break; + } + //Auto min/max + case KEY_SPECTRUM_AUTOEXTREMA: + { + //Only allow valid values + unsigned int valueInt; + if(stream_cast(valueInt,value)) + return false; + + //Only update as needed + if(valueInt ==0 || valueInt == 1) + { + if((int)autoExtrema != valueInt) + { + needUpdate=true; + autoExtrema=valueInt; + } + else + needUpdate=false; + + } + else + return false; + + clearCache(); + + break; + + } + //Plot min + case KEY_SPECTRUM_MIN: + { + if(autoExtrema) + return false; + + float newMin; + if(stream_cast(newMin,value)) + return false; + + if(newMin >= maxPlot) + return false; + + needUpdate=true; + minPlot=newMin; + + clearCache(); + break; + } + //Plot max + case KEY_SPECTRUM_MAX: + { + if(autoExtrema) + return false; + float newMax; + if(stream_cast(newMax,value)) + return false; + + if(newMax <= minPlot) + return false; + + needUpdate=true; + maxPlot=newMax; + clearCache(); + + break; + } + case KEY_SPECTRUM_LOGARITHMIC: + { + //Only allow valid values + unsigned int valueInt; + if(stream_cast(valueInt,value)) + return false; + + //Only update as needed + if(valueInt ==0 || valueInt == 1) + { + if((int)logarithmic != valueInt) + { + needUpdate=true; + logarithmic=valueInt; + } + else + needUpdate=false; + + } + else + return false; + + if(cacheOK) + { + //Change the output of the plot streams that + //we cached, in order to avoid recomputation + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + PlotStreamData *p; + p =(PlotStreamData*)filterOutputs[ui]; + + p->logarithmic=logarithmic; + } + } + + } + + break; + + } + //Plot type + case KEY_SPECTRUM_PLOTTYPE: + { + unsigned int tmpPlotType; + + tmpPlotType=plotID(value); + + if(tmpPlotType >= PLOT_TRACE_ENDOFENUM) + return false; + + plotStyle = tmpPlotType; + needUpdate=true; + + + //Perform introspection on + //cache + if(cacheOK) + { + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + PlotStreamData *p; + p =(PlotStreamData*)filterOutputs[ui]; + + p->plotStyle=plotStyle; + } + } + + } + + break; + } + case KEY_SPECTRUM_COLOUR: + { + unsigned char newR,newG,newB,newA; + + parseColString(value,newR,newG,newB,newA); + + if(newB != b || newR != r || + newG !=g || newA != a) + needUpdate=true; + r=newR/255.0; + g=newG/255.0; + b=newB/255.0; + a=newA/255.0; + if(cacheOK) + { + for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) + { + PlotStreamData *p; + p =(PlotStreamData*)filterOutputs[ui]; + + p->r=r; + p->g=g; + p->b=b; + } + } + + } + break; + } + default: + ASSERT(false); + break; + + } + + + return true; +} + +void SpectrumPlotFilter::setUserString(const std::string &s) +{ + if(userString !=s) + { + userString=s; + clearCache(); + cacheOK=false; + } +} + + +std::string SpectrumPlotFilter::getErrString(unsigned int code) const +{ + switch(code) + { + case SPECTRUM_BAD_ALLOC: + return string(TRANS("Insufficient memory for spectrum filter.")); + case SPECTRUM_BAD_BINCOUNT: + return string(TRANS("Bad bincount value in spectrum filter.")); + } + return std::string("BUG: (SpectrumPlotFilter::getErrString) Shouldn't see this!"); +} + +void SpectrumPlotFilter::setPropFromBinding(const SelectionBinding &b) +{ + ASSERT(false); +} + +bool SpectrumPlotFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" <" << endl; + + f << tabs(depth+1) << "" << endl; + + f << tabs(depth) << "" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool SpectrumPlotFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + using std::string; + string tmpStr; + + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Retrieve Extrema + //=== + float tmpMin,tmpMax; + if(XMLHelpFwdToElem(nodePtr,"extrema")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"min"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //convert from string to digit + if(stream_cast(tmpMin,tmpStr)) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"max"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //convert from string to digit + if(stream_cast(tmpMax,tmpStr)) + return false; + + + if(tmpMin >=tmpMax) + return false; + + minPlot=tmpMin; + maxPlot=tmpMax; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"auto"); + if(!xmlString) + return false; + + tmpStr=(char *)xmlString; + if(tmpStr == "1") + autoExtrema=true; + else if(tmpStr== "0") + autoExtrema=false; + else + { + xmlFree(xmlString); + return false; + } + + xmlFree(xmlString); + //=== + + //Retrieve bin width + //==== + // + if(!XMLGetNextElemAttrib(nodePtr,binWidth,"binwidth","value")) + return false; + if(binWidth <= 0.0) + return false; + + if(!autoExtrema && binWidth > maxPlot - minPlot) + return false; + //==== + //Retrieve colour + //==== + if(XMLHelpFwdToElem(nodePtr,"colour")) + return false; + if(!parseXMLColour(nodePtr,r,g,b,a)) + return false; + //==== + + //Retrieve logarithmic mode + //==== + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"logarithmic","value")) + return false; + if(tmpStr == "0") + logarithmic=false; + else if(tmpStr == "1") + logarithmic=true; + else + return false; + //==== + + //Retrieve plot type + //==== + if(!XMLGetNextElemAttrib(nodePtr,plotStyle,"plottype","value")) + return false; + if(plotStyle >= PLOT_TRACE_ENDOFENUM) + return false; + //==== + + return true; +} + +unsigned int SpectrumPlotFilter::getRefreshBlockMask() const +{ + //Absolutely nothing can go through this filter. + return STREAMTYPE_MASK_ALL; +} + +unsigned int SpectrumPlotFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_PLOT; +} + +unsigned int SpectrumPlotFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS; +} + +#ifdef DEBUG +#include + +IonStreamData *synDataPoints(const unsigned int span[], unsigned int numPts) +{ + IonStreamData *d = new IonStreamData; + + for(unsigned int ui=0;uidata.push_back(h); + } + + return d; +} + +bool countTest() +{ + auto_ptr d; + const unsigned int VOL[]={ + 10,10,10 + }; + const unsigned int NUMPTS=100; + d.reset(synDataPoints(VOL,NUMPTS)); + + SpectrumPlotFilter *f; + f = new SpectrumPlotFilter; + + + bool needUp; + std::string s; + TEST(f->setProperty(KEY_SPECTRUM_LOGARITHMIC,"0",needUp),"Set prop"); + + genColString(255,0,0,s); + TEST(f->setProperty(KEY_SPECTRUM_COLOUR,s,needUp),"Set prop"); + + vector streamIn,streamOut; + + streamIn.push_back(d.get()); + + //OK, so now do the rotation + //Do the refresh + ProgressData p; + f->setCaching(false); + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_PLOT,"stream type"); + + PlotStreamData *plot; + plot = (PlotStreamData*)streamOut[0]; + + + //Check the plot colour is what we want. + TEST(fabs(plot->r -1.0f) < sqrt(std::numeric_limits::epsilon()),"colour (r)"); + TEST(plot->g< + sqrt(std::numeric_limits::epsilon()),"colour (g)"); + TEST(plot->b < sqrt(std::numeric_limits::epsilon()),"colour (b)"); + + //Count the number of ions in the plot, and check that it is equal to the number of ions we put in. + float sumV=0; + + for(unsigned int ui=0;uixyData.size();ui++) + sumV+=plot->xyData[ui].second; + + TEST(fabs(sumV - (float)NUMPTS) < + std::numeric_limits::epsilon(),"ion count"); + + + delete plot; + return true; +} + +bool SpectrumPlotFilter::runUnitTests() +{ + if(!countTest()) + return false; + + return true; +} + +#endif + diff -Nru 3depict-0.0.12/src/backend/filters/spectrumPlot.h 3depict-0.0.13/src/backend/filters/spectrumPlot.h --- 3depict-0.0.12/src/backend/filters/spectrumPlot.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/spectrumPlot.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * spectrumPlot.h - Compute histograms of values for valued 3D point data + * 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 . +*/ +#ifndef SPECTRUMPLOT_H +#define SPECTRUMPLOT_H +#include "../filter.h" +#include "../../common/translation.h" + + +//!Spectrum plot filter +class SpectrumPlotFilter : public Filter +{ + private: + float minPlot,maxPlot; + float binWidth; + bool autoExtrema; + bool logarithmic; + + + //Vector of spectra. Each spectra is comprised of a sorted Y data + std::vector< std::vector > spectraCache; + float r,g,b,a; + unsigned int plotStyle; + public: + SpectrumPlotFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + //!Returns FILTER_TYPE_SPECTRUMPLOT + unsigned int getType() const { return FILTER_TYPE_SPECTRUMPLOT;}; + + //!Get approx number of bytes for caching output + size_t numBytesForCache(size_t nObjects) const; + + //!update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + virtual std::string typeString() const { return std::string(TRANS("Spectrum"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter. Returns true if prop set OK + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Set the user string. + void setUserString(const std::string &s); + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, unsigned int depth=0) const; + + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be possibly used during ::refresh + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b) ; + +#ifdef DEBUG + bool runUnitTests() ; + +#endif +}; + +#endif + diff -Nru 3depict-0.0.12/src/backend/filters/transform.cpp 3depict-0.0.13/src/backend/filters/transform.cpp --- 3depict-0.0.12/src/backend/filters/transform.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/transform.cpp 2013-04-10 19:40:31.000000000 +0000 @@ -0,0 +1,2209 @@ +/* + * transform.cpp - Perform geometrical transform operations on point clouds + * 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 . +*/ +#include "transform.h" + +#include "filterCommon.h" + + + + +enum +{ + KEY_MODE, + KEY_SCALEFACTOR, + KEY_SCALEFACTOR_ANISOTROPIC, + KEY_ORIGIN, + KEY_TRANSFORM_SHOWORIGIN, + KEY_ORIGINMODE, + KEY_NOISELEVEL, + KEY_NOISETYPE, + KEY_ROTATE_ANGLE, + KEY_ROTATE_AXIS, + KEY_ORIGIN_VALUE +}; + +//Possible transform modes (scaling, rotation etc) +enum +{ + MODE_TRANSLATE, + MODE_SCALE_ISOTROPIC, + MODE_SCALE_ANISOTROPIC, + MODE_ROTATE, + MODE_VALUE_SHUFFLE, + MODE_SPATIAL_NOISE, + MODE_TRANSLATE_VALUE, + MODE_ENUM_END +}; + +//!Possible mode for selection of origin in transform filter +enum +{ + ORIGINMODE_SELECT, + ORIGINMODE_CENTREBOUND, + ORIGINMODE_MASSCENTRE, + ORIGINMODE_END, // Not actually origin mode, just end of enum +}; + +//!Possible noise modes +enum +{ + NOISETYPE_GAUSSIAN, + NOISETYPE_WHITE, + NOISETYPE_END +}; + +//!Error codes +enum +{ + ERR_CALLBACK_FAIL=1, + ERR_NOMEM +}; + +const char *TRANSFORM_MODE_STRING[] = { NTRANS("Translate"), + NTRANS("Scale (isotropic)"), + NTRANS("Scale (anisotropic)"), + NTRANS("Rotate"), + NTRANS("Value Shuffle"), + NTRANS("Spatial Noise"), + NTRANS("Translate Value") + }; + +const char *TRANSFORM_ORIGIN_STRING[]={ + NTRANS("Specify"), + NTRANS("Boundbox Centre"), + NTRANS("Mass Centre") + }; + + + +//=== Transform filter === +TransformFilter::TransformFilter() +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(TRANSFORM_MODE_STRING) == MODE_ENUM_END); + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(TRANSFORM_ORIGIN_STRING) == ORIGINMODE_END); + + randGen.initTimer(); + transformMode=MODE_TRANSLATE; + originMode=ORIGINMODE_SELECT; + noiseType=NOISETYPE_WHITE; + //Set up default value + vectorParams.resize(1); + vectorParams[0] = Point3D(0,0,0); + + showPrimitive=true; + showOrigin=false; + + cacheOK=false; + cache=false; +} + +Filter *TransformFilter::cloneUncached() const +{ + TransformFilter *p=new TransformFilter(); + + //Copy the values + p->vectorParams.resize(vectorParams.size()); + p->scalarParams.resize(scalarParams.size()); + + std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin()); + std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin()); + + p->showPrimitive=showPrimitive; + p->originMode=originMode; + p->transformMode=transformMode; + p->showOrigin=showOrigin; + p->noiseType=noiseType; + //We are copying wether to cache or not, + //not the cache itself + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +size_t TransformFilter::numBytesForCache(size_t nObjects) const +{ + //Say we don't know, we are not going to cache anyway. + return (size_t)-1; +} + +DrawStreamData* TransformFilter::makeMarkerSphere(SelectionDevice* &s) const +{ + //construct a new primitive, do not cache + DrawStreamData *drawData=new DrawStreamData; + drawData->parent=this; + //Add drawable components + DrawSphere *dS = new DrawSphere; + dS->setOrigin(vectorParams[0]); + dS->setRadius(1); + //FIXME: Alpha blending is all screwed up. May require more + //advanced drawing in scene. (front-back drawing). + //I have set alpha=1 for now. + dS->setColour(0.2,0.2,0.8,1.0); + dS->setLatSegments(40); + dS->setLongSegments(40); + dS->wantsLight=true; + drawData->drawables.push_back(dS); + + s=0; + //Set up selection "device" for user interaction + //Note the order of s->addBinding is critical, + //as bindings are selected by first match. + //==== + //The object is selectable + if (originMode == ORIGINMODE_SELECT ) + { + dS->canSelect=true; + + s=new SelectionDevice(this); + SelectionBinding b; + + b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_SPHERE_BIND_ORIGIN, + BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); + b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); + s->addBinding(b); + + } + drawData->cached=0; + + return drawData; +} + +unsigned int TransformFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + //Clear selection devices FIXME: Is this a memory leak??? + clearDevices(); + //use the cached copy if we have it. + if(cacheOK) + { + ASSERT(filterOutputs.size()); + for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) + getOut.push_back(dataIn[ui]); + } + + for(unsigned int ui=0;ui *s; + getOut.push_back(makeMarkerSphere(s)); + if(s) + devices.push_back(s); + } + + } + + return 0; + } + + + //The user is allowed to choose the mode by which the origin is computed + //so set the origin variable depending upon this + switch(originMode) + { + case ORIGINMODE_CENTREBOUND: + { + BoundCube masterB; + masterB.setInverseLimits(); + #pragma omp parallel for + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + const IonStreamData* ions; + ions = (const IonStreamData*)dataIn[ui]; + if(ions->data.size()) + { + thisB = getIonDataLimits(ions->data); + #pragma omp critical + masterB.expand(thisB); + } + } + } + + if(!masterB.isValid()) + vectorParams[0]=Point3D(0,0,0); + else + vectorParams[0]=masterB.getCentroid(); + break; + } + case ORIGINMODE_MASSCENTRE: + { + Point3D massCentre(0,0,0); + size_t numCentres=0; + #pragma omp parallel for + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) + { + const IonStreamData* ions; + ions = (const IonStreamData*)dataIn[ui]; + + if(ions->data.size()) + { + Point3D thisCentre; + thisCentre=Point3D(0,0,0); + for(unsigned int uj=0;ujdata.size();uj++) + thisCentre+=ions->data[uj].getPosRef(); + massContrib=thisCentre*1.0/(float)ions->data.size(); + #pragma omp critical + massCentre+=massContrib; + numCentres++; + } + } + } + vectorParams[0]=massCentre*1.0/(float)numCentres; + break; + + } + case ORIGINMODE_SELECT: + break; + default: + ASSERT(false); + } + + //If the user is using a transform mode that requires origin selection + if(showOrigin && (transformMode == MODE_ROTATE || + transformMode == MODE_SCALE_ANISOTROPIC || + transformMode == MODE_SCALE_ISOTROPIC) ) + { + SelectionDevice *s; + getOut.push_back(makeMarkerSphere(s)); + if(s) + devices.push_back(s); + } + + //Apply the transformations to the incoming + //ion streams, generating new outgoing ion streams with + //the modified positions + size_t totalSize=numElements(dataIn); + if( transformMode != MODE_VALUE_SHUFFLE) + { + //Dont cross the streams. Why? It would be bad. + // - Im fuzzy on the whole good-bad thing, what do you mean bad?" + // - Every ion in the data body can be operated on independently. + // + // OK, important safety tip. + size_t n=0; + for(unsigned int ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + //Set up scaling output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + + try + { + d->data.resize(src->data.size()); + } + catch(std::bad_alloc) + { + delete d; + return ERR_NOMEM; + } + d->r = src->r; + d->g = src->g; + d->b = src->b; + d->a = src->a; + d->ionSize = src->ionSize; + d->valueType=src->valueType; + + ASSERT(src->data.size() <= totalSize); + unsigned int curProg=NUM_CALLBACK; +#ifdef _OPENMP + //Parallel version + bool spin=false; + #pragma omp parallel for shared(spin) + for(unsigned int ui=0;uidata.size();ui++) + { + unsigned int thisT=omp_get_thread_num(); + if(spin) + continue; + + if(!curProg--) + { + #pragma omp critical + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + } + + + if(thisT == 0) + { + if(!(*callback)(false)) + spin=true; + } + } + + + //set the position for the given ion + d->data[ui].setPos((src->data[ui].getPosRef() - origin)*scaleFactor+origin); + d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); + } + if(spin) + { + delete d; + return ERR_CALLBACK_FAIL; + } + +#else + //Single threaded version + size_t pos=0; + //Copy across the ions into the target + for(vector::const_iterator it=src->data.begin(); + it!=src->data.end(); ++it) + { + //set the position for the given ion + d->data[pos].setPos((it->getPosRef() - origin)*scaleFactor+origin); + d->data[pos].setMassToCharge(it->getMassToCharge()); + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + curProg=NUM_CALLBACK; + } + pos++; + } + + ASSERT(pos == d->data.size()); +#endif + ASSERT(d->data.size() == src->data.size()); + + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + break; + } + default: + //Just copy across the ptr, if we are unfamiliar with this type + getOut.push_back(dataIn[ui]); + break; + } + break; + } + case MODE_SCALE_ANISOTROPIC: + { + //We are going to scale the incoming point data + //around the specified origin. + ASSERT(vectorParams.size() == 2); + + + Point3D origin=vectorParams[0]; + Point3D transformVec=vectorParams[1]; + switch(dataIn[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + //Set up scaling output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + + try + { + d->data.resize(src->data.size()); + } + catch(std::bad_alloc) + { + delete d; + return ERR_NOMEM; + } + d->r = src->r; + d->g = src->g; + d->b = src->b; + d->a = src->a; + d->ionSize = src->ionSize; + d->valueType=src->valueType; + + ASSERT(src->data.size() <= totalSize); + unsigned int curProg=NUM_CALLBACK; +#ifdef _OPENMP + //Parallel version + bool spin=false; + #pragma omp parallel for shared(spin) + for(unsigned int ui=0;uidata.size();ui++) + { + unsigned int thisT=omp_get_thread_num(); + if(spin) + continue; + + if(!curProg--) + { + #pragma omp critical + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + } + + + if(thisT == 0) + { + if(!(*callback)(false)) + spin=true; + } + } + + + //set the position for the given ion + d->data[ui].setPos((src->data[ui].getPosRef() - origin)*transformVec+origin); + d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); + } + if(spin) + { + delete d; + return ERR_CALLBACK_FAIL; + } + +#else + //Single threaded version + size_t pos=0; + //Copy across the ions into the target + for(vector::const_iterator it=src->data.begin(); + it!=src->data.end(); ++it) + { + //set the position for the given ion + d->data[pos].setPos((it->getPosRef() - origin)*transformVec+origin); + d->data[pos].setMassToCharge(it->getMassToCharge()); + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + curProg=NUM_CALLBACK; + } + pos++; + } + + ASSERT(pos == d->data.size()); +#endif + ASSERT(d->data.size() == src->data.size()); + + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + break; + } + default: + //Just copy across the ptr, if we are unfamiliar with this type + getOut.push_back(dataIn[ui]); + break; + } + + + + + break; + } + case MODE_TRANSLATE: + { + //We are going to scale the incoming point data + //around the specified origin. + ASSERT(vectorParams.size() == 1); + ASSERT(scalarParams.size() == 0); + Point3D origin =vectorParams[0]; + switch(dataIn[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + //Set up scaling output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + try + { + d->data.resize(src->data.size()); + } + catch(std::bad_alloc) + { + delete d; + return ERR_NOMEM; + } + d->r = src->r; + d->g = src->g; + d->b = src->b; + d->a = src->a; + d->ionSize = src->ionSize; + d->valueType=src->valueType; + + ASSERT(src->data.size() <= totalSize); + unsigned int curProg=NUM_CALLBACK; +#ifdef _OPENMP + //Parallel version + bool spin=false; +#pragma omp parallel for shared(spin) + for(unsigned int ui=0;uidata.size();ui++) + { + unsigned int thisT=omp_get_thread_num(); + if(spin) + continue; + + if(!curProg--) + { +#pragma omp critical + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + } + + + if(thisT == 0) + { + if(!(*callback)(false)) + spin=true; + } + } + + + //set the position for the given ion + d->data[ui].setPos((src->data[ui].getPosRef() - origin)); + d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); + } + if(spin) + { + delete d; + return ERR_CALLBACK_FAIL; + } + +#else + //Single threaded version + size_t pos=0; + //Copy across the ions into the target + for(vector::const_iterator it=src->data.begin(); + it!=src->data.end(); ++it) + { + //set the position for the given ion + d->data[pos].setPos((it->getPosRef() - origin)); + d->data[pos].setMassToCharge(it->getMassToCharge()); + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + curProg=NUM_CALLBACK; + } + pos++; + } + ASSERT(pos == d->data.size()); +#endif + ASSERT(d->data.size() == src->data.size()); + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + break; + } + default: + //Just copy across the ptr, if we are unfamiliar with this type + getOut.push_back(dataIn[ui]); + break; + } + break; + } + case MODE_TRANSLATE_VALUE: + { + //We are going to scale the incoming point data + //around the specified origin. + ASSERT(vectorParams.size() == 0); + ASSERT(scalarParams.size() == 1); + float origin =scalarParams[0]; + switch(dataIn[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + //Set up scaling output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + try + { + d->data.resize(src->data.size()); + } + catch(std::bad_alloc) + { + delete d; + return ERR_NOMEM; + } + d->r = src->r; + d->g = src->g; + d->b = src->b; + d->a = src->a; + d->ionSize = src->ionSize; + d->valueType=src->valueType; + + ASSERT(src->data.size() <= totalSize); + unsigned int curProg=NUM_CALLBACK; +#ifdef _OPENMP + //Parallel version + bool spin=false; +#pragma omp parallel for shared(spin) + for(unsigned int ui=0;uidata.size();ui++) + { + unsigned int thisT=omp_get_thread_num(); + if(spin) + continue; + + if(!curProg--) + { +#pragma omp critical + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + } + + + if(thisT == 0) + { + if(!(*callback)(false)) + spin=true; + } + } + + + //set the position for the given ion + d->data[ui].setPos((src->data[ui].getPosRef())); + d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()+origin); + } + if(spin) + { + delete d; + return ERR_CALLBACK_FAIL; + } + +#else + //Single threaded version + size_t pos=0; + //Copy across the ions into the target + for(vector::const_iterator it=src->data.begin(); + it!=src->data.end(); ++it) + { + //set the position for the given ion + d->data[pos].setPos((it->getPosRef())); + d->data[pos].setMassToCharge(it->getMassToCharge() + origin); + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + curProg=NUM_CALLBACK; + } + pos++; + } + ASSERT(pos == d->data.size()); +#endif + ASSERT(d->data.size() == src->data.size()); + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + break; + } + default: + //Just copy across the ptr, if we are unfamiliar with this type + getOut.push_back(dataIn[ui]); + break; + } + break; + } + case MODE_ROTATE: + { + Point3D origin=vectorParams[0]; + switch(dataIn[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + //Set up output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + try + { + d->data.resize(src->data.size()); + } + catch(std::bad_alloc) + { + delete d; + return ERR_NOMEM; + } + d->r = src->r; + d->g = src->g; + d->b = src->b; + d->a = src->a; + d->ionSize = src->ionSize; + d->valueType=src->valueType; + + //We are going to rotate the incoming point data + //around the specified origin. + ASSERT(vectorParams.size() == 2); + ASSERT(scalarParams.size() == 1); + Point3D axis =vectorParams[1]; + axis.normalise(); + float angle=scalarParams[0]*M_PI/180.0f; + + unsigned int curProg=NUM_CALLBACK; + + Point3f rotVec,p; + rotVec.fx=axis[0]; + rotVec.fy=axis[1]; + rotVec.fz=axis[2]; + + Quaternion q1; + + //Generate the rotating quaternion + quat_get_rot_quat(&rotVec,-angle,&q1); + ASSERT(src->data.size() <= totalSize); + + + size_t pos=0; + + //TODO: Parallelise rotation + //Copy across the ions into the target + for(vector::const_iterator it=src->data.begin(); + it!=src->data.end(); ++it) + { + p.fx=it->getPosRef()[0]-origin[0]; + p.fy=it->getPosRef()[1]-origin[1]; + p.fz=it->getPosRef()[2]-origin[2]; + quat_rot_apply_quat(&p,&q1); + //set the position for the given ion + d->data[pos].setPos(p.fx+origin[0], + p.fy+origin[1],p.fz+origin[2]); + d->data[pos].setMassToCharge(it->getMassToCharge()); + //update progress every CALLBACK ions + if(!curProg--) + { + n+=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + curProg=NUM_CALLBACK; + } + pos++; + } + + ASSERT(d->data.size() == src->data.size()); + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + break; + } + default: + getOut.push_back(dataIn[ui]); + break; + } + + break; + } + case MODE_SPATIAL_NOISE: + { + ASSERT(scalarParams.size() ==1 && + vectorParams.size()==0); + switch(dataIn[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + //Set up scaling output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + try + { + d->data.resize(src->data.size()); + } + catch(std::bad_alloc) + { + delete d; + return ERR_NOMEM; + } + d->r = src->r; + d->g = src->g; + d->b = src->b; + d->a = src->a; + d->ionSize = src->ionSize; + d->valueType=src->valueType; + + float scaleFactor=scalarParams[0]; + ASSERT(src->data.size() <= totalSize); + unsigned int curProg=NUM_CALLBACK; + + //NOTE: This *cannot* be parallelised without parallelising the random + // number generator safely. If using multiple random number generators, + // one would need to ensure sufficient entropy in EACH generator. This + // is not trivial to prove, and so has not been done here. Bootstrapping + // each random number generator using non-random seeds could be problematic + // same as feeding back a random number into other rng instances + // + // One solution is to use the unix /dev/urandom interface or the windows + // cryptographic API, alternatively use the TR1 header's Mersenne twister with + // multi-seeding: + // http://theo.phys.sci.hiroshima-u.ac.jp/~ishikawa/PRNG/mt_stream_en.html + switch(noiseType) + { + case NOISETYPE_WHITE: + { + for(size_t ui=0;uidata.size();ui++) + { + Point3D pt; + + pt.setValue(0,randGen.genUniformDev()-0.5f); + pt.setValue(1,randGen.genUniformDev()-0.5f); + pt.setValue(2,randGen.genUniformDev()-0.5f); + + pt*=scaleFactor; + + //set the position for the given ion + d->data[ui].setPos(src->data[ui].getPosRef() + pt); + d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); + + + if(!curProg--) + { + curProg=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(ui)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + } + } + break; + } + case NOISETYPE_GAUSSIAN: + { + for(size_t ui=0;uidata.size();ui++) + { + Point3D pt; + + pt.setValue(0,randGen.genGaussDev()); + pt.setValue(1,randGen.genGaussDev()); + pt.setValue(2,randGen.genGaussDev()); + + pt*=scaleFactor; + + //set the position for the given ion + d->data[ui].setPos(src->data[ui].getPosRef() + pt); + d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); + + + if(!curProg--) + { + curProg=NUM_CALLBACK; + progress.filterProgress= (unsigned int)((float)(ui)/((float)totalSize)*100.0f); + if(!(*callback)(false)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + } + } + + break; + } + } + + ASSERT(d->data.size() == src->data.size()); + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + break; + } + default: + getOut.push_back(dataIn[ui]); + break; + } + break; + } + } + } + } + else + { + progress.step=1; + progress.filterProgress=0; + progress.stepName=TRANS("Collate"); + progress.maxStep=3; + if(!(*callback)(true)) + return ERR_CALLBACK_FAIL; + //we have to cross the streams (I thought that was bad?) + // - Each dataset is no longer independent, and needs to + // be mixed with the other datasets. Bugger; sounds mem. expensive. + + //Set up output ion stream + IonStreamData *d=new IonStreamData; + d->parent=this; + + //TODO: Better output colouring/size + //Set up ion metadata + d->r = 0.5; + d->g = 0.5; + d->b = 0.5; + d->a = 0.5; + d->ionSize = 2.0; + d->valueType=TRANS("Mass-to-Charge (amu/e)"); + + size_t curPos=0; + + vector massData; + + //TODO: Ouch. Memory intensive -- could do a better job + //of this? + try + { + massData.resize(totalSize); + d->data.resize(totalSize); + } + catch(std::bad_alloc) + { + return ERR_NOMEM; + } + + //merge the datasets + for(size_t ui=0;uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + + const IonStreamData *src = (const IonStreamData *)dataIn[ui]; + + //Loop through the ions in this stream, and copy its data value +#pragma omp parallel for shared(massData,d,curPos,src) + for(size_t uj=0;ujdata.size();uj++) + { + massData[uj+curPos] = src->data[uj].getMassToCharge(); + d->data[uj+curPos].setPos(src->data[uj].getPos()); + } + + if(!(*callback)(true)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + + curPos+=src->data.size(); + break; + } + default: + getOut.push_back(dataIn[ui]); + break; + } + } + + + progress.step=2; + progress.filterProgress=0; + progress.stepName=TRANS("Shuffle"); + if(!(*callback)(true)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + //Shuffle the value data.TODO: callback functor + std::random_shuffle(massData.begin(),massData.end()); + if(!(*callback)(true)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + + progress.step=3; + progress.filterProgress=0; + progress.stepName=TRANS("Splice"); + if(!(*callback)(true)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + + + + //Set the output data by splicing together the + //shuffled values and the original position info +#pragma omp parallel for shared(d,massData) + for(size_t uj=0;ujdata[uj].setMassToCharge(massData[uj]); + + if(!(*callback)(true)) + { + delete d; + return ERR_CALLBACK_FAIL; + } + + massData.clear(); + + if(cache) + { + d->cached=1; + filterOutputs.push_back(d); + cacheOK=true; + } + else + d->cached=0; + + getOut.push_back(d); + + } + return 0; +} + + +void TransformFilter::getProperties(FilterPropGroup &propertyList) const +{ + + FilterProperty p; + size_t curGroup=0; + string tmpStr; + vector > choices; + for(unsigned int ui=0;ui > choices; + for(unsigned int ui=0;ui::epsilon()) + return false; + + if(!(vectorParams[1] == newPt )) + { + vectorParams[1] = newPt; + needUpdate=true; + clearCache(); + } + + return true; + } + case KEY_ORIGINMODE: + { + size_t i; + for (i = 0; i < ORIGINMODE_END; i++) + if (value == TRANS(getOriginTypeString(i).c_str())) break; + + if( i == ORIGINMODE_END) + return false; + + if(originMode != i) + { + originMode = i; + needUpdate=true; + clearCache(); + } + return true; + } + case KEY_TRANSFORM_SHOWORIGIN: + { + string stripped=stripWhite(value); + + if(!(stripped == "1"|| stripped == "0")) + return false; + + showOrigin=(stripped=="1"); + + needUpdate=true; + + break; + } + case KEY_NOISETYPE: + { + size_t i; + for (i = 0; i < NOISETYPE_END; i++) + if (value == TRANS(getNoiseTypeString(i).c_str())) break; + + if( i == NOISETYPE_END) + return false; + + if(noiseType != i) + { + noiseType = i; + needUpdate=true; + clearCache(); + } + break; + } + default: + ASSERT(false); + } + return true; +} + + +std::string TransformFilter::getErrString(unsigned int code) const +{ + + switch(code) + { + //User aborted in a callback + case ERR_CALLBACK_FAIL: + return std::string(TRANS("Aborted")); + //Caught a memory issue + case ERR_NOMEM: + return std::string(TRANS("Unable to allocate memory")); + } + ASSERT(false); +} + +bool TransformFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << ""<"<"<"<" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool TransformFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Retrieve transformation type + //==== + if(!XMLGetNextElemAttrib(nodePtr,transformMode,"transformmode","value")) + return false; + if(transformMode>= MODE_ENUM_END) + return false; + //==== + + //Retrieve origination type + //==== + if(!XMLGetNextElemAttrib(nodePtr,originMode,"originmode","value")) + return false; + if(originMode>= ORIGINMODE_END) + return false; + //==== + + //Retrieve origination type + //==== + if(!XMLGetNextElemAttrib(nodePtr,originMode,"noisetype","value")) + return false; + if(noiseType>= NOISETYPE_END) + return false; + //==== + + //Retrieve origination type + //==== + if(!XMLGetNextElemAttrib(nodePtr,originMode,"showorigin","value")) + return false; + //==== + + //Retreive vector parameters + //=== + if(XMLHelpFwdToElem(nodePtr,"vectorparams")) + return false; + xmlNodePtr tmpNode=nodePtr; + + if(!readVectorsXML(nodePtr,vectorParams)) + return false; + //=== + + nodePtr=tmpNode; + //Retreive scalar parameters + //=== + if(XMLHelpFwdToElem(nodePtr,"scalarparams")) + return false; + + if(!readScalarsXML(nodePtr,scalarParams)) + return false; + //=== + + //Check the scalar params match the selected primitive + switch(transformMode) + { + case MODE_TRANSLATE: + if(vectorParams.size() != 1 || scalarParams.size() !=0) + return false; + break; + case MODE_SCALE_ISOTROPIC: + if(vectorParams.size() != 1 || scalarParams.size() !=1) + return false; + break; + case MODE_SCALE_ANISOTROPIC: + if(vectorParams.size() != 2 || scalarParams.size() !=0) + return false; + break; + case MODE_ROTATE: + if(vectorParams.size() != 2 || scalarParams.size() !=1) + return false; + break; + case MODE_TRANSLATE_VALUE: + if(vectorParams.size() != 0 || scalarParams.size() !=1) + return false; + break; + case MODE_VALUE_SHUFFLE: + case MODE_SPATIAL_NOISE: + break; + default: + ASSERT(false); + return false; + } + return true; +} + + +unsigned int TransformFilter::getRefreshBlockMask() const +{ + //Only ions cannot go through this filter. + return STREAM_TYPE_IONS; +} + +unsigned int TransformFilter::getRefreshEmitMask() const +{ + if(showPrimitive) + return STREAM_TYPE_IONS | STREAM_TYPE_DRAW; + else + return STREAM_TYPE_IONS; +} + +unsigned int TransformFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS; +} + +void TransformFilter::setPropFromBinding(const SelectionBinding &b) +{ + switch(b.getID()) + { + case BINDING_SPHERE_ORIGIN: + b.getValue(vectorParams[0]); + break; + default: + ASSERT(false); + } + clearCache(); +} + +std::string TransformFilter::getOriginTypeString(unsigned int i) +{ + ASSERT(ispan. +//span must be a 3-wide array, and numPts will be generated. +//each entry in the array should be coprime for optimal results. +//filter pointer must be deleted. +IonStreamData *synthDataPoints(unsigned int span[],unsigned int numPts); +bool rotateTest(); +bool translateTest(); +bool scaleTest(); +bool scaleAnisoTest(); +bool shuffleTest(); + +class MassCompare +{ + public: + inline bool operator()(const IonHit &h1,const IonHit &h2) const + {return h1.getMassToCharge()data.push_back(h); + } + + return d; +} + +bool rotateTest() +{ + //Simulate some data to send to the filter + vector streamIn,streamOut; + IonStreamData *d= new IonStreamData; + + RandNumGen rng; + rng.initTimer(); + + const unsigned int NUM_PTS=10000; + + + //Build a sphere of data points + //by rejection method + d->data.reserve(NUM_PTS/2); + for(unsigned int ui=0;uidata.push_back(h); + } + } + + streamIn.push_back(d); + + //Set up the filter itself + //--- + TransformFilter *f=new TransformFilter; + f->setCaching(false); + + + bool needUp; + string s; + TEST(f->setProperty(KEY_MODE, + TRANS(TRANSFORM_MODE_STRING[MODE_ROTATE]),needUp),"Set transform mode"); + float tmpVal; + tmpVal=rng.genUniformDev()*M_PI*2.0; + stream_cast(s,tmpVal); + TEST(f->setProperty(KEY_ROTATE_ANGLE,s,needUp),"Set rotate angle"); + Point3D tmpPt; + + //NOTE: Technically there is a nonzero chance of this failing. + tmpPt=Point3D(rng.genUniformDev()-0.5f, + rng.genUniformDev()-0.5f, + rng.genUniformDev()-0.5f); + stream_cast(s,tmpPt); + TEST(f->setProperty(KEY_ROTATE_AXIS,s,needUp),"set rotate axis"); + + TEST(f->setProperty(KEY_ORIGINMODE, + TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp),"Set origin"); + TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set no-show origin"); + //--- + + + //OK, so now do the rotation + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); + + const IonStreamData *outData=(IonStreamData*)streamOut[0]; + + Point3D massCentre[2]; + massCentre[0]=massCentre[1]=Point3D(0,0,0); + //Now check that the mass centre has not moved + for(unsigned int ui=0;uidata.size();ui++) + massCentre[0]+=d->data[ui].getPos(); + + for(unsigned int ui=0;uidata.size();ui++) + massCentre[1]+=outData->data[ui].getPos(); + + + TEST((massCentre[0]-massCentre[1]).sqrMag() < + 2.0*sqrt(std::numeric_limits::epsilon()),"mass centre invariance"); + + //Rotating a sphere around its centre of mass + // should not massively change the bounding box + // 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); + + float volumeRat; + volumeRat = bc[0].volume()/bc[1].volume(); + + TEST(volumeRat > 0.5f && volumeRat < 2.0f, "volume ratio test"); + + delete streamOut[0]; + delete d; + return true; +} + +bool translateTest() +{ + RandNumGen rng; + rng.initTimer(); + + //Simulate some data to send to the filter + vector streamIn,streamOut; + IonStreamData *d; + const unsigned int NUM_PTS=10000; + + unsigned int span[]={ + 5, 7, 9 + }; + d=synthDataPoints(span,NUM_PTS); + streamIn.push_back(d); + + Point3D offsetPt; + + //Set up the filter itself + //--- + TransformFilter *f=new TransformFilter; + + bool needUp; + string s; + TEST(f->setProperty(KEY_MODE, + TRANSFORM_MODE_STRING[MODE_TRANSLATE],needUp),"set translate mode"); + + //NOTE: Technically there is a nonzero chance of this failing. + offsetPt=Point3D(rng.genUniformDev()-0.5f, + rng.genUniformDev()-0.5f, + rng.genUniformDev()-0.5f); + offsetPt[0]*=span[0]; + offsetPt[1]*=span[1]; + offsetPt[2]*=span[2]; + + stream_cast(s,offsetPt); + TEST(f->setProperty(KEY_ORIGIN,s,needUp),"Set Origin"); + TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set display origin"); + //--- + + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); + + const IonStreamData *outData=(IonStreamData*)streamOut[0]; + + //Bound cube should move exactly as per the translation + BoundCube bc[2]; + bc[0]=getIonDataLimits(d->data); + bc[1]=getIonDataLimits(outData->data); + + for(unsigned int ui=0;ui<3;ui++) + { + for(unsigned int uj=0;uj<2;uj++) + { + float f; + f=bc[0].getBound(ui,uj) -bc[1].getBound(ui,uj); + TEST(fabs(f-offsetPt[ui]) < sqrt(std::numeric_limits::epsilon()), "bound translation"); + } + } + + delete d; + delete streamOut[0]; + + return true; +} + + +bool scaleTest() +{ + //Simulate some data to send to the filter + vector streamIn,streamOut; + IonStreamData *d; + + RandNumGen rng; + rng.initTimer(); + + const unsigned int NUM_PTS=10000; + + unsigned int span[]={ + 5, 7, 9 + }; + d=synthDataPoints(span,NUM_PTS); + streamIn.push_back(d); + + //Set up the filter itself + //--- + TransformFilter *f=new TransformFilter; + + bool needUp; + string s; + //Switch to scale mode (isotropic) + TEST(f->setProperty(KEY_MODE, + TRANS(TRANSFORM_MODE_STRING[MODE_SCALE_ISOTROPIC]),needUp),"Set scale mode"); + + + //Switch to mass-centre origin + TEST(f->setProperty(KEY_ORIGINMODE, + TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp),"Set origin->mass mode"); + + float scaleFact; + //Pick some scale, both positive and negative. + if(rng.genUniformDev() > 0.5) + scaleFact=rng.genUniformDev()*10; + else + scaleFact=0.1f/(0.1f+rng.genUniformDev()); + + stream_cast(s,scaleFact); + + TEST(f->setProperty(KEY_SCALEFACTOR,s,needUp),"Set scalefactor"); + //Don't show origin marker + TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set show origin") + //--- + + + //OK, so now do the rotation + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); + + const IonStreamData *outData=(IonStreamData*)streamOut[0]; + + //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); + + float cubeOfScale=scaleFact*scaleFact*scaleFact; + + float volumeDelta; + volumeDelta=fabs(bc[1].volume()/cubeOfScale - bc[0].volume() ); + + TEST(volumeDelta < 100.0f*sqrt(std::numeric_limits::epsilon()), "scaled volume test"); + + delete streamOut[0]; + delete d; + return true; +} + +bool scaleAnisoTest() +{ + //Simulate some data to send to the filter + vector streamIn,streamOut; + IonStreamData *d; + + RandNumGen rng; + rng.initTimer(); + + const unsigned int NUM_PTS=10000; + + unsigned int span[]={ + 5, 7, 9 + }; + d=synthDataPoints(span,NUM_PTS); + streamIn.push_back(d); + + //Set up the filter itself + //--- + TransformFilter *f=new TransformFilter; + + bool needUp; + string s; + //Switch to scale mode (isotropic) + TEST(f->setProperty(KEY_MODE, + TRANS(TRANSFORM_MODE_STRING[MODE_SCALE_ANISOTROPIC]),needUp),"Set scale mode"); + + + //Switch to mass-centre origin + TEST(f->setProperty(KEY_ORIGINMODE, + TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp),"Set origin->mass mode"); + + Point3D scaleFact; + //Pick some random scale vector, both positive and negative. + scaleFact=Point3D(rng.genUniformDev()*10,rng.genUniformDev()*10,rng.genUniformDev()*10); + + stream_cast(s,scaleFact); + + TEST(f->setProperty(KEY_SCALEFACTOR_ANISOTROPIC,s,needUp),"Set scalefactor"); + //Don't show origin marker + TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set show origin") + //--- + + + //OK, so now do the rotation + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); + + delete streamOut[0]; + delete d; + return true; +} +bool shuffleTest() +{ + //Simulate some data to send to the filter + vector streamIn,streamOut; + IonStreamData *d; + + RandNumGen rng; + rng.initTimer(); + + const unsigned int NUM_PTS=1000; + + unsigned int span[]={ + 5, 7, 9 + }; + d=synthDataPoints(span,NUM_PTS); + streamIn.push_back(d); + + //Set up the filter itself + //--- + TransformFilter *f=new TransformFilter; + + bool needUp; + //Switch to shuffle mode + TEST(f->setProperty(KEY_MODE, + TRANS(TRANSFORM_MODE_STRING[MODE_VALUE_SHUFFLE]),needUp),"refresh error code"); + //--- + + + //OK, so now run the shuffle + //Do the refresh + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); + TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); + + TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); + + IonStreamData *outData=(IonStreamData*)streamOut[0]; + + //Check to see that the output masses each exist in the input, + //but are not in the same sequence + //--- + + + bool sequenceDifferent=false; + for(size_t ui=0;uidata.size();ui++) + { + if(d->data[ui].getMassToCharge() != outData->data[ui].getMassToCharge()) + { + sequenceDifferent=true; + break; + } + } + TEST(sequenceDifferent, + "Should be shuffled - Prob. of sequence being identical in both orig & shuffled cases is very low"); + //Sort masses + MassCompare cmp; + std::sort(outData->data.begin(),outData->data.end(),cmp); + std::sort(d->data.begin(),d->data.end(),cmp); + + + for(size_t ui=0;uidata.size();ui++) + { + TEST(d->data[ui].getMassToCharge() == outData->data[ui].getMassToCharge(),"Shuffle + Sort mass should be the same"); + + } + + + + delete streamOut[0]; + delete d; + return true; +} + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/transform.h 3depict-0.0.13/src/backend/filters/transform.h --- 3depict-0.0.12/src/backend/filters/transform.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/transform.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * transform.h - Perform geometrical transform operations on point clouds + * 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 . +*/ +#ifndef TRANSFORM_H +#define TRANSFORM_H + +#include "../filter.h" +#include "../../common/translation.h" + +//!Affine transformation filter +class TransformFilter : public Filter +{ + private: + //!Transform mode (scale, rotate, translate) + unsigned int transformMode; + + //!Show origin if needed; + bool showOrigin; + //!Mode for selection of origin for transform + unsigned int originMode; + //!Mode for particular noise type + unsigned int noiseType; + //!Scalar values for transformation (scaling factors, rotation angle ) + std::vector scalarParams; + //!Vector values for transformation (translation or rotation vectors) + std::vector vectorParams; + + //!Should we show the origin primitive markers? + bool showPrimitive; + + static std::string getOriginTypeString(unsigned int i); + + static std::string getNoiseTypeString(unsigned int i); + + //!Make the marker sphere + DrawStreamData* makeMarkerSphere(SelectionDevice* &s) const; + + //!random number generator + RandNumGen randGen; + public: + TransformFilter(); + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + //!Returns -1, as range file cache size is dependant upon input. + virtual size_t numBytesForCache(size_t nObjects) const; + + + //!Returns FILTER_TYPE_TRANSFORM + unsigned int getType() const { return FILTER_TYPE_TRANSFORM;}; + //update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + //!Force a re-read of the rangefile Return value is range file reading error code + unsigned int updateRng(); + virtual std::string typeString() const { return std::string(TRANS("Ion. Transform"));}; + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshUseMask() const; + + //!Set internal property value using a selection binding (Disabled, this filter has no bindings) + void setPropFromBinding(const SelectionBinding &b); + +#ifdef DEBUG + bool runUnitTests(); +#endif +}; +#endif + diff -Nru 3depict-0.0.12/src/backend/filters/voxelise.cpp 3depict-0.0.13/src/backend/filters/voxelise.cpp --- 3depict-0.0.12/src/backend/filters/voxelise.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/voxelise.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1685 @@ +/* + * voxelise.cpp - Compute 3D binning (voxelisation) of point clouds + * 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 . +*/ + +#include "voxelise.h" + +#include "filterCommon.h" + +#include + +enum +{ + KEY_FIXEDWIDTH, + KEY_NBINSX, + KEY_NBINSY, + KEY_NBINSZ, + KEY_WIDTHBINSX, + KEY_WIDTHBINSY, + KEY_WIDTHBINSZ, + KEY_COUNT_TYPE, + KEY_NORMALISE_TYPE, + KEY_SPOTSIZE, + KEY_TRANSPARANCY, + KEY_COLOUR, + KEY_ISOLEVEL, + KEY_VOXEL_REPRESENTATION_MODE, + KEY_FILTER_MODE, + KEY_FILTER_BOUNDARY_MODE, + KEY_FILTER_BINS, + KEY_ENABLE_NUMERATOR, + KEY_ENABLE_DENOMINATOR +}; + +//!Normalisation method +enum +{ + VOXELISE_NORMALISETYPE_NONE,// straight count + VOXELISE_NORMALISETYPE_VOLUME,// density + VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL, // concentration + VOXELISE_NORMALISETYPE_COUNT2INVOXEL,// ratio count1/count2 + VOXELISE_NORMALISETYPE_MAX // keep this at the end so it's a bookend for the last value +}; + +//!Filtering mode +enum +{ + VOXELISE_FILTERTYPE_NONE, + VOXELISE_FILTERTYPE_GAUSS, + VOXELISE_FILTERTYPE_MAX // keep this at the end so it's a bookend for the last value +}; + + +//Boundary behaviour for filtering +enum +{ + VOXELISE_FILTERBOUNDMODE_ZERO, + VOXELISE_FILTERBOUNDMODE_BOUNCE, + VOXELISE_FILTERBOUNDMODE_MAX// keep this at the end so it's a bookend for the last value +}; + +enum +{ + VOXELISE_ABORT_ERR, + VOXELISE_MEMORY_ERR, + VOXELISE_CONVOLVE_ERR, + VOXELISE_BOUNDS_INVALID_ERR +}; + +const char *NORMALISE_TYPE_STRING[] = { + NTRANS("None (Raw count)"), + NTRANS("Volume (Density)"), + NTRANS("All Ions (conc)"), + NTRANS("Ratio (Num/Denom)"), + }; + +const char *REPRESENTATION_TYPE_STRING[] = { + NTRANS("Point Cloud"), + NTRANS("Isosurface") + }; + +const char *VOXELISE_FILTER_TYPE_STRING[]={ + NTRANS("None"), + NTRANS("Gaussian (2𝜎)"), + }; + +const char *VOXELISE_FILTER_BOUND_STRING[] ={ + NTRANS("Zero"), + NTRANS("Bounce") + }; + +//This is not a member of voxels.h, as the voxels do not have any concept of the IonHit +int countPoints(Voxels &v, const std::vector &points, + bool noWrap,bool (*callback)(bool)) +{ + + size_t x,y,z; + size_t binCount[3]; + v.getSize(binCount[0],binCount[1],binCount[2]); + + unsigned int downSample=MAX_CALLBACK; + for (size_t ui=0; ui v.getData(x,y,z)) + v.setData(x,y,z,value); + } else { + v.setData(x,y,z,value); + } + } + } + } + return 0; +} + +// == Voxels filter == +VoxeliseFilter::VoxeliseFilter() +: fixedWidth(false), normaliseType(VOXELISE_NORMALISETYPE_NONE) +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(NORMALISE_TYPE_STRING) == VOXELISE_NORMALISETYPE_MAX); + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXELISE_FILTER_TYPE_STRING) == VOXELISE_FILTERTYPE_MAX ); + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXELISE_FILTER_BOUND_STRING) == VOXELISE_FILTERBOUNDMODE_MAX); + + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(REPRESENTATION_TYPE_STRING) == VOXEL_REPRESENT_END); + + splatSize=1.0f; + a=0.9f; + r=g=b=0.5; + isoLevel=0.5; + + filterBins=3; + filterMode=VOXELISE_FILTERTYPE_NONE; + filterBoundaryMode=VOXELISE_FILTERBOUNDMODE_BOUNCE; + gaussDev=0.5; + + representation=VOXEL_REPRESENT_POINTCLOUD; + + + //Ficticious bounds. + bc.setBounds(Point3D(0,0,0),Point3D(1,1,1)); + + for (unsigned int i = 0; i < INDEX_LENGTH; i++) + nBins[i] = 50; + + calculateWidthsFromNumBins(binWidth,nBins); + + numeratorAll = false; + denominatorAll = true; + + cacheOK=false; + cache=true; //By default, we should cache, but decision is made higher up + + + rsdIncoming=0; +} + + +Filter *VoxeliseFilter::cloneUncached() const +{ + VoxeliseFilter *p=new VoxeliseFilter(); + p->splatSize=splatSize; + p->a=a; + p->r=r; + p->g=g; + p->b=b; + + p->isoLevel=isoLevel; + + p->filterMode=filterMode; + p->filterBoundaryMode=filterBoundaryMode; + p->filterBins=filterBins; + p->gaussDev=gaussDev; + + p->representation=representation; + p->splatSize=splatSize; + + p->normaliseType=normaliseType; + p->numeratorAll=numeratorAll; + p->denominatorAll=denominatorAll; + + p->bc=bc; + + for(size_t ui=0;uinBins[ui] = nBins[ui]; + p->binWidth[ui] = binWidth[ui]; + } + + p->enabledIons[0].resize(enabledIons[0].size()); + std::copy(enabledIons[0].begin(),enabledIons[0].end(),p->enabledIons[0].begin()); + + p->enabledIons[1].resize(enabledIons[1].size()); + std::copy(enabledIons[1].begin(),enabledIons[1].end(),p->enabledIons[1].begin()); + + if(rsdIncoming) + { + p->rsdIncoming=new RangeStreamData(); + *(p->rsdIncoming) = *rsdIncoming; + } + else + p->rsdIncoming=0; + + p->cache=cache; + p->cacheOK=false; + p->userString=userString; + return p; +} + +size_t VoxeliseFilter::numBytesForCache(size_t nObjects) const +{ + //if we are using fixed width, we know the answer. + //otherwise we dont until we are presented with the boundcube. + //TODO: Modify the function description to pass in the boundcube + if(!fixedWidth) + return nBins[0]*nBins[1]*nBins[2]*sizeof(float); + else + return 0; +} + +void VoxeliseFilter::initFilter(const std::vector &dataIn, + std::vector &dataOut) +{ + const RangeStreamData *c=0; + //Determine if we have an incoming range + for (size_t i = 0; i < dataIn.size(); i++) + { + if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE) + { + c=(const RangeStreamData *)dataIn[i]; + + break; + } + } + + //we no longer (or never did) have any incoming ranges. Not much to do + if(!c) + { + //delete the old incoming range pointer + if(rsdIncoming) + delete rsdIncoming; + rsdIncoming=0; + + enabledIons[0].clear(); //clear numerator options + enabledIons[1].clear(); //clear denominator options + + //Prevent normalisation type being set incorrectly + // if we have no incoming range data + if(normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL || normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL) + normaliseType= VOXELISE_NORMALISETYPE_NONE; + } + else + { + + + //If we didn't have an incoming rsd, then make one up! + if(!rsdIncoming) + { + rsdIncoming = new RangeStreamData; + *rsdIncoming=*c; + + //set the numerator to all disabled + enabledIons[0].resize(rsdIncoming->rangeFile->getNumIons(),0); + //set the denominator to have all enabled + enabledIons[1].resize(rsdIncoming->rangeFile->getNumIons(),1); + } + else + { + + //OK, so we have a range incoming already (from last time) + //-- the question is, is it the same + //one we had before + //Do a pointer comparison (its a hack, yes, but it should work) + if(rsdIncoming->rangeFile != c->rangeFile) + { + //hmm, it is different. well, trash the old incoming rng + delete rsdIncoming; + + rsdIncoming = new RangeStreamData; + *rsdIncoming=*c; + + //set the numerator to all disabled + enabledIons[0].resize(rsdIncoming->rangeFile->getNumIons(),0); + //set the denominator to have all enabled + enabledIons[1].resize(rsdIncoming->rangeFile->getNumIons(),1); + } + } + + } +} + +unsigned int VoxeliseFilter::refresh(const std::vector &dataIn, + std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) +{ + for(size_t ui=0;uigetStreamType() & getRefreshBlockMask() )) + getOut.push_back(dataIn[ui]); + } + + //use the cached copy if we have it. + if(cacheOK) + { + for(size_t ui=0;uigetStreamType() != 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; + bcTmp=getIonDataLimits(is->data); + + //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.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; + + 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 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) + { + + for (size_t i = 0; i < dataIn.size(); i++) + { + + //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 = 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) { + 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); + } + + if(!(*callback)(false)) + { + delete vs; + return VOXELISE_ABORT_ERR; + } + } + + //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++) + { + + if(dataIn[i]->getStreamType() == STREAM_TYPE_IONS) + { + is= (const IonStreamData *)dataIn[i]; + + countPoints(vs->data,is->data,true,callback); + + if(!(*callback)(false)) + { + delete vs; + return VOXELISE_ABORT_ERR; + } + + } + } + ASSERT(normaliseType != VOXELISE_NORMALISETYPE_COUNT2INVOXEL + && normaliseType!=VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL); + if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME) + vs->data.calculateDensity(); + } + + vsDenom.clear(); + + + //Perform voxel filtering + switch(filterMode) + { + case VOXELISE_FILTERTYPE_NONE: + break; + case VOXELISE_FILTERTYPE_GAUSS: + { + Voxels kernel,res; + + map modeMap; + + + 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 + + //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; + + //Gaussian kernel is separable (rank 1) + if(vs->data.separableConvolve(kernel,res,modeMap[filterBoundaryMode])) + return VOXELISE_CONVOLVE_ERR; + + vs->data.swap(res); + + res.clear(); + break; + } + default: + ASSERT(false); + } + + + float min,max; + vs->data.minMax(min,max); + + + string sMin,sMax; + stream_cast(sMin,min); + stream_cast(sMax,max); + consoleOutput.push_back(std::string(TRANS("Voxel Limits (min,max): (") + sMin + string(",")) + + sMax + ")"); + 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); + + //Copy the inputs into the outputs, provided they are not voxels + return 0; +} + +std::string VoxeliseFilter::getNormaliseTypeString(int type){ + ASSERT(type < VOXELISE_NORMALISETYPE_MAX); + return TRANS(NORMALISE_TYPE_STRING[type]); +} + +std::string VoxeliseFilter::getRepresentTypeString(int type) { + ASSERT(type > choices; + tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_NONE); + choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_NONE,tmpStr)); + tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_VOLUME); + choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_VOLUME,tmpStr)); + if(rsdIncoming) + { + //Concentration mode + tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL); + choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL,tmpStr)); + //Ratio is only valid if we have a way of separation for the ions i.e. range + tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_COUNT2INVOXEL); + choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_COUNT2INVOXEL,tmpStr)); + } + + tmpStr= choiceString(choices,normaliseType); + p.name=TRANS("Normalise by"); + p.data=tmpStr; + p.type=PROPERTY_TYPE_CHOICE; + p.helpText=TRANS("Method to use to normalise scalar value in each voxel"); + p.key=KEY_NORMALISE_TYPE; + propertyList.addProperty(p,curGroup); + propertyList.setGroupTitle(curGroup,TRANS("Computation")); + + curGroup++; + + // numerator + if (rsdIncoming) + { + p.name=TRANS("Numerator"); + p.data=numeratorAll ? "1" : "0"; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Parmeter \"a\" used in fraction (a/b) to get voxel value"); + p.key=KEY_ENABLE_NUMERATOR; + propertyList.addProperty(p,curGroup); + + ASSERT(rsdIncoming->enabledIons.size()==enabledIons[0].size()); + ASSERT(rsdIncoming->enabledIons.size()==enabledIons[1].size()); + + //Look at the numerator + for(unsigned int ui=0; uienabledIons.size(); ui++) + { + string str; + if(enabledIons[0][ui]) + str="1"; + else + str="0"; + + //Append the ion name with a checkbox + p.name=rsdIncoming->rangeFile->getName(ui); + p.data=str; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Enable this ion for numerator"); + p.key=KEY_ENABLE_NUMERATOR*1000+ui; + propertyList.addProperty(p,curGroup); + } + + curGroup++; + } + + + if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL && rsdIncoming) + { + p.name=TRANS("Denominator"); + p.data=denominatorAll ? "1" : "0"; + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Parameter \"b\" used in fraction (a/b) to get voxel value"); + p.key=KEY_ENABLE_DENOMINATOR; + + for(unsigned int ui=0; uienabledIons.size(); ui++) + { + string str; + if(enabledIons[1][ui]) + str="1"; + else + str="0"; + + //Append the ion name with a checkbox + p.key=KEY_ENABLE_DENOMINATOR*1000 + ui; + p.data=str; + p.name=rsdIncoming->rangeFile->getName(ui); + p.type=PROPERTY_TYPE_BOOL; + p.helpText=TRANS("Enable this ion for denominator contribution"); + + propertyList.addProperty(p,curGroup); + } + curGroup++; + } + + //Start a new set for filtering + //---- + //TODO: Other filtering? threshold/median? laplacian? etc + + choices.clear(); + + //Post-filtering method + for(unsigned int ui=0;uisplatSize=splatSize; + } + } + + } + break; + } + case KEY_TRANSPARANCY: + { + float f; + if(stream_cast(f,value)) + return false; + if(f < 0.0f || f > 1.0) + return false; + needUpdate=true; + //Alpha is opacity, which is 1-transparancy + a=1.0f-f; + //Go in and manually adjust the cached + //entries to have the new value, rather + //than doing a full recomputation + if(cacheOK) + { + for(unsigned int ui=0;uia=a; + } + } + break; + } + case KEY_ISOLEVEL: + { + float f; + if(stream_cast(f,value)) + return false; + if(f <= 0.0f) + return false; + needUpdate=true; + isoLevel=f; + //Go in and manually adjust the cached + //entries to have the new value, rather + //than doing a full recomputation + if(cacheOK) + { + for(unsigned int ui=0;uiisoLevel=isoLevel; + } + } + break; + } + case KEY_COLOUR: + { + unsigned char newR,newG,newB,newA; + + parseColString(value,newR,newG,newB,newA); + + if(newB != b || newR != r || + newG !=g || newA != a) + needUpdate=true; + r=newR/255.0; + g=newG/255.0; + b=newB/255.0; + //Go in and manually adjust the cached + //entries to have the new value, rather + //than doing a full recomputation + if(cacheOK) + { + for(unsigned int ui=0;uir=r; + d->g=g; + d->b=b; + } + } + break; + } + case KEY_VOXEL_REPRESENTATION_MODE: + { + 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) + { + for(unsigned int ui=0;uirepresentationType=representation; + } + } + break; + } + case KEY_ENABLE_NUMERATOR: + { + bool b; + if(stream_cast(b,value)) + return false; + //Set them all to enabled or disabled as a group + for (size_t i = 0; i < enabledIons[0].size(); i++) + enabledIons[0][i] = b; + numeratorAll = b; + needUpdate=true; + clearCache(); + break; + } + case KEY_ENABLE_DENOMINATOR: + { + bool b; + if(stream_cast(b,value)) + return false; + + //Set them all to enabled or disabled as a group + for (size_t i = 0; i < enabledIons[1].size(); i++) + enabledIons[1][i] = b; + + denominatorAll = b; + needUpdate=true; + clearCache(); + break; + } + case KEY_FILTER_MODE: + { + unsigned int i; + for (i = 0; i < VOXEL_REPRESENT_END; i++) + if (value == getFilterTypeString(i)) break; + if (i == VOXEL_REPRESENT_END) + return false; + if(i!=filterMode) + { + needUpdate=true; + filterMode=i; + clearCache(); + } + break; + } + case KEY_FILTER_BOUNDARY_MODE: + { + unsigned int i; + for (i = 0; i < VOXELISE_FILTERBOUNDMODE_MAX; i++) + if (value == getFilterBoundTypeString(i)) break; + if (i == VOXELISE_FILTERTYPE_MAX) + return false; + + if(i != filterBoundaryMode) + { + filterBoundaryMode=i; + needUpdate=true; + clearCache(); + } + break; + } + case KEY_FILTER_BINS: + { + unsigned int i; + if(stream_cast(i,value)) + return false; + + //FIXME: Min restriction is artificial and imposed due to incomplete separable convolution filter implementation + if(i == 0 || i > std::min(nBins[0],std::min(nBins[1],nBins[2]))) + return false; + if(i != filterBins) + { + needUpdate=true; + filterBins=i; + clearCache(); + } + break; + } + default: + { + if (key >= KEY_ENABLE_DENOMINATOR*1000) { + bool b; + if(stream_cast(b,value)) + return false; + + enabledIons[1][key - KEY_ENABLE_DENOMINATOR*1000]=b; + if (!b) { + denominatorAll = false; + } + needUpdate=true; + clearCache(); + } else if (key >= KEY_ENABLE_NUMERATOR*1000) { + bool b; + if(stream_cast(b,value)) + return false; + + enabledIons[0][key - KEY_ENABLE_NUMERATOR*1000]=b; + if (!b) { + numeratorAll = false; + } + needUpdate=true; + clearCache(); + } + else + { + ASSERT(false); + } + break; + } + } + return true; +} + +std::string VoxeliseFilter::getErrString(unsigned int code) const +{ + switch(code) + { + case VOXELISE_ABORT_ERR: + return std::string(TRANS("Voxelisation aborted")); + case VOXELISE_MEMORY_ERR: + return std::string(TRANS("Out of memory")); + case VOXELISE_CONVOLVE_ERR: + return std::string(TRANS("Unable to perform filter convolution")); + case VOXELISE_BOUNDS_INVALID_ERR: + return std::string(TRANS("Voxelisation bounds are invalid")); + } + + return std::string("BUG! Should not see this (VoxeliseFilter)"); +} + +bool VoxeliseFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + { + f << tabs(depth) << "<" << trueName() << ">" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+2) << "" << endl; + for(unsigned int ui=0;ui" << endl; + f << tabs(depth+2) << "" << endl; + + f << tabs(depth+2) << "" << endl; + for(unsigned int ui=0;ui" << endl; + f << tabs(depth+2) << "" << endl; + + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" << endl; + f << tabs(depth+1) << "" <" << endl; + break; + } + default: + ASSERT(false); + return false; + } + + return true; +} + +bool VoxeliseFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) +{ + using std::string; + string tmpStr; + xmlChar *xmlString; + stack nodeStack; + + //Retrieve user string + //=== + if(XMLHelpFwdToElem(nodePtr,"userstring")) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + if(!xmlString) + return false; + userString=(char *)xmlString; + xmlFree(xmlString); + //=== + + //Retrieve fixedWidth mode + if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixedwidth","value")) + return false; + if(tmpStr == "1") + fixedWidth=true; + else if(tmpStr== "0") + fixedWidth=false; + else + return false; + + //Retrieve nBins + if(XMLHelpFwdToElem(nodePtr,"nbins")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values"); + if(!xmlString) + return false; + std::vector v1; + splitStrsRef((char *)xmlString,',',v1); + for (size_t i = 0; i < INDEX_LENGTH && i < v1.size(); i++) + { + if(stream_cast(nBins[i],v1[i])) + return false; + + if(nBins[i] <= 0) + return false; + } + xmlFree(xmlString); + + //Retrieve bin width + if(XMLHelpFwdToElem(nodePtr,"binwidth")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values"); + if(!xmlString) + return false; + std::vector v2; + splitStrsRef((char *)xmlString,',',v2); + for (size_t i = 0; i < INDEX_LENGTH && i < v2.size(); i++) + { + if(stream_cast(binWidth[i],v2[i])) + return false; + + if(binWidth[i] <= 0) + return false; + } + xmlFree(xmlString); + + //Retrieve normaliseType + if(!XMLGetNextElemAttrib(nodePtr,normaliseType,"normalisetype","value")) + return false; + if(normaliseType >= VOXELISE_NORMALISETYPE_MAX) + return false; + + //Look for the enabled ions bit + //------- + // + + if(!XMLHelpFwdToElem(nodePtr,"enabledions")) + { + + nodeStack.push(nodePtr); + if(!nodePtr->xmlChildrenNode) + return false; + nodePtr=nodePtr->xmlChildrenNode; + + //enabled ions for numerator + if(XMLHelpFwdToElem(nodePtr,"numerator")) + return false; + + nodeStack.push(nodePtr); + + if(!nodePtr->xmlChildrenNode) + return false; + + nodePtr=nodePtr->xmlChildrenNode; + + while(nodePtr) + { + char c; + //Retrieve representation + if(!XMLGetNextElemAttrib(nodePtr,c,"enabled","value")) + break; + + if(c == '1') + enabledIons[0].push_back(true); + else + enabledIons[0].push_back(false); + + + nodePtr=nodePtr->next; + } + + nodePtr=nodeStack.top(); + nodeStack.pop(); + + //enabled ions for denominator + if(XMLHelpFwdToElem(nodePtr,"denominator")) + return false; + + + if(!nodePtr->xmlChildrenNode) + return false; + + nodeStack.push(nodePtr); + nodePtr=nodePtr->xmlChildrenNode; + + while(nodePtr) + { + char c; + //Retrieve representation + if(!XMLGetNextElemAttrib(nodePtr,c,"enabled","value")) + break; + + if(c == '1') + enabledIons[1].push_back(true); + else + enabledIons[1].push_back(false); + + + nodePtr=nodePtr->next; + } + + + nodeStack.pop(); + nodePtr=nodeStack.top(); + nodeStack.pop(); + + //Check that the enabled ions size makes at least some sense... + if(enabledIons[0].size() != enabledIons[1].size()) + return false; + + } + + //------- + //Retrieve representation + if(!XMLGetNextElemAttrib(nodePtr,representation,"representation","value")) + return false; + if(representation >=VOXEL_REPRESENT_END) + return false; + + //------- + //Retrieve representation + if(!XMLGetNextElemAttrib(nodePtr,isoLevel,"isovalue","value")) + return false; + + //Retrieve colour + //==== + if(XMLHelpFwdToElem(nodePtr,"colour")) + return false; + if(!parseXMLColour(nodePtr,r,g,b,a)) + return false; + + //==== + return true; + +} + +unsigned int VoxeliseFilter::getRefreshBlockMask() const +{ + //Ions, plots and voxels cannot pass through this filter + return STREAM_TYPE_IONS | STREAM_TYPE_PLOT | STREAM_TYPE_VOXEL; +} + +unsigned int VoxeliseFilter::getRefreshEmitMask() const +{ + return STREAM_TYPE_VOXEL | STREAM_TYPE_DRAW; +} + +unsigned int VoxeliseFilter::getRefreshUseMask() const +{ + return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; +} + +void VoxeliseFilter::setPropFromBinding(const SelectionBinding &b) +{ +} + +#ifdef DEBUG +bool voxelSingleCountTest() +{ + //Test counting a single vector + + vector ionVec; + + ionVec.resize(5); + ionVec[0].setPos(Point3D(0.1,0.1,0.1)); + ionVec[1].setPos(Point3D(0.1,0.0,0.1)); + ionVec[2].setPos(Point3D(0.0,0.1,0.1)); + ionVec[3].setPos(Point3D(0.1,0.1,0.0)); + ionVec[4].setPos(Point3D(0.0,0.1,0.0)); + + for(unsigned int ui=0;uidata,ionVec); + + size_t numIons=ionData->data.size(); + + VoxeliseFilter *f = new VoxeliseFilter; + f->setCaching(false); + + bool needUpdate; + TEST(f->setProperty(KEY_NBINSX,"4",needUpdate),"num bins x"); + TEST(f->setProperty(KEY_NBINSY,"4",needUpdate),"num bins y"); + TEST(f->setProperty(KEY_NBINSZ,"4",needUpdate),"num bins z"); + + + vector streamIn,streamOut; + streamIn.push_back(ionData); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + delete f; + + TEST(streamOut.size() == 1,"stream count"); + TEST(streamOut[0]->getStreamType() == STREAM_TYPE_VOXEL,"Stream type"); + + + const VoxelStreamData *v= (const VoxelStreamData*)streamOut[0]; + + TEST(v->data.max() <=numIons, + "voxel max less than input stream") + + TEST(v->data.min() >= 0.0f,"voxel counting minimum sanity"); + + + float dataSum; + sumVoxels(v->data,dataSum); + TEST(fabs(dataSum - (float)numIons ) < + sqrt(std::numeric_limits::epsilon()),"voxel counting all input ions "); + + delete ionData; + delete streamOut[0]; + + return true; +} + +bool voxelMultiCountTest() +{ + //Test counting multiple data streams containing ranged data + + vector streamIn,streamOut; + vector ionVec; + + ionVec.resize(5); + ionVec[0].setPos(Point3D(0.1,0.1,0.1)); + ionVec[1].setPos(Point3D(0.1,0.0,0.1)); + ionVec[2].setPos(Point3D(0.0,0.1,0.1)); + ionVec[3].setPos(Point3D(0.1,0.1,0.0)); + ionVec[4].setPos(Point3D(0.0,0.1,0.0)); + + IonStreamData *ionData[2]; + RangeStreamData *rngStream; + rngStream = new RangeStreamData; + rngStream->rangeFile= new RangeFile; + + RGBf col; col.red=col.green=col.blue=1.0f; + + const unsigned int MAX_NUM_RANGES=2; + for(unsigned int ui=0;uirangeFile->addIon(sTmp,sTmp,col); + rngStream->rangeFile->addRange((float)ui-0.5f,(float)ui+0.5f,ionNum); + + //Change m/c value for ion + for(unsigned int uj=0;ujdata.resize(ionVec.size()); + std::copy(ionVec.begin(),ionVec.end(),ionData[ui]->data.begin()); + streamIn.push_back(ionData[ui]); + } + + rngStream->enabledIons.resize(rngStream->rangeFile->getNumIons()); + rngStream->enabledRanges.resize(rngStream->rangeFile->getNumRanges()); + + streamIn.push_back(rngStream); + + VoxeliseFilter *f = new VoxeliseFilter; + + //Initialise range data + f->initFilter(streamIn,streamOut); + + + f->setCaching(false); + + bool needUpdate; + TEST(f->setProperty(KEY_NBINSX,"4",needUpdate),"num bins x"); + TEST(f->setProperty(KEY_NBINSY,"4",needUpdate),"num bins y"); + TEST(f->setProperty(KEY_NBINSZ,"4",needUpdate),"num bins z"); + + + TEST(f->setProperty(KEY_NORMALISE_TYPE, + TRANS(NORMALISE_TYPE_STRING[VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL]),needUpdate), + "Set normalise mode"); + + ProgressData p; + TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); + delete f; + for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_VOXEL,"Stream type"); + + const VoxelStreamData *v= (const VoxelStreamData*)streamOut[1]; + + TEST(v->data.max() <=1.0f, + "voxel max less than input stream") + TEST(v->data.min() >= 0.0f,"voxel counting minimum sanity"); + + + for(unsigned int ui=0;uidata.getSize();ui++) + { + float delta; + delta=(v->data.getData(ui) - v->data.getData(0) ); + ASSERT( v->data.getData(ui) == 0 || delta < std::numeric_limits::epsilon()); + } + + delete v; + + delete rngStream->rangeFile; + delete rngStream; + + return true; +} + + +bool VoxeliseFilter::runUnitTests() +{ + + if(!voxelSingleCountTest()) + return false; + + if(!voxelMultiCountTest()) + return false; + + + return true; +} + +#endif diff -Nru 3depict-0.0.12/src/backend/filters/voxelise.h 3depict-0.0.13/src/backend/filters/voxelise.h --- 3depict-0.0.12/src/backend/filters/voxelise.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filters/voxelise.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,153 @@ +/* + * voxelise.h - Compute 3D binning (voxelisation) of point clouds + * 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 . +*/ +#ifndef VOXELISE_H +#define VOXELISE_H +#include "../filter.h" +#include "../../common/translation.h" + +//!Filter that does voxelisation for various primitives (copied from CompositionFilter) +class VoxeliseFilter : public Filter +{ +private: + const static size_t INDEX_LENGTH = 3; + + //Enabled ions for numerator/denom + std::vector enabledIons[2]; + + //!Stepping mode - fixed width or fixed number of bins + bool fixedWidth; + + //!number of bins (if using fixed bins) + unsigned long long nBins[INDEX_LENGTH]; + //!Width of each bin (if using fixed wdith) + Point3D binWidth; + //!boundcube for the input data points + BoundCube bc; + + //!density-based or count-based + unsigned int normaliseType; + bool numeratorAll, denominatorAll; + //This is filter's enabled ranges + RangeStreamData *rsdIncoming; + + float r,g,b,a; + + //!Filter mode to apply to data before output + unsigned int filterMode; + + //!How do we treat boundaries when applying filters + unsigned int filterBoundaryMode; + + //!Filter size + unsigned int filterBins; + + //!Gaussian filter standard deviation + float gaussDev; + + //!3D Point Representation size + float splatSize; + + //!Isosurface level + float isoLevel; + //!Default output representation mode + unsigned int representation; +public: + VoxeliseFilter(); + ~VoxeliseFilter() { if(rsdIncoming) delete rsdIncoming;} + //!Duplicate filter contents, excluding cache. + Filter *cloneUncached() const; + + + + //!Get approx number of bytes for caching output + size_t numBytesForCache(size_t nObjects) const; + + unsigned int getType() const { return FILTER_TYPE_VOXELS;}; + + virtual void initFilter(const std::vector &dataIn, + std::vector &dataOut); + //!update filter + unsigned int refresh(const std::vector &dataIn, + std::vector &getOut, + ProgressData &progress, bool (*callback)(bool)); + + virtual std::string typeString() const { return std::string(TRANS("Voxelisation"));}; + + //!Get the human-readable options for the normalisation, based upon enum + static std::string getNormaliseTypeString(int type); + //!Get the human-readable options for filtering, based upon enum + static std::string getFilterTypeString(int type); + //!Get the human-readable options for the visual representation (enum) + static std::string getRepresentTypeString(int type); + //!Get the human-readable options for boundary behaviour during filtering, based upon enum + static std::string getFilterBoundTypeString(int type); + + //!Get the properties of the filter, in key-value form. First vector is for each output. + void getProperties(FilterPropGroup &propertyList) const; + + //!Set the properties for the nth filter. Returns true if prop set OK + bool setProperty(unsigned int key, + const std::string &value, bool &needUpdate); + //!Get the human readable error string associated with a particular error code during refresh(...) + std::string getErrString(unsigned int code) const; + + //!Dump state to output stream, using specified format + bool writeState(std::ostream &f,unsigned int format, + unsigned int depth=0) const; + //!Read the state of the filter from XML file. If this + //fails, filter will be in an undefined state. + bool readState(xmlNodePtr &node, const std::string &packDir); + + //!Get the stream types that will be dropped during ::refresh + unsigned int getRefreshBlockMask() const; + + //!Get the stream types that will be generated during ::refresh + unsigned int getRefreshEmitMask() const; + + //!Get the stream types that will be possibly ued during ::refresh + unsigned int getRefreshUseMask() const; + //!Set internal property value using a selection binding + void setPropFromBinding(const SelectionBinding &b) ; + + + //!calculate the widths of the bins in 3D + void calculateWidthsFromNumBins(Point3D &widths, unsigned long long *nb) const{ + Point3D low, high; + bc.getBounds(low, high); + for (unsigned int i = 0; i < 3; i++) { + widths[i] = (high[i] - low[i])/(float)nb[i]; + } + } + //!set the number of the bins in 3D + void calculateNumBinsFromWidths(Point3D &widths, unsigned long long *nb) const{ + Point3D low, high; + bc.getBounds(low, high); + for (unsigned int i = 0; i < 3; i++) { + if (low[i] == high[i]) nb[i] = 1; + else nb[i] = (unsigned long long)((high[i] - low[i])/(float)widths[i]) + 1; + } + } + +#ifdef DEBUG + bool runUnitTests(); +#endif + +}; + +#endif + diff -Nru 3depict-0.0.12/src/backend/filtertree.cpp 3depict-0.0.13/src/backend/filtertree.cpp --- 3depict-0.0.12/src/backend/filtertree.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filtertree.cpp 2013-04-10 20:01:35.000000000 +0000 @@ -0,0 +1,1806 @@ +/* + * filtertree.cpp - Filter tree topology and data propagation handling + * 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 . +*/ + + + +#include "filtertree.h" +#include "filters/allFilter.h" + +#include "common/xmlHelper.h" +#include "common/stringFuncs.h" + +using std::string; + +enum +{ + CACHE_DEPTH_FIRST=1, + CACHE_NEVER, +}; + + +//Simple garbage collector for FilterTree::refresh +// does not have to be efficient, as it is assumed that this is not a bottleneck +class FilterRefreshCollector +{ + private: + //Pile of lists of pointers that we are tracking + vector > nodes; + + //Find out if a filter tracks itself or not + static bool tracksSelf(const FilterStreamData *p) { return p->cached;} + +#ifdef DEBUG + void checkSanity(); +#endif + + public: + FilterRefreshCollector() {}; + ~FilterRefreshCollector() ; + + //Add pointers that are to be garbage collected, if they don't maintain + // their own ownership + void trackPointers(const vector &vecPtrs); + + //Stop tracking the specified pointers + void forgetPointers(const vector &vecPtrs); + + //clean up all pointers in list + void collectAll(); + unsigned int getLevel() const { return nodes.size();} + void collectToLevel(unsigned int level); + +}; + +#ifdef DEBUG +void FilterRefreshCollector::checkSanity() +{ + //Should never have a duplicate - flatten object to find out + set s; + for(size_t ui=0;ui::iterator it=nodes[ui].begin(); + it!=nodes[ui].end(); ++it) + { + //Check that we hve not already inserted this + ASSERT(s.find(*it) == s.end()) + s.insert(*it); + } + } + s.clear(); + + //Should never have something that tracks itself + for(size_t ui=0;ui::iterator it=nodes[ui].begin(); + it!=nodes[ui].end(); ++it) + { + ASSERT(!tracksSelf(*it) ) + } + } + +} +#endif + +FilterRefreshCollector::~FilterRefreshCollector() +{ +#ifdef DEBUG + checkSanity(); +#endif + collectAll(); +} + +void FilterRefreshCollector::trackPointers(const vector &v) +{ + //Just remember the pointers we want to track + list lKeep; + for(size_t ui=0;ui &v) +{ +#ifdef DEBUG + checkSanity(); +#endif + for(size_t uj=0;uj::iterator it; + it=std::find(nodes[ui].begin(),nodes[ui].end(),v[uj]) ; + if(it != nodes[ui].end()) + { + nodes[ui].erase(it); + //We deleted the source of this, no need to continue + // checking for this particular pointer. + break; + } + } + } + +} + +void FilterRefreshCollector::collectAll() +{ +#ifdef DEBUG + checkSanity(); +#endif + for(size_t ui=0;ui< nodes.size() ;ui++) + { + for(list::iterator it=nodes[ui].begin(); it!=nodes[ui].end(); ++it) + delete *it; + } + + nodes.clear(); +} + + +void FilterRefreshCollector::collectToLevel(unsigned int level) +{ +#ifdef DEBUG + checkSanity(); +#endif + for(size_t ui=level+1;ui::iterator it=nodes[ui].begin(); it!=nodes[ui].end(); ++it) + delete *it; + } + + nodes.resize(level); +} + + + +const float DEFAULT_MAX_CACHE_PERCENT=50; + +void popPointerStack(std::stack > &inDataStack, + unsigned int depth) +{ + + while(inDataStack.size() > depth) + { + //We no longer need this level + inDataStack.pop(); + } +} + +FilterTree::FilterTree() +{ + maxCachePercent=DEFAULT_MAX_CACHE_PERCENT; + cacheStrategy=CACHE_DEPTH_FIRST; +} + +FilterTree::~FilterTree() +{ + clear(); +} + +FilterTree::FilterTree(const FilterTree &orig) : + cacheStrategy(orig.cacheStrategy), maxCachePercent(orig.maxCachePercent), + filters(orig.filters) +{ + //Don't grab a direct copy of the tree, but rather an cloned duplicate, + // without the internal cache data + for(tree::pre_order_iterator it=filters.begin(); + it!=filters.end();++it) + (*it)=(*it)->cloneUncached(); +} + +size_t FilterTree::depth(const tree::pre_order_iterator &it) const +{ + ASSERT(std::find(filters.begin(),filters.end(),*it)!=filters.end()); + return filters.depth(it); +} + +void FilterTree::swap(FilterTree &other) +{ + std::swap(cacheStrategy,other.cacheStrategy); + std::swap(maxCachePercent,other.maxCachePercent); + std::swap(filters,other.filters); +} + +const FilterTree &FilterTree::operator=(const FilterTree &orig) +{ + cacheStrategy=orig.cacheStrategy; + maxCachePercent=orig.maxCachePercent; + + filters=orig.filters; + + //Don't grab a direct copy of the tree, but rather an cloned duplicate, + // without the internal cache data + for(tree::pre_order_iterator it=filters.begin(); + it!=filters.end();++it) + (*it)=(*it)->cloneUncached(); + + return *this; +} + +size_t FilterTree::maxDepth() const +{ + return filters.max_depth(); +} + +void FilterTree::initFilterTree() const +{ + vector< const FilterStreamData *> curData; + stack > inDataStack; + list > outData; + + FilterRefreshCollector refreshCollector; + + //Do not allow stack to empty + inDataStack.push(curData); + refreshCollector.trackPointers(curData); + + //Depth-first search from root node, refreshing filters as we proceed. + for(tree::pre_order_iterator filtIt=filters.begin(); + filtIt!=filters.end(); ++filtIt) + { + //Step 0 : Pop the cache until we reach our current level, + // deleting any pointers that would otherwise be lost. + //--- + size_t popLevel; + popLevel=filters.depth(filtIt)+1; + popPointerStack(inDataStack,popLevel); + refreshCollector.collectToLevel(popLevel); + ASSERT(refreshCollector.getLevel() == inDataStack.size()); + //--- + + //Step 1: Take the stack top, and turn it into "curdata" using the filter + // record the result on the stack + //--- + //Take the stack top, filter it and generate "curData" + (*filtIt)->initFilter(inDataStack.top(),curData); + +#ifdef DEBUG + //Peform some quick sanity checks + for(unsigned int ui=0;uicached); + } +#endif + + + //Step 2: Put output in the intermediary stack, + //so it is available for any other children at this level. + inDataStack.push(curData); + + //Track pointers for garbage collection + refreshCollector.trackPointers(curData); + + curData.clear(); + //--- + } +} + +void FilterTree::clear() +{ + for(tree::iterator filterIt=filters.begin(); + filterIt!=filters.end();++filterIt) + delete (*filterIt); + + filters.clear(); +} + +void FilterTree::getAccumulatedPropagationMaps(map &emitTypes, map &blockTypes) const +{ + //Build the emit type map. This describes + //what possible types can be emitted at any point in the tree. + for(tree::iterator it=filters.begin_breadth_first(); + it!=filters.end_breadth_first(); ++it) + { + //FIXME: HACK -- why does the BFS not terminate correctly? + if(!filters.is_valid(it)) + break; + + size_t curEmit; + //Root node is special, does not combine with the + //previous filter + if(!filters.depth(it)) + curEmit=(*it)->getRefreshEmitMask(); + else + { + //Normal child. We need to remove any types that + //are blocked (& (~blocked)), then add any types that are emitted + //(|) + curEmit=emitTypes[*(filters.parent(it))]; + curEmit&=(~(*it)->getRefreshBlockMask() )& STREAMTYPE_MASK_ALL; + curEmit|=(*it)->getRefreshEmitMask(); + } + + ASSERT(curEmit < STREAMTYPE_MASK_ALL); + emitTypes.insert(make_pair(*it,curEmit)); + + } + + + + + //Build the accumulated block map; this describes + //what types, if emitted, will NOT be propagated to the final output + //Nor affect any downstream filters + for(size_t ui=filters.max_depth()+1; ui; ) + { + ui--; + + for(tree::iterator it=filters.begin(); it!=filters.end(); ++it) + { + //Check to see if we are at the correct depth + if(filters.depth(it) != ui) + continue; + + + //Initially assume that everything is passed through + //filter + int blockMask=0x0; + + + if((*it)->haveCache()) + { + //Loop over the children of this filter, grab their block masks + for(tree::sibling_iterator itJ=it.begin(); itJ!=it.end(); ++itJ) + { + + if((*itJ)->haveCache()) + { + int curBlockMask; + curBlockMask=(*itJ)->getRefreshBlockMask(); + blockMask= (blockMask & curBlockMask); + + } + else + { + blockMask&=0; + //The only reason to keep looping is to + //alter the blockmask. If it is at any point zero, + //then the answer will be zero, due to the & operator. + break; + } + + } + + //OK, so we now know which filters the children will ALL block. + //Combine this with our block list for this filter, and we this will give ush + //the blocklist for this subtree section + blockMask|=(*it)->getRefreshBlockMask(); + } + else + blockMask=0; + + blockTypes.insert(make_pair(*it,blockMask)); + } + + } + + + +} + + +void FilterTree::getFilterRefreshStarts(vector::iterator > &propStarts) const +{ + + if(!filters.size()) + return; + + const bool STUPID_ALGORITHM=false; + if(STUPID_ALGORITHM) + { + //Stupid version + //start at root every time + propStarts.push_back(filters.begin()); + } + else + { + //Do something hopefully non-stupid. Here we examine the types of data that are + //propagated through the tree, and which filters emit, or block transmission + //of any given type (ie their output is influenced only by certain data types). + + //From this information, and the cache status of each filter + //(recall caches only cache data generated inside the filter), it is possible to + //skip certain initial element refreshes. + + //Block and emit adjuncts for tree + map accumulatedEmitTypes,accumulatedBlockTypes; + getAccumulatedPropagationMaps(accumulatedEmitTypes,accumulatedBlockTypes); + + vector::iterator > seedFilts; + + + + + for(tree::iterator it=filters.begin_breadth_first(); + it!=filters.end_breadth_first(); ++it) + { + //FIXME: HACK -- why does the BFS not terminate correctly? + if(!filters.is_valid(it)) + break; + + //Check to see if we have an insertion point above us. + //if so, we cannot press on, as we have determined that + //we must start higher up. + bool isChildFilt; + isChildFilt=false; + for(unsigned int ui=0; ui::leaf_iterator itJ= filters.begin_leaf(); + itJ!=filters.end_leaf(); ++itJ) + + { + if(itJ == it) + { + isLeaf=true; + seedFilts.push_back(it); + break; + } + } + + if(isLeaf) + continue; + + //Check to see if we can use these children as insertion + //points in the tree + //i.e., ask, "Do all subtrees block everything we emit from here?" + int emitMask,blockMask; + emitMask=accumulatedEmitTypes[*it]; + blockMask=~0; + for(tree::sibling_iterator itJ=filters.begin(it); itJ!=filters.end(it); ++itJ) + blockMask&=accumulatedBlockTypes[*itJ]; + + + + + + if( emitMask & ((~blockMask) & STREAMTYPE_MASK_ALL)) + { + + //Oh noes! we don't block, we will have to stop here, + // for this subtree. We cannot go further down. + seedFilts.push_back(it); + } + + } + + propStarts.swap(seedFilts); + } + +#ifdef DEBUG + for(unsigned int ui=0; ui &outData, + std::vector *> &devices, + vector > &consoleMessages, + ProgressData &curProg, bool (*callback)(bool)) const +{ + + unsigned int errCode=0; + + if(!filters.size()) + return 0; + + //Destroy any caches that belong to monitored filters that need + //refreshing. Failing to do this can lead to filters being skipped + //during the refresh + for(tree::iterator filterIt=filters.begin(); + filterIt!=filters.end();++filterIt) + { + //We need to clear the cache of *all* + //downstream filters, as otherwise + //their cache's could block our update. + if((*filterIt)->monitorNeedsRefresh()) + { + for(tree::pre_order_iterator it(filterIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(filterIt) >= filters.depth(it) && it!=filterIt ) + break; + + (*it)->clearCache(); + } + } + } + + + // -- Build data streams -- + vector< const FilterStreamData *> curData; + stack > inDataStack; + FilterRefreshCollector refreshCollector; + + //Push some dummy data onto the stack to prime first-pass (call to refresh(..) requires stack + //size to be non-zero) + inDataStack.push(curData); + + + //Keep redoing the refresh until the user stops fiddling with the filter tree. + + vector::iterator> baseTreeNodes; + + baseTreeNodes.clear(); + + //Find the minimal starting locations for the refresh - eg. we can skip certain filters + // depending upon filter cache status and dependency data, and just start from sub-nodes + getFilterRefreshStarts(baseTreeNodes); + curProg.totalNumFilters=countChildFilters(filters,baseTreeNodes)+baseTreeNodes.size(); + + + (*callback)(false); + + for(unsigned int itPos=0;itPos::pre_order_iterator filtIt=baseTreeNodes[itPos]; + filtIt!=filters.end(); ++filtIt) + { + //Check to see if this node is a child of the base node. + //if not, move on. + if( filtIt!= baseTreeNodes[itPos] && + !isChild(filters,baseTreeNodes[itPos],filtIt)) + continue; + + + //Step 0 : Pop the cache until we reach our current level, + // delete any pointers that would otherwise be lost. + // Recall that the zero size in the stack may not correspond to the + // tree root, but rather corresponds to our insertion level + //--- + size_t popLevel; + popLevel=filters.depth(filtIt) - filters.depth(baseTreeNodes[itPos])+1; + popPointerStack(inDataStack,popLevel); + refreshCollector.collectToLevel(popLevel); + //--- + + //Step 1: Set up the progress system + //--- + curProg.clock(); + curProg.curFilter=*filtIt; + //--- + + //Step 2: Check if we should cache this filter or not. + //Get the number of bytes that the filter expects to use + //--- + unsigned long long cacheBytes; + if(inDataStack.empty()) + cacheBytes=(*filtIt)->numBytesForCache(0); + else + cacheBytes=(*filtIt)->numBytesForCache(numElements(inDataStack.top())); + + if(cacheBytes != (unsigned long long)(-1)) + { + //As long as we have caching enabled, let us cache according to the + //selected strategy + switch(cacheStrategy) + { + case CACHE_NEVER: + (*filtIt)->setCaching(false); + break; + case CACHE_DEPTH_FIRST: + (*filtIt)->setCaching(cacheBytes/(1024*1024) < maxCachePercent*getAvailRAM()); + break; + + } + } + else + (*filtIt)->setCaching(false); + + //--- + + //Step 3: Take the stack top, and turn it into "curdata" and refresh using the filter. + // Record the result on the stack. + // We also record any Selection devices that are generated by the filter. + // This is the guts of the system. + //--- + // + (*callback)(false); + + + //Take the stack top, filter it and generate "curData" + errCode=(*filtIt)->refresh(inDataStack.top(), + curData,curProg,callback); + +#ifdef DEBUG + //Perform sanity checks on filter output + checkRefreshValidity(curData,*filtIt); + ASSERT(curProg.step == curProg.maxStep || errCode); +#endif + //Ensure that (1) yield is called, regardless of what filter does + //(2) yield is called after 100% update + curProg.filterProgress=100; + (*callback)(false); + + + vector *> curDevices; + //Retrieve the user interaction "devices", and send them to the scene + (*filtIt)->getSelectionDevices(curDevices); + + //Add them to the total list of devices + for(size_t ui=0;ui tmpMessages; + (*filtIt)->getConsoleStrings(tmpMessages); + //Accumulate the messages + consoleMessages.reserve(consoleMessages.size()+tmpMessages.size()); + for(size_t ui=0;ui::iterator it=outData.begin(); + it!=outData.end();++it) + { + for(size_t ui=0;uisecond.size();ui++) + { + const FilterStreamData *data; + data = it->second[ui]; + + //Output data is uncached - delete it + if(!data->cached) + delete data; + } + } + return errCode; + } + + + //Update the filter output statistics, eg num objects of each type output + (*filtIt)->updateOutputInfo(curData); + + + //is this node a leaf of the tree? + bool isLeaf; + isLeaf=false; + for(tree::leaf_iterator leafIt=filters.begin_leaf(); + leafIt!=filters.end_leaf(); ++leafIt) + { + if(*leafIt == *filtIt) + { + isLeaf=true; + break; + } + } + + if(curData.size()) + { + //If this is not a leaf, keep track of intermediary pointers + if(!isLeaf) + { + //The filter will generate a list of new pointers. If any out-going data + //streams are un-cached, track them + refreshCollector.trackPointers(curData); + + //Put this in the intermediary stack, + //so it is available for any other children at this leve. + inDataStack.push(curData); + } + else + { + //The filter has created an output. Record it for passing to updateScene + outData.push_back(make_pair(*filtIt,curData)); + refreshCollector.forgetPointers(curData); + } + //Cur data is recorded either in outDta or on the data stack + curData.clear(); + } + //--- + + } + + } + + popPointerStack(inDataStack,0); + //Clean up any remaining intermediary pointers + refreshCollector.collectAll(); + + //====Output scrubbing === + + //Should be no duplicate pointers in output data. + //(this makes preventing double frees easier, and + // minimises unnecessary output) + //Construct a single list of all pointers in output, + //checking for uniqueness. Delete duplicates + list flatList; + + for(list::iterator it=outData.begin();it!=outData.end(); ) + { + vector::iterator itJ; + + itJ=it->second.begin(); + while(itJ!=it->second.end()) + { + //Each stream data pointer should only occur once in the entire lot. + if(find(flatList.begin(),flatList.end(),*itJ) == flatList.end()) + { + flatList.push_back(*itJ); + ++itJ; + } + else + { + itJ=it->second.erase(itJ); + } + } + + if(it->second.empty()) + it=outData.erase(it); + else + ++it; + } + + //outData List is complete, and contains only unique entries. clear the checking list. + flatList.clear(); + + //====== + + + + return 0; +} + +bool FilterTree::setFilterProperty(Filter *targetFilter, unsigned int key, + const std::string &value, bool &needUpdate) +{ + ASSERT(std::find(filters.begin(),filters.end(),targetFilter) != filters.end()); + if(!targetFilter->setProperty(key,value,needUpdate)) + return false; + + //If we no longer have a cache, and the filter needs an update, then we must + //modify the downstream objects + if(needUpdate) + { + for(tree::pre_order_iterator filtIt=filters.begin(); + filtIt!=filters.end(); ++filtIt) + { + if(targetFilter == *filtIt) + { + //Kill all cache below filtIt + for(tree::pre_order_iterator it(filtIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(filtIt) >= filters.depth(it) && it!=filtIt ) + break; + + //Do not clear the cache for the target filter. + //This is the responsibility of the setProperty function for the filter + if(*it !=targetFilter) + (*it)->clearCache(); + } + break; + } + } + + } + + initFilterTree(); + return true; + +} + +unsigned int FilterTree::loadXML(const xmlNodePtr &treeParent, std::ostream &errStream,const std::string &stateFileDir) + +{ + clear(); + + //Parse the filter tree in the XML file. + //generating a filter tree + bool inTree=true; + tree::iterator lastFilt=filters.begin(); + tree::iterator lastTop=filters.begin(); + stack::iterator> treeNodeStack; + + xmlNodePtr nodePtr = treeParent->xmlChildrenNode; + + + //push root tag + std::stack nodeStack; + nodeStack.push(nodePtr); + + bool needCleanup=false; + while (inTree) + { + //Jump to the next XML node at this depth + if (XMLHelpNextType(nodePtr,XML_ELEMENT_NODE)) + { + //If there is not one, pop the tree stack + if (!treeNodeStack.empty()) + { + //Pop the node stack for the XML and filter trees. + nodePtr=nodeStack.top(); + nodeStack.pop(); + lastFilt=treeNodeStack.top(); + treeNodeStack.pop(); + } + else + { + //Did we run out of stack? + //then we have finished the tree. + inTree=false; + } + continue; + } + + Filter *newFilt; + bool nodeUnderstood; + newFilt=0; + nodeUnderstood=true; //assume by default we understand, and set false if not + + //If we encounter a "children" node. then we need to look at the children of this filter + if (!xmlStrcmp(nodePtr->name,(const xmlChar*)"children")) + { + //Can't have children without parent + if (!filters.size()) + { + needCleanup=true; + break; + } + + //Child node should have its own child + if (!nodePtr->xmlChildrenNode) + { + needCleanup=true; + break; + } + + nodeStack.push(nodePtr); + treeNodeStack.push(lastFilt); + + nodePtr=nodePtr->xmlChildrenNode; + continue; + } + else + { + //Well, its not a "children" node, so it could + //be a filter... Lets find out + std::string tmpStr; + tmpStr=(char *)nodePtr->name; + + newFilt=makeFilter(tmpStr); + if(newFilt) + { + if (!newFilt->readState(nodePtr->xmlChildrenNode,stateFileDir)) + { + needCleanup=true; + break; + } + } + else + { + errStream << TRANS("WARNING: Skipping node ") << (const char *)nodePtr->name << TRANS(" as it was not recognised") << endl; + nodeUnderstood=false; + } + } + + + //Skip this item + if (nodeUnderstood) + { + ASSERT(newFilt); + + //Add the new item the tree + if (filters.empty()) + lastFilt=filters.insert(filters.begin(),newFilt); + else + { + if (!treeNodeStack.empty()) + lastFilt=filters.append_child(treeNodeStack.top(),newFilt); + else + { + lastTop=filters.insert(lastTop,newFilt); + lastFilt=lastTop; + } + + + } + + } + } + + + //All good? + if(!needCleanup) + return 0; + + //OK, we hit an error, we need to delete any pointers on the + //cleanup list + if(nodePtr) + errStream << TRANS("Error processing node: ") << (const char *)nodePtr->name << endl; + + clear(); + + //No good.. + return 1; + +} + +bool FilterTree::saveXML(std::ofstream &f,std::map &fileMapping, + bool writePackage, bool useRelativePaths, unsigned int minTabDepth) const +{ + f << tabs(minTabDepth+1) << "" << endl; + //Depth-first search, enumerate all filters in depth-first fashion + unsigned int depthLast=0; + unsigned int child=0; + for(tree::pre_order_iterator filtIt=filters.begin(); + filtIt!=filters.end(); ++filtIt) + { + unsigned int depth; + depth = filters.depth(filtIt); + if(depth >depthLast) + { + while(depthLast++ < depth) + { + f << tabs(minTabDepth+depthLast+1); + f << "" << endl; + child++; + } + } + else if (depth < depthLast) + { + while(depthLast-- > depth) + { + f << tabs(minTabDepth+depthLast+2); + f << "" << endl; + child--; + } + } + + //If we are writing a package, override the filter storage values + if(writePackage || useRelativePaths) + { + vector valueOverrides; + (*filtIt)->getStateOverrides(valueOverrides); + + //The overrides, at the moment, only are files. + //So lets find them & move them + for(unsigned int ui=0;ui::const_iterator it; + it =fileMapping.find(valueOverrides[ui]); + + if(it == fileMapping.end()) + { + //map does not exist, so make it! + fileMapping[newFilename]=valueOverrides[ui]; + } + else if (it->second !=valueOverrides[ui]) + { + //Keep adding a prefix until we find a valid new filename + while(fileMapping.find(newFilename) != fileMapping.end()) + newFilename="remap"+newFilename; + //map does not exist, so make it! + fileMapping[newFilename]=valueOverrides[ui]; + } + valueOverrides[ui] = newFilename; + } + + if(!(*filtIt)->writePackageState(f,STATE_FORMAT_XML,valueOverrides,depth+2)) + return false; + } + else + { + if(!(*filtIt)->writeState(f,STATE_FORMAT_XML,depth+2)) + return false; + } + depthLast=depth; + } + + //Close out filter tree. + while(child--) + { + f << tabs(minTabDepth+child+2) << "" << endl; + } + f << tabs(minTabDepth+1) << "" << endl; + + return true; +} + + +bool FilterTree::hasHazardousContents() const +{ + //Check the filter system for "hazardous" contents. + // each filter defines what it believes is "hazardous" + for(tree::pre_order_iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if ((*it)->canBeHazardous()) + return true; + } + + return false; +} + +void FilterTree::stripHazardousContents() +{ + for(tree::pre_order_iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if ((*it)->canBeHazardous()) + { + //delete filters from this branch + for(tree::pre_order_iterator itj(it); itj!=filters.end(); ++itj) + delete *itj; + + + //nuke this branch + it=filters.erase(it); + --it; + } + } + +} + +bool FilterTree::isChild(const tree &treeInst, + const tree::iterator &testParent, + tree::iterator testChild) const +{ + // NOTE: A comparison against tree root (treeInst.begin())is INVALID + // for trees that have multiple base nodes. + while(treeInst.depth(testChild)) + { + testChild=treeInst.parent(testChild); + + if(testChild== testParent) + return true; + } + + return false; +} + +bool FilterTree::contains(const Filter *f) const +{ + return std::find(filters.begin(),filters.end(),f) != filters.end(); +} + +size_t FilterTree::countChildFilters(const tree &treeInst, + const vector::iterator> &nodes) +{ + set childIts; + for(size_t ui=0;ui::pre_order_iterator it=nodes[ui]; + it!=treeInst.end();++it) + childIts.insert(*it); + + } + + return childIts.size()-nodes.size(); +} + + +#ifdef DEBUG +void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &curData, + const Filter *refreshFilter) const +{ + + //Filter outputs should + // - never be null pointers. + for(size_t ui=0; ui::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if(*it == curData[ui]->parent) + found=true; + } + + ASSERT(found); + } + + //Filter outputs should + // - never contain duplicate pointers + for(size_t ui=0; uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *ionData; + ionData=((const IonStreamData *)f); + + ASSERT(ionData->data.size()); + break; + } + default: + ; + } + + } + + //Filter outputs should + // - Always have isCached set to 0 or 1. + // - Filter should report that it has a cache, if it is emitting cached objects + // - If caching is disabled, filter should not be caching objects + bool hasSomeCached=false; + for(size_t ui=0; uicached == 1 || + curData[ui]->cached == 0); + + if(curData[ui]->parent == refreshFilter) + { + if(!(refreshFilter->cacheEnabled()) ) + { + ASSERT(curData[ui]->cached==0); + } + hasSomeCached|=curData[ui]->cached; + } + } + + ASSERT(!(hasSomeCached == false && refreshFilter->haveCache())); + + //Filter outputs for this filter should + // -only be from those specified in filter emit mask + for(size_t ui=0; uiparent) + { + cerr << "Warning: orphan filter stream (FilterStreamData::parent == 0)." << + "This must be set when creating new filter streams in the ::refresh function for the filter." << endl; + cerr << "Filter :" << refreshFilter->getUserString() << "Stream Type: " << + STREAM_NAMES[getBitNum(curData[ui]->getStreamType())] << endl; + } + else if(curData[ui]->parent == refreshFilter) + { + //Check we emitted something that our parent's emit mask said we should + // by performing bitwise ops + ASSERT(curData[ui]->getStreamType() & + refreshFilter->getRefreshEmitMask()); + } + } + + //plot output streams should only have known types + //for various identifiers + for(size_t ui=0; uigetStreamType() != STREAM_TYPE_PLOT) + continue; + + const PlotStreamData *p; + p =(const PlotStreamData*)curData[ui]; + +#ifdef DEBUG + p->checkSelfConsistent(); +#endif + } + + //Voxel output streams should only have known types + for(size_t ui=0; uigetStreamType() != STREAM_TYPE_VOXEL) + continue; + + const VoxelStreamData *p; + p =(const VoxelStreamData*)curData[ui]; + + //Must have valid representation + ASSERT(p->representationType< VOXEL_REPRESENT_END); + } + +} +#endif + +void FilterTree::safeDeleteFilterList( std::list &outData, + size_t typeMask, bool maskPrevents) const +{ + //Loop through the list of vectors of filterstreamdata, then drop any elements that are deleted + for(list ::iterator it=outData.begin(); + it!=outData.end(); ) + { + //Note the No-op at the loop iterator. this is needed so we can safely .erase() + for(size_t ui=0;uisecond.size();ui++) + { + //Don't operate on streams if we have a nonzero mask, and the (mask is active XOR mask mode) + //NOTE: the XOR flips the action of the mask. if maskprevents is true, then this logical switch + //prevents the masked item from being deleted. If not, ONLY the masked types are deleted. + //In any case, a zero mask makes this whole thing not do anything, and everything gets deleted. + if(typeMask && ( ((bool)(it->second[ui]->getStreamType() & typeMask)) ^ !maskPrevents)) + continue; + + switch(it->second[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + //Iterator points to vector. Typecast elements in vector to IonStreamData + const IonStreamData *ionData; + ionData=((const IonStreamData *)(it->second[ui])); + + ASSERT(ionData->cached == 1 || + ionData->cached == 0); + + if(!ionData->cached) + delete ionData; + break; + } + case STREAM_TYPE_PLOT: + { + const PlotStreamData *plotData; + plotData=((PlotStreamData *)it->second[ui]); + + ASSERT(plotData->cached == 1 || + plotData->cached == 0); + if(!plotData->cached) + delete plotData; + + break; + } + case STREAM_TYPE_DRAW: + { + DrawStreamData *drawData; + drawData=((DrawStreamData *)it->second[ui]); + + ASSERT(drawData->cached == 1 || + drawData->cached == 0); + if(drawData->cached) + delete drawData; + break; + } + case STREAM_TYPE_RANGE: + //Range data has no allocated pointer + break; + case STREAM_TYPE_VOXEL: + { + //Iterator points to vector. Typecast elements in vector to VoxelStreamData + const VoxelStreamData *voxelData; + voxelData=((const VoxelStreamData *)(it->second[ui])); + + ASSERT(voxelData->cached == 1 || + voxelData->cached == 0); + + if(!voxelData->cached) + delete voxelData; + break; + } + default: + ASSERT(false); + } + + + std::swap((it->second[ui]),it->second.back()); + it->second.pop_back(); + } + + //Check to see if this element still has any items in its vector. if not, + //then discard the element + if(!(it->second.size())) + it=outData.erase(it); + else + ++it; + + } +} + +void FilterTree::getFiltersByType(std::vector &filtersOut, unsigned int type) const +{ + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if((*it)->getType() == type) + filtersOut.push_back(*it); + } +} + +void FilterTree::purgeCache() +{ + for(tree::iterator it=filters.begin();it!=filters.end();++it) + (*it)->clearCache(); +} + +bool FilterTree::hasStateOverrides() const +{ + for(tree::iterator it=filters.begin(); it!=filters.end(); ++it) + { + vector overrides; + (*it)->getStateOverrides(overrides); + + if(overrides.size()) + return true; + } + + return false; +} + + +void FilterTree::addFilter(Filter *f,const Filter *parentFilter) +{ + if(parentFilter) + { + tree::iterator it= std::find(filters.begin(),filters.end(),parentFilter); + + ASSERT(it != filters.end()); + + //Add the child to the tree + filters.append_child(it,f); + } + else + { + if(filters.empty()) + filters.insert(filters.begin(),f); + else + filters.insert_after(filters.begin(),f); + } + + //Topology has changed, notify filters + initFilterTree(); +} + +void FilterTree::addFilterTree(FilterTree &f, const Filter *parent) +{ + //The insert_subtree and insert_subtree_after algorithms + // apparently work across multiple trees, I think, after examining tree::merge + if(parent) + { + tree::pre_order_iterator it; + it=std::find(filters.begin(),filters.end(),parent); + ASSERT(it!=filters.end()); + + it=filters.append_child(it,0); + filters.insert_subtree(it,f.filters.begin()); + filters.erase(it); + } + else + { + if(filters.empty()) + filters.insert_subtree(filters.begin(),f.filters.begin()); + else + filters.insert_subtree_after(filters.begin(),f.filters.begin()); + } + + f.filters.clear(); +} + +bool FilterTree::copyFilter(Filter *toCopy,const Filter *newParent) +{ + //Copy a filter child to a filter child + if(newParent) + { + + ASSERT(toCopy && newParent && + !(toCopy==newParent)); + + //Look for both newparent and sibling iterators + bool found[2] = {false,false}; + tree::iterator moveFilterIt,parenterIt; + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if(!found[0]) + { + if(*it == toCopy) + { + moveFilterIt=it; + found[0]=true; + } + } + if(!found[1]) + { + if(*it == newParent) + { + parenterIt=it; + found[1]=true; + } + } + + if(found[0] && found[1] ) + break; + } + + ASSERT(found[0] && found[1] ); + + //ensure that this is actually a parent-child relationship + for(tree::pre_order_iterator it(moveFilterIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(moveFilterIt) >= filters.depth(it) && it!=moveFilterIt ) + break; + + if(it == parenterIt) + return false; + } + + //Move the "tomove" filter, and its children to be a child of the + //newly nominated parent (DoCS* "adoption" you might say.) + //*DoCs : Department of Child Services (bad taste .au joke) + if(parenterIt != moveFilterIt) + { + //Create a temporary tree and copy the contents into here + tree tmpTree; + tree::iterator node= tmpTree.insert(tmpTree.begin(),0); + tmpTree.replace(node,moveFilterIt); //Note this doesn't kill the original + + //Replace each of the filters in the temporary_tree with a clone of the original + for(tree::iterator it=tmpTree.begin();it!=tmpTree.end(); ++it) + *it= (*it)->cloneUncached(); + + //In the original tree, create a new null node + node = filters.append_child(parenterIt,0); + //Replace the node with the tmpTree's contents + filters.replace(node,tmpTree.begin()); + + } + + initFilterTree(); + return parenterIt != moveFilterIt; + } + else + { + //copy a selected base of the tree to a new base component + + //Look for both newparent and sibling iterators + bool found = false; + tree::iterator moveFilterIt; + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if(*it == toCopy) + { + moveFilterIt=it; + found=true; + break; + } + } + + if(!found) + return false; + + //Create a temporary tree and copy the contents into here + tree tmpTree; + tree::iterator node= tmpTree.insert(tmpTree.begin(),0); + tmpTree.replace(node,moveFilterIt); //Note this doesn't kill the original + + //Replace each of the filters in the temporary_tree with a clone of the original + for(tree::iterator it=tmpTree.begin();it!=tmpTree.end(); ++it) + *it= (*it)->cloneUncached(); + + //In the original tree, create a new null node + node = filters.insert_after(filters.begin(),0); + //Replace the node with the tmpTree's contents + filters.replace(node,tmpTree.begin()); + initFilterTree(); + return true; + } + + ASSERT(false); +} + + +void FilterTree::removeSubtree(Filter *removeFilt) +{ + ASSERT(removeFilt); + + //Remove element and all children + for(tree::pre_order_iterator filtIt=filters.begin(); + filtIt!=filters.end(); ++filtIt) + { + if(removeFilt == *filtIt) + { + + for(tree::pre_order_iterator it(filtIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(filtIt) >= filters.depth(it) && it!=filtIt ) + break; + + //Delete the children filters. + delete *it; + } + + //Remove the children from the tree + filters.erase_children(filtIt); + filters.erase(filtIt); + break; + } + + } + + //Topology has changed, notify filters + initFilterTree(); +} + +void FilterTree::cloneSubtree(FilterTree &f,Filter *targetFilt) const +{ + ASSERT(!f.filters.size()); //Should only be passing empty trees + + tree::iterator targetIt=std::find(filters.begin(),filters.end(),targetFilt); + //Filter should exist. + ASSERT(targetIt!=filters.end()); + + tree::iterator node= f.filters.insert(f.filters.begin(),0); + f.filters.replace(node,targetIt); //Note this doesn't kill the original + + + //Replace each of the filters in the output tree with a clone of the original + //rather than the actual subtree + for(tree::iterator it=f.filters.begin();it!=f.filters.end(); ++it) + *it= (*it)->cloneUncached(); + + +} + +void FilterTree::setCachePercent(unsigned int newCache) +{ + ASSERT(newCache <= 100); + if(!newCache) + cacheStrategy=CACHE_NEVER; + else + { + cacheStrategy=CACHE_DEPTH_FIRST; + maxCachePercent=newCache; + } +} + +bool FilterTree::hasUpdates() const +{ + for(tree::iterator it=filters.begin();it!=filters.end();++it) + { + if((*it)->monitorNeedsRefresh()) + return true; + } + + return false; +} + + +bool FilterTree::reparentFilter(Filter *f, const Filter *newParent) +{ + + ASSERT(f && !(f==newParent)); + + tree::iterator replaceNode,parentFilterIt ; + tree::iterator moveFilterIt=filters.end(); + //If we are moving to the base, then that is a special case. + if(!newParent) + { + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if(*it == f) + { + moveFilterIt=it; + break; + } + } + + } + else + { + + //Look for both newparent and sibling iterators + bool found[2] = {false,false}; + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if(!found[0]) + { + if(*it == f) + { + moveFilterIt=it; + found[0]=true; + } + } + if(!found[1]) + { + if(*it == newParent) + { + parentFilterIt=it; + found[1]=true; + } + } + + if(found[0] && found[1] ) + break; + } + + ASSERT(parentFilterIt!=moveFilterIt); + ASSERT(found[0] && found[1] ); + + //ensure that this is actually a parent-child relationship, and not the other way around! + for(tree::pre_order_iterator it(moveFilterIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(moveFilterIt) >= filters.depth(it) && it!=moveFilterIt ) + break; + + if(it == parentFilterIt) + return false; + } + + } + + ASSERT(moveFilterIt!=filters.end()); + + //clear the cache of filters + //---- + //clear children + for(tree::pre_order_iterator it(moveFilterIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(moveFilterIt) == filters.depth(it)) + continue; + (*it)->clearCache(); + } + + //Erase the cache of moveFilterIt, and then move it to a new location + (*moveFilterIt)->clearCache(); + if(!newParent) + { + //create a dummy node, ready to be replaced + replaceNode=filters.insert_after(filters.begin(),0); + } + else + { + //Set the new target location to replace + replaceNode= filters.append_child(parentFilterIt,0); + } + //---- + + //Create a dummy node after this parent + //This doesn't actually nuke the original subtree, but rather copies it, + //replacing the dummy node. + filters.replace(replaceNode,moveFilterIt); + //Nuke the original subtree + filters.erase(moveFilterIt); + //-------- + + //Topology of filter tree has changed. + //some filters may need to know about this + initFilterTree(); + + return true; +} + + +void FilterTree::clearCache(const Filter *filter) +{ + if(!filter) + { + //Invalidate everything + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + (*it)->clearCache(); + } + else + { + //Find the filter in the tree + tree::iterator filterIt; + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if(*it == filter) + { + filterIt=it; + break; + } + } + + for(tree::pre_order_iterator it(filterIt);it!= filters.end(); ++it) + { + //Do not traverse siblings + if(filters.depth(filterIt) >= filters.depth(it) && it!=filterIt ) + break; + + (*it)->clearCache(); + } + } +} + +void FilterTree::clearCacheByType(unsigned int type) +{ + //Build a list of all filters who we need to invalidate + // Note that we cannot do this directly on the filter ptr, + // as we also need to invalidate children, so re-use the clearCache function + for(tree::iterator it=filters.begin(); + it!=filters.end(); ++it) + { + if((*it)->getType() == type) + clearCache(*it); + } + +} diff -Nru 3depict-0.0.12/src/backend/filtertree.h 3depict-0.0.13/src/backend/filtertree.h --- 3depict-0.0.12/src/backend/filtertree.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filtertree.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,201 @@ +/* + * filtertree.h - Filter tree topology and data propagation handling + * 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 . +*/ + +#ifndef FILTERTREE_H +#define FILTERTREE_H + +#include "tree.hh" +#include "filter.h" + +#include +#include + +typedef std::pair > FILTER_OUTPUT_DATA; + +class FilterTree +{ + private: + + + //!Caching strategy + unsigned int cacheStrategy; + + //!Maximum size for cache (percent of available ram). + float maxCachePercent; + + //!Filters that provide and act upon datastreams. + tree filters; + + + //!Get the filter refresh seed points in tree, by examination of tree caches, block/emit of filters + //and tree topology + void getFilterRefreshStarts(vector::iterator > &propStarts) const; + + + //Retrieve the filter's pointer from its ID value + Filter* getFilterByIdNonConst(unsigned long long filterId) const; + +#ifdef DEBUG + //!Check that the output of filter refresh functions + void checkRefreshValidity(const vector< const FilterStreamData *> &curData, + const Filter *refreshFilter) const; +#endif + + + //TODO: Move me to tree.hh + //!Returns true if the testChild is a child of testParent. + // returns false if testchild == testParent, or if the testParent + // is not a parent of testChild. + bool isChild(const tree &treeInst, + const tree::iterator &testParent, + tree::iterator testChild) const; + + + static size_t countChildFilters(const tree &treeInst, + const vector::iterator> &nodes); + public: + FilterTree(); + ~FilterTree(); + + FilterTree(const FilterTree &orig); + + void swap(FilterTree &); + //Note that the = operator creates a *CLONE* of the orignal tree, + // not an exact duplicate. underlying pointers will not be the same + const FilterTree &operator=(const FilterTree &orig); + + //Return iterator to tree contents begin. + tree::pre_order_iterator depthBegin() const { return filters.begin();}; + //Return iterator to tree contents end + tree::pre_order_iterator depthEnd() const { return filters.end();} + //Return depth of a given iterator + size_t maxDepth() const; + + size_t depth(const tree::pre_order_iterator &it) const ; + + //Get a reference to the underlying tree + const tree &getTree() const { return filters;} + + //!Return the number of filters + size_t size() const {return filters.size();}; + + //!Remove all tree contents + void clear(); + + bool contains(const Filter *f) const; + + //Refresh functions + //--- + //!Run the initialisation stage of the filter processing + void initFilterTree() const; + + bool setFilterProperty(Filter *f, unsigned int key, + const std::string &value, bool &needUpdate); + + //!Refresh the entire filter tree. Whilst this is public, great care must be taken in + // deleting the filterstream data correctly. To do this, use the "safeDeleteFilterList" function. + unsigned int refreshFilterTree( + std::list &outData, + std::vector *> &devices,std::vector > &consoleMessages, + ProgressData &curProg, bool (*callback)(bool)) const; + + //!Safely delete data generated by refreshFilterTree(...). + //a mask can be used to *prevent* STREAM_TYPE_blah from being deleted. Deleted items are removed from the list. + void safeDeleteFilterList(std::list &outData, + size_t typeMask=STREAMTYPE_MASK_ALL, bool maskPrevents=false) const; + + void getAccumulatedPropagationMaps(map &emitTypes, map &blockTypes) const; + //--- + + + //!function for the loading of a filter tree from its XML representation + unsigned int loadXML(const xmlNodePtr &treeParent, + std::ostream &errStream, const std::string &stateDir); + + + //Write out the filters into their XML representation + bool saveXML(std::ofstream &f, std::map &fileMapping, + bool writePackage, bool useRelativePaths, unsigned int minTabDepth=0) const; + + + //Topological alteration & examination functions + //---------- + //!Remove an element and all sub elements from the tree, + void removeSubtree(Filter *f); + + //!Add a new filter to the tree. Note that pointer will be released + // by filter destructor + void addFilter(Filter *f, const Filter *parent); + + //!Add a new tree as a subtree to a node + void addFilterTree(FilterTree &f, const Filter *parent); + + //!Move a branch of the tree to a new position + bool reparentFilter(Filter *f, const Filter *newParent); + //!Duplicate a branch of the tree to a new position. Do not copy cache, + bool copyFilter(Filter *id, const Filter *newParent); + + //Obtain a copy of the filters in the specified subtree + void cloneSubtree(FilterTree &f,Filter *targetFilt) const; + //--------- + + + //Filter alteration functions + //--------- + //!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 type of filter + // and all their children. + void clearCacheByType(unsigned int type); + + //!Return all of a given type of filter from the filter tree + void getFiltersByType(std::vector &filters, unsigned int type) const; + + //!Make the filter system safe (non-hazardous) + void removeHazardousContents(); + + + //!Used to remove potentially hazardous filters + //(filters that can do nasty things to computers, like executing commands) + //which may have come from unsafe sources + void stripHazardousContents(); + + //!return true if the tree contains hazardous filters + bool hasHazardousContents() const ; + + //!Force a wipe of all caches in the filter tree + void purgeCache(); + + + //!Returns true if any of the filters (incl. stash) + //return a state override (i.e. refer to external entities, such as files) + bool hasStateOverrides() const ; + + bool hasUpdates() const ; + + //--------- + + void setCachePercent(unsigned int newCache); +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/filtertreeAnalyse.cpp 3depict-0.0.13/src/backend/filtertreeAnalyse.cpp --- 3depict-0.0.12/src/backend/filtertreeAnalyse.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filtertreeAnalyse.cpp 2013-04-10 19:35:49.000000000 +0000 @@ -0,0 +1,469 @@ +/* + * filtertreeAnalyse.cpp - Performs correctness checking of filter trees + * 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 . +*/ + +#include "filtertreeAnalyse.h" + + + +//Needed to obtain filter data keys +//---- +#include "filters/dataLoad.h" +#include "filters/ionDownsample.h" +#include "filters/compositionProfile.h" +//---- + +void FilterTreeAnalyse::getAnalysisResults(std::vector &errs) const +{ + errs.resize(analysisResults.size()); + std::copy(analysisResults.begin(),analysisResults.end(),errs.begin()); +} + +void FilterTreeAnalyse::analyse(const FilterTree &f) +{ + f.getAccumulatedPropagationMaps(emitTypes,blockTypes); + + //Check for a data pair where the output is entirely blocked, + // rendering computation of filter useless + blockingPairError(f); + + //Check for spatial sampling altering some results in later analyses + spatialSampling(f); + + //Check for compositional biasing altering some later analysis + compositionAltered(f); + + emitTypes.clear(); + blockTypes.clear(); + +} + + + + +void FilterTreeAnalyse::blockingPairError(const FilterTree &f) +{ + //Examine the emit and block/use masks for each filter's parent (emit) + // child relationship(block/use), such that in the case of a child filter that is expecting + // a particular input, but the parent cannot generate it + + const tree &treeFilt=f.getTree(); + for(tree::pre_order_iterator it = treeFilt.begin(); it!=treeFilt.end(); ++it) + { + + tree_node_ *myNode=it.node->first_child; + + size_t parentEmit; + parentEmit = emitTypes[(*it) ]| (*it)->getRefreshEmitMask(); + + while(myNode) + { + Filter *childFilter; + childFilter = myNode->data; + + size_t curBlock,curUse; + curBlock=blockTypes[childFilter] | childFilter->getRefreshBlockMask(); + curUse=childFilter->getRefreshUseMask(); + + //If the child filter cannot use and blocks all parent emit values + // emission of the all possible output filters, + // then this is a bad filter pairing + bool passedThrough; + passedThrough=parentEmit & ~curBlock; + + if(!parentEmit && curUse) + { + FILTERTREE_ERR treeErr; + treeErr.reportedFilters.push_back(childFilter); + treeErr.reportedFilters.push_back(*it); + treeErr.verboseReportMessage = TRANS("Parent filter has no output, but filter requires input -- there is no point in placing a child filter here."); + treeErr.shortReportMessage = TRANS("Leaf-only filter with child"); + treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing. + + analysisResults.push_back(treeErr); + } + else if(!(parentEmit & curUse) && !passedThrough ) + { + FILTERTREE_ERR treeErr; + treeErr.reportedFilters.push_back(childFilter); + treeErr.reportedFilters.push_back(*it); + treeErr.verboseReportMessage = TRANS("Parent filters' output will be blocked by child, without use. Parent results will be dropped."); + treeErr.shortReportMessage = TRANS("Bad parent->child pair"); + treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing. + + analysisResults.push_back(treeErr); + } + //If the parent does not emit a usable 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()) + { + FILTERTREE_ERR treeErr; + treeErr.reportedFilters.push_back(childFilter); + treeErr.reportedFilters.push_back(*it); + treeErr.verboseReportMessage = TRANS("First filter does not output anything useable by child filter. Child filter not useful."); + treeErr.shortReportMessage = TRANS("Bad parent->child pair"); + treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing. + + analysisResults.push_back(treeErr); + + } + + + //Move to next sibling + myNode = myNode->next_sibling; + } + + + } + +} + +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) +{ + //True if spatial sampling is (probably) happening for children of + //filter. + vector affectedFilters; + affectedFilters.push_back(FILTER_TYPE_CLUSTER_ANALYSIS); //If have range parent + affectedFilters.push_back(FILTER_TYPE_COMPOSITION); //If using density + affectedFilters.push_back(FILTER_TYPE_SPATIAL_ANALYSIS); + affectedFilters.push_back(FILTER_TYPE_IONINFO); + + const tree &treeFilt=f.getTree(); + for(tree::pre_order_iterator it(treeFilt.begin()); it!=treeFilt.end(); ++it) + { + //Check to see if we have a filter that can cause sampling + if(filterIsSampling(*it)) + { + tree_node_ *childNode=it.node->first_child; + + if(childNode) + { + + //TODO: Not the most efficient method of doing this... + //shouldn't need to continually compute depth to iterate over children + size_t minDepth=treeFilt.depth(it); + for(tree::pre_order_iterator itJ(childNode); treeFilt.depth(itJ) > minDepth;++itJ) + { + //ignore filters that are not affected by spatial sampling + size_t filterType; + filterType=(*itJ)->getType(); + if(std::find(affectedFilters.begin(),affectedFilters.end(),filterType)== affectedFilters.end()) + continue; + + childNode=itJ.node; + + //Check to see if we have a "range" type ancestor + // - we will need to know this in a second + bool haveRngParent=false; + { + tree_node_ *ancestor; + ancestor = childNode->parent; + while(true) + { + if(ancestor->data->getType() == FILTER_TYPE_RANGEFILE) + { + haveRngParent=true; + break; + } + + if(!ancestor->parent) + break; + + ancestor=ancestor->parent; + + } + } + + if(affectedBySampling(*itJ,haveRngParent)) + { + FILTERTREE_ERR treeErr; + treeErr.reportedFilters.push_back(*it); + treeErr.reportedFilters.push_back(*itJ); + treeErr.shortReportMessage=TRANS("Spatial results possibly altered"); + treeErr.verboseReportMessage=TRANS("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."); + treeErr.severity=ANALYSE_SEVERITY_WARNING; + + analysisResults.push_back(treeErr); + } + } + } + + //No need to walk child nodes + it.skip_children(); + } + + + + } +} + + +bool filterAltersComposition(const Filter *f) +{ + bool affectsComposition=false; + + + FilterPropGroup props; + f->getProperties(props); + + + + switch(f->getType()) + { + case FILTER_TYPE_IONDOWNSAMPLE: + { + FilterProperty p; + if(!props.hasProp(KEY_IONDOWNSAMPLE_PERSPECIES)) + return false; + + p=props.getPropValue(KEY_IONDOWNSAMPLE_PERSPECIES); + + + if(p.data== "1") + { + vector propVec; + const int GROUP_SAMPLING=1; + props.getGroup(GROUP_SAMPLING,propVec); + + //If using per-species mode, then + // we may affect the output ion composition + // if we have differing values + for(size_t ui=1;uigetProperties(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); + + //Affected if using normalise mode, and we do have a range parent + affected= (p.data== "1" && haveRngParent); + break; + } + case FILTER_TYPE_SPATIAL_ANALYSIS: + { + affected=true; + break; + } + } + + return affected; +} + +//FIXME: This is largely a cut and paste of ::spatialSampling - could be unified through +// function pointers and friends +void FilterTreeAnalyse::compositionAltered(const FilterTree &f) +{ + //True if composition biasing is (probably) happening for children of + //filter. + vector affectedFilters; + affectedFilters.push_back(FILTER_TYPE_CLUSTER_ANALYSIS); //If have range parent + affectedFilters.push_back(FILTER_TYPE_COMPOSITION); //By definition + affectedFilters.push_back(FILTER_TYPE_IONINFO); //If using composition + + const tree &treeFilt=f.getTree(); + for(tree::pre_order_iterator it(treeFilt.begin()); it!=treeFilt.end(); ++it) + { + //Check to see if we have a filter that can cause sampling + if(filterAltersComposition(*it)) + { + tree_node_ *childNode=it.node->first_child; + + if(childNode) + { + + //TODO: Not the most efficient method of doing this... + //shouldn't need to continually compute depth to iterate over children + size_t minDepth=treeFilt.depth(it); + for(tree::pre_order_iterator itJ(childNode); treeFilt.depth(itJ) > minDepth;++itJ) + { + //ignore filters that are not affected by spatial sampling + size_t filterType; + filterType=(*itJ)->getType(); + if(std::find(affectedFilters.begin(),affectedFilters.end(),filterType)== affectedFilters.end()) + continue; + + childNode=itJ.node; + + //Check to see if we have a "range" type ancestor + // - we will need to know this in a second + bool haveRngParent=false; + { + tree_node_ *ancestor; + ancestor = childNode->parent; + while(true) + { + if(ancestor->data->getType() == FILTER_TYPE_RANGEFILE) + { + haveRngParent=true; + break; + } + + if(!ancestor->parent) + break; + + ancestor=ancestor->parent; + + } + } + + if(filterAffectedByComposition(*itJ,haveRngParent)) + { + FILTERTREE_ERR treeErr; + treeErr.reportedFilters.push_back(*it); + treeErr.reportedFilters.push_back(*itJ); + treeErr.shortReportMessage=TRANS("Composition results possibly altered"); + treeErr.verboseReportMessage=TRANS("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."); + treeErr.severity=ANALYSE_SEVERITY_WARNING; + + analysisResults.push_back(treeErr); + } + } + } + + //No need to walk child nodes + it.skip_children(); + } + + + + } +} diff -Nru 3depict-0.0.12/src/backend/filtertreeAnalyse.h 3depict-0.0.13/src/backend/filtertreeAnalyse.h --- 3depict-0.0.12/src/backend/filtertreeAnalyse.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/filtertreeAnalyse.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * filtertree.h - Filter tree topology and data propagation handling + * 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 . +*/ + +#ifndef FILTERTREEANALYSE_H +#define FILTERTREEANALYSE_H + +#include "filtertree.h" + + +enum +{ + ANALYSE_SEVERITY_WARNING, // Probable warning + ANALYSE_SEVERITY_ERROR, // definite error + ANALYSE_SEVERITY_END_ENUM // Not a severity, just end of enum +}; + +struct FILTERTREE_ERR +{ + //The filters that are associated with the error messages + std::vector reportedFilters; + //Error messages associated with the reported filters + std::string verboseReportMessage,shortReportMessage; + + unsigned int severity; +}; + + +class FilterTreeAnalyse +{ + private: + std::vector analysisResults; + + + //Accumulated emit and block masks for the filter tree + // these are only valid during the call to ::analyse + std::map emitTypes; //Whatever types can be emitted from this filer, considering this filter's ancestors in tree, not incl. self + std::map blockTypes; //Whatever types can be blocked by this filter, considering this filter's children in tree, not incl. self + + //!Detect misconfiguration of the filter tree + // where parent emits something that the child + // cannot use + void blockingPairError( const FilterTree &f); + + //!Detect case where algorithms that depend + // upon there being no spatial sampling + // are being used with sampling. + void spatialSampling(const FilterTree &f); + + void compositionAltered(const FilterTree &f); + public: + void analyse(const FilterTree &f); + + void getAnalysisResults(std::vector &errs) const; + + void clear() {analysisResults.clear();}; +}; + + +#endif + diff -Nru 3depict-0.0.12/src/backend/plot.cpp 3depict-0.0.13/src/backend/plot.cpp --- 3depict-0.0.12/src/backend/plot.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/plot.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,1397 @@ +/* + * plot.cpp - mathgl plot wrapper 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 . +*/ +#include "plot.h" + +#include "common/stringFuncs.h" + +#include "common/translation.h" + +#ifdef USE_MGL2 + #include +#endif + +//!Plot error bar estimation strings +const char *errModeStrings[] = { + NTRANS("None"), + NTRANS("Moving avg.") + }; + +const char *plotModeStrings[]= { + NTRANS("Lines"), + NTRANS("Bars"), + NTRANS("Steps"), + NTRANS("Stem"), + NTRANS("Points") + }; + +using std::string; +using std::pair; +using std::vector; + + +//Axis min/max bounding box is disallowed to be exactly zero on any given axis +// perform a little "push off" by this fudge factor +const float AXIS_MIN_TOLERANCE=10*sqrtf(std::numeric_limits::epsilon()); + +int MGLColourFixer::maxCols=-1; + +void MGLColourFixer::reset() +{ + rs.clear(); + gs.clear(); + bs.clear(); +} + +char MGLColourFixer::haveExactColour(float r, float g, float b) const +{ + ASSERT(rs.size() == gs.size()) + ASSERT(gs.size() == bs.size()) + + ASSERT(rs.size() <=getMaxColours()); + + for(unsigned int ui=0; ui::epsilon() + && fabs(g-gs[ui]) ::epsilon() + && fabs(b-bs[ui]) ::epsilon()) + return mglColorIds[ui+1].id; //Add one to offset to avoid the reserved "k" + } + + return 0; +} + +unsigned int MGLColourFixer::getMaxColours() +{ + //Used cached value if available + if(maxCols!=-1) + return maxCols; + + //The array is statically defined in + //mgl/mgl_main.cpp, and must end with an id of zero. + // + //this is not documented at all. + maxCols=0; + while(mglColorIds[maxCols].id) + maxCols++; + + return maxCols; +} + +char MGLColourFixer::getNextBestColour(float r, float g, float b) +{ + ASSERT(rs.size() == gs.size()); + ASSERT(gs.size() == bs.size()); + + + //As a special case, mgl has its own black + if(r == 0.0f && g == 0.0f && b == 0.0f) + return mglColorIds[0].id; + + + unsigned int best=0; + if(rs.size() == getMaxColours()) + { + ASSERT(getMaxColours()); + //Looks like we ran out of palette colours. + //lets just give up and try to match this against our existing colours + + //TODO: let this modify the existing palette + // to find a better match. + float distanceSqr=std::numeric_limits::max(); + for(unsigned int ui=0; ui::epsilon())) + return true; + + const int FLOAT_ACC_MASK=0xffff0000; + union FLT_INT + { + float f; + int i; + }; + FLT_INT u; + u.f=a; + //For big numbers, we have to either bit-bash, or something + u.i&=FLOAT_ACC_MASK; + a=u.f; + + u.f=b; + u.i&=FLOAT_ACC_MASK; + b=u.f; + + if(fabs(a-b) < sqrt(std::numeric_limits::epsilon())) + return true; + + return false; +} + + +//Nasty string conversion functions. +std::wstring strToWStr(const std::string& s) +{ + std::wstring temp(s.length(),L' '); + std::copy(s.begin(), s.end(), temp.begin()); + return temp; +} + +std::string wstrToStr(const std::wstring& s) +{ + std::string temp(s.length(), ' '); + std::copy(s.begin(), s.end(), temp.begin()); + return temp; +} + + +//TODO: Refactor these functions to use a common string map +//----------- +string plotString(unsigned int traceType) +{ + ASSERT(traceType< PLOT_TRACE_ENDOFENUM); + return TRANS(plotModeStrings[traceType]); +} + +unsigned int plotID(const std::string &plotString) +{ + for(unsigned int ui=0;ui &x, const std::vector &y, + std::vector &errBars, const PLOT_ERROR &errMode) +{ + switch(errMode.mode) + { + case PLOT_ERROR_NONE: + return; + case PLOT_ERROR_MOVING_AVERAGE: + { + ASSERT(errMode.movingAverageNum); + errBars.resize(y.size()); + for(int ui=0;ui<(int)y.size();ui++) + { + float mean; + mean=0.0f; + + //Compute the local mean + for(int uj=0;uj<(int)errMode.movingAverageNum;uj++) + { + int idx; + idx= std::max(ui+uj-(int)errMode.movingAverageNum/2,0); + idx=std::min(idx,(int)(y.size()-1)); + ASSERT(idxvisible && plottingData[ui]->parentObject) + { + lastVisiblePlots.push_back(std::make_pair(plottingData[ui]->parentObject, + plottingData[ui]->parentPlotIndex)); + } + } + } + else + applyUserBounds=false; + + + //Free the plotting data pointers + for(size_t ui=0;uixLabel = strToWStr(x); + plottingData[plotPos]->yLabel = strToWStr(y); + + plottingData[plotPos]->title = strToWStr(t); + plotChanged=true; +} + +void PlotWrapper::setParentData(unsigned int plotID, const void *parentObj, unsigned int idx) +{ + unsigned int plotPos=plotIDHandler.getPos(plotID); + plottingData[plotPos]->parentObject= parentObj; + plottingData[plotPos]->parentPlotIndex=idx; + + plotChanged=true; +} + +void PlotWrapper::setTraceStyle(unsigned int plotUniqueID,unsigned int mode) +{ + + ASSERT(modetraceType=mode; + plotChanged=true; +} + +void PlotWrapper::setColours(unsigned int plotUniqueID, float rN,float gN,float bN) +{ + unsigned int plotPos=plotIDHandler.getPos(plotUniqueID); + plottingData[plotPos]->r=rN; + plottingData[plotPos]->g=gN; + plottingData[plotPos]->b=bN; + plotChanged=true; +} + +void PlotWrapper::setBounds(float xMin, float xMax, + float yMin,float yMax) +{ + ASSERT(!interactionLocked); + + ASSERT(xMin::epsilon() && + fabs(yUserMin -yMin)<=std::numeric_limits::epsilon()) + { + applyUserBounds=false; + } + + plotChanged=true; +} + +void PlotWrapper::getBounds(float &xMin, float &xMax, + float &yMin,float &yMax) const +{ + if(applyUserBounds) + { + xMin=xUserMin; + yMin=yUserMin; + xMax=xUserMax; + yMax=yUserMax; + } + else + scanBounds(xMin,xMax,yMin,yMax); + + ASSERT(xMin ::max(); + xMax=-std::numeric_limits::max(); + yMin=std::numeric_limits::max(); + yMax=-std::numeric_limits::max(); + + for(unsigned int uj=0;ujvisible) + continue; + + //Expand our bounding box to encompass that of this visible plot + float tmpXMin,tmpXMax,tmpYMin,tmpYMax; + plottingData[uj]->getBounds(tmpXMin,tmpXMax,tmpYMin,tmpYMax); + + xMin=std::min(xMin,tmpXMin); + xMax=std::max(xMax,tmpXMax); + yMin=std::min(yMin,tmpYMin); + yMax=std::max(yMax,tmpYMax); + + } + + ASSERT(xMin < xMax && yMin <=yMax); +} + +void PlotWrapper::bestEffortRestoreVisibility() +{ + //Try to match up the last visible plots to the + //new plots. Use index and owner as guiding data + + for(unsigned int uj=0;ujvisible=false; + + for(unsigned int ui=0; uiparentObject == lastVisiblePlots[ui].first + && plottingData[uj]->parentPlotIndex == lastVisiblePlots[ui].second) + { + plottingData[uj]->visible=true; + break; + } + + } + } + + lastVisiblePlots.clear(); + plotChanged=true; +} + +void PlotWrapper::getRawData(vector > > &data, + std::vector > &labels) const +{ + if(plottingData.empty()) + return; + + //Determine if we have multiple types of plot. + //if so, we cannot really return the raw data for this + //in a meaningful fashion + switch(getVisibleType()) + { + case PLOT_TYPE_ONED: + { + //Try to retrieve the raw data from the visible plots + for(unsigned int ui=0;uivisible) + { + vector > thisDat,dummy; + vector thisLabel; + plottingData[ui]->getRawData(thisDat,thisLabel); + + //Data title size should hopefully be the same + //as the label size + ASSERT(thisLabel.size() == thisDat.size()); + + if(thisDat.size()) + { + data.push_back(dummy); + data.back().swap(thisDat); + + labels.push_back(thisLabel); + } + } + } + break; + } + case PLOT_TYPE_ENUM_END: + return; + default: + ASSERT(false); + } +} + +unsigned int PlotWrapper::getVisibleType() const +{ + unsigned int visibleType=PLOT_TYPE_ENUM_END; + for(unsigned int ui=0;uivisible && + plottingData[ui]->plotType!= visibleType) + { + if(visibleType == PLOT_TYPE_ENUM_END) + { + visibleType=plottingData[ui]->plotType; + continue; + } + else + { + visibleType=PLOT_TYPE_MIXED; + break; + } + } + } + + return visibleType; +} + +void PlotWrapper::drawPlot(mglGraph *gr) const +{ + unsigned int visType = getVisibleType(); + if(visType == PLOT_TYPE_ENUM_END || + visType == PLOT_TYPE_MIXED) + { + //We don't handle the drawing case well here, so assert this. + // calling code should check this case and ensure that it draws something + // meaningful + ASSERT(false); + return; + } + + //Un-fudger for mathgl plots + MGLColourFixer colourFixer; + + bool haveMultiTitles=false; + float minX,maxX,minY,maxY; + minX=std::numeric_limits::max(); + maxX=-std::numeric_limits::max(); + minY=std::numeric_limits::max(); + maxY=-std::numeric_limits::max(); + + //Compute the bounding box in data coordinates + std::wstring xLabel,yLabel,plotTitle; + + for(unsigned int ui=0;uivisible) + { + + 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); + + + if(!xLabel.size()) + xLabel=plottingData[ui]->xLabel; + else + { + + if(xLabel!=plottingData[ui]->xLabel) + xLabel=stlStrToStlWStr(TRANS("Multiple data types")); + } + if(!yLabel.size()) + yLabel=plottingData[ui]->yLabel; + else + { + + if(yLabel!=plottingData[ui]->yLabel) + yLabel=stlStrToStlWStr(TRANS("Multiple data types")); + } + if(!haveMultiTitles && !plotTitle.size()) + plotTitle=plottingData[ui]->title; + else + { + + if(plotTitle!=plottingData[ui]->title) + { + plotTitle=L"";//L prefix means wide char + haveMultiTitles=true; + } + } + + + } + } + + + + string sX,sY; + sX.assign(xLabel.begin(),xLabel.end()); //unicode conversion + sY.assign(yLabel.begin(),yLabel.end()); //unicode conversion + + string sT; + sT.assign(plotTitle.begin(), plotTitle.end()); //unicode conversion + gr->Title(sT.c_str()); + + + switch(visType) + { + case PLOT_TYPE_ONED: + { + //OneD connected value line plot f(x) + bool useLogPlot=false; + bool notLog=false; + + + for(unsigned int ui=0;uivisible) + { + if(((Plot1D*)plottingData[ui])->wantLogPlot()) + useLogPlot=true; + else + notLog=true; + } + } + + //work out the bounding box for the plot, + //and where the axis should cross + mglPoint axisCross; + mglPoint min,max; + if(applyUserBounds) + { + ASSERT(yUserMax >=yUserMin); + ASSERT(xUserMax >=xUserMin); + + max.x =xUserMax; + max.y=yUserMax; + + min.x =xUserMin; + min.y =yUserMin; + + axisCross.x=min.x; + axisCross.y=min.y; + + } + else + { + //Retrieve the bounds of the data that is in the plot + + min.x=minX; + min.y=minY; + max.x=maxX; + + if(useLogPlot && maxY > 0.0f) + max.y =log10(maxY); + else + max.y=maxY; + + axisCross.x = minX; + axisCross.y=min.y; + } + + //"Push" bounds around to prevent min == max + // This is a hack to prevent mathgl from inf. looping + //--- + if(mglFloatTooClose(min.x , max.x)) + { + min.x-=5; + max.x+=5; + } + + if(mglFloatTooClose(min.y , max.y)) + max.y+=1; + //------ + + //tell mathgl about the bounding box +#ifdef USE_MGL2 + gr->SetRanges(min,max); + gr->SetOrigin(axisCross); +#else + gr->Axis(min,max,axisCross); +#endif + + WARN((fabs(min.x-max.x) > sqrt(std::numeric_limits::epsilon())), + "WARNING: Mgl limits (X) too Close! Due to limitiations in MGL, This may inf. loop!"); + WARN((fabs(min.y-max.y) > sqrt(std::numeric_limits::epsilon())), + "WARNING: Mgl limits (Y) too Close! Due to limitiations in MGL, This may inf. loop!"); + +#ifdef USE_MGL2 + mglCanvas *canvas = dynamic_cast(gr->Self()); + canvas->AdjustTicks("x"); + canvas->SetTickTempl('x',"%g"); //Set the tick type + canvas->Axis("xy"); //Build an X-Y crossing axis +#else + gr->AdjustTicks("x"); + gr->SetXTT("%g"); //Set the tick type + gr->Axis("xy"); //Build an X-Y crossing axis +#endif + //--- + + //Loop through the plots, drawing them as needed + for(unsigned int ui=0;uivisible) + continue; + + + curPlot->drawRegions(gr,colourFixer,min,max); + curPlot->drawPlot(gr,colourFixer); + + if(drawLegend) + { + //Fake an mgl colour code + char colourCode[2]; + colourCode[0]=colourFixer.getNextBestColour( + curPlot->r,curPlot->g,curPlot->b); + colourCode[1]='\0'; + gr->AddLegend(curPlot->title.c_str(),colourCode); + } + } + + //Prevent mathgl from dropping lines that straddle the plot bound. + gr->SetCut(false); + + if(useLogPlot && !notLog) + sY = string("\\log_{10}(") + sY + ")"; + else if (useLogPlot && notLog) + { + sY = string(TRANS("Mixed log/non-log:")) + sY ; + } + + break; + } + default: + ASSERT(false); + } + + + gr->Label('x',sX.c_str()); + gr->Label('y',sY.c_str(),0); + + if(haveMultiTitles) + { +#ifdef USE_MGL2 + const float LEGEND_SIZE=5.0f; + mreal oldFontSize=gr->Self()->GetFontSize(); + gr->SetFontSize(LEGEND_SIZE); + if(drawLegend) + gr->Legend(); + gr->SetFontSize(oldFontSize); +#else + gr->SetLegendBox(false); + //I have NO idea what this size value is about, + //I just kept changing the number until it looked nice. + //the library default is -0.85 (why negative??) + const float LEGEND_SIZE=-1.1f; + + //Legend at top right (0x3), in default font "rL" at specified size + if(drawLegend) + gr->Legend(0x3,"rL",LEGEND_SIZE); +#endif + } + +} + +void PlotWrapper::hideAll() +{ + for(unsigned int ui=0;uivisible=false; + plotChanged=true; +} + +void PlotWrapper::setVisible(unsigned int uniqueID, bool setVis) +{ + unsigned int plotPos = plotIDHandler.getPos(uniqueID); + + plottingData[plotPos]->visible=setVis; + plotChanged=true; +} + +bool PlotWrapper::getRegionIdAtPosition(float x, float y, unsigned int &pId, unsigned int &rId) const +{ + for(size_t ui=0;uivisible) + continue; + + if(plottingData[ui]->getRegionIdAtPosition(x,y,rId)) + { + pId=ui; + return true; + } + } + + return false; +} + +unsigned int PlotWrapper::getNumVisible() const +{ + unsigned int num=0; + for(unsigned int ui=0;uivisible) + num++; + } + + + return num; +} + +bool PlotWrapper::isPlotVisible(unsigned int plotID) const +{ + return plottingData[plotIDHandler.getPos(plotID)]->visible; +} + +void PlotWrapper::getRegion(unsigned int plotId, unsigned int regionId, PlotRegion ®ion) const +{ + plottingData[plotIDHandler.getPos(plotId)]->getRegion(regionId,region); +} + +unsigned int PlotWrapper::plotType(unsigned int plotId) const +{ + return plottingData[plotIDHandler.getPos(plotId)]->plotType; +} + + +void PlotWrapper::moveRegionLimit(unsigned int plotId, unsigned int regionId, + unsigned int movementType, float &constrainX, float &constrainY) const +{ + plottingData[plotIDHandler.getPos(plotId)]->moveRegionLimit( + regionId,movementType,constrainX,constrainY); +} + + +void PlotWrapper::moveRegion(unsigned int plotID, unsigned int regionId, unsigned int movementType, + float newX, float newY) const +{ + plottingData[plotIDHandler.getPos(plotID)]->moveRegion(regionId,movementType,newX,newY); +} +//----------- + + +Plot1D::Plot1D() +{ + //Set the default plot properties + visible=(true); + traceType=PLOT_TRACE_LINES; + plotType=PLOT_TYPE_ONED; + xLabel=(strToWStr("")); + yLabel=(strToWStr("")); + title=(strToWStr("")); + r=(0);g=(0);b=(1); +} + +void Plot1D::setData(const vector &vX, const vector &vY, + const vector &vErr) +{ + + ASSERT(vX.size() == vY.size()); + ASSERT(vErr.size() == vY.size() || !vErr.size()); + + + //Fill up vectors with data + xValues.resize(vX.size()); + std::copy(vX.begin(),vX.end(),xValues.begin()); + yValues.resize(vY.size()); + std::copy(vY.begin(),vY.end(),yValues.begin()); + + errBars.resize(vErr.size()); + std::copy(vErr.begin(),vErr.end(),errBars.begin()); + + //Compute minima and maxima of plot data, and keep a copy of it + float maxThis=-std::numeric_limits::max(); + float minThis=std::numeric_limits::max(); + for(unsigned int ui=0;ui::max(); + minThis=std::numeric_limits::max(); + for(unsigned int ui=0;ui > &v) +{ + vector dummyVar; + + setData(v,dummyVar); + +} +void Plot1D::setData(const vector > &v,const vector &vErr) +{ + //Fill up vectors with data + xValues.resize(v.size()); + yValues.resize(v.size()); + for(unsigned int ui=0;ui::max(); + float minThis=std::numeric_limits::max(); + for(unsigned int ui=0;ui::max(); + minThis=std::numeric_limits::max(); + if(vErr.size()) + { + ASSERT(vErr.size() == v.size()); + for(unsigned int ui=0;ui 0.0) + bufferY[uj] = log10(yValues[uj]); + else + bufferY[uj] = 0; + + } + } + else + { + for(unsigned int uj=0;ujSetCut(true); + + gr->Plot(xDat,yDat,colourCode); + if(showErrs) + gr->Error(xDat,yDat,eDat,colourCode); + gr->SetCut(false); + break; + case PLOT_TRACE_BARS: + gr->Bars(xDat,yDat,colourCode); + break; + case PLOT_TRACE_STEPS: + //Same problem as for line plot. + gr->SetCut(true); + gr->Step(xDat,yDat,colourCode); + gr->SetCut(false); + break; + case PLOT_TRACE_STEM: + gr->Stem(xDat,yDat,colourCode); + break; + + case PLOT_TRACE_POINTS: + { + std::string s; + s = colourCode; + //Mathgl uses strings to manipulate line styles + s+=" "; + //space means "no line" + s+="x"; //x shaped point markers + + gr->SetCut(true); + + gr->Plot(xDat,yDat,s.c_str()); + if(showErrs) + gr->Error(xDat,yDat,eDat,s.c_str()); + gr->SetCut(false); + break; + } + default: + ASSERT(false); + break; + } + + delete[] bufferX; + delete[] bufferY; + if(showErrs) + delete[] bufferErr; + + + +} + + +void Plot1D::addRegion(unsigned int parentPlot,unsigned int regionID,float start, float end, + float rNew, float gNew, float bNew, Filter *parentFilter) +{ + ASSERT(start =0.0 && rNew <= 1.0); + ASSERT( gNew>=0.0 && gNew <= 1.0); + ASSERT( bNew>=0.0 && bNew <= 1.0); + + PlotRegion region; + //1D plots only have one bounding direction + region.bounds.push_back(std::make_pair(start,end)); + region.boundAxis.push_back(0); // the bounding direction is along the X axis + region.parentFilter = parentFilter; + + //Set the ID and create a unique ID (one that is invariant if regions are added or removed) + //for the region + region.id = regionID; + region.uniqueID = regionIDHandler.genId(regions.size()); + + region.r=rNew; + region.g=gNew; + region.b=bNew; + + regions.push_back(region); +} + +//---- + +void Plot1D::getRawData(std::vector > &rawData, + std::vector &labels) const +{ + + vector tmp,dummy; + + tmp.resize(xValues.size()); + std::copy(xValues.begin(),xValues.end(),tmp.begin()); + rawData.push_back(dummy); + rawData.back().swap(tmp); + + tmp.resize(yValues.size()); + std::copy(yValues.begin(),yValues.end(),tmp.begin()); + rawData.push_back(dummy); + rawData.back().swap(tmp); + + labels.push_back(xLabel); + if(titleAsRawDataLabel) + labels.push_back(title); + else + labels.push_back(yLabel); + + + if(errBars.size()) + { + tmp.resize(errBars.size()); + std::copy(errBars.begin(),errBars.end(),tmp.begin()); + + rawData.push_back(dummy); + rawData.back().swap(tmp); + labels.push_back(stlStrToStlWStr(TRANS("error"))); + } +} + + +void Plot1D::moveRegionLimit(unsigned int regionID, + unsigned int method, float &newPosX, float &newPosY) const +{ + + unsigned int region=regionIDHandler.getPos(regionID); + + ASSERT(region mean) + + { + //Disallow hitting other bounds + for(unsigned int ui=0; ui mean && ui != region) ) + newPosX=std::min(newPosX,regions[ui].bounds[0].first); + } + newPosX=std::max(newPosX,xMin); + } + else + { + //Disallow hitting other bounds + for(unsigned int ui=0; ui mean && ui != region)) + newPosX=std::min(newPosX,regions[ui].bounds[0].first); + } + //Dont allow past self left + newPosX=std::max(newPosX,regions[region].bounds[0].first); + //Dont extend outside plot + newPosX=std::min(newPosX,xMax); + break; + default: + ASSERT(false); + } + +} + + +void Plot1D::moveRegion(unsigned int regionID, unsigned int method, float newPosX,float newPosY) const +{ + //Well, we should have called this externally to determine location + //let us confirm that this is the case + moveRegionLimit(regionID,method,newPosX,newPosY); + + + unsigned int region=regionIDHandler.getPos(regionID); + ASSERT(regions[region].parentFilter); + + //Pass the filter ID value stored in the region to the filter, along with the new + //value to take for that filter ID + regions[region].parentFilter->setPropFromRegion(method,regions[region].id,newPosX); + +} + + +void Plot1D::drawRegions(mglGraph *gr,MGLColourFixer &fixer, + const mglPoint &min,const mglPoint &max) const +{ + //Mathgl palette colour name + char colourCode[2]; + colourCode[1]='\0'; + + for(unsigned int uj=0;uj rMinX && rMaxY > rMinY) + { + colourCode[0] = fixer.getNextBestColour(regions[uj].r, + regions[uj].g,regions[uj].b); + colourCode[1] = '\0'; +#ifdef USE_MGL2 + gr->FaceZ(mglPoint(rMinX,rMinY,-1),rMaxX-rMinX,rMaxY-rMinY, + colourCode); +#else + gr->FaceZ(rMinX,rMinY,-1,rMaxX-rMinX,rMaxY-rMinY, + colourCode); +#endif + + } + } +} + + +void Plot1D::clear( bool preserveVisiblity) +{ + regions.clear(); + regionIDHandler.clear(); +} + +bool Plot1D::getRegionIdAtPosition(float x, float y, unsigned int &id) const +{ + for(unsigned int ui=0;ui x ) + { + id=ui; + return true; + } + } + + + return false; +} + +void Plot1D::getRegion(unsigned int id, PlotRegion &r) const +{ + r = regions[regionIDHandler.getPos(id)]; +} + + diff -Nru 3depict-0.0.12/src/backend/plot.h 3depict-0.0.13/src/backend/plot.h --- 3depict-0.0.12/src/backend/plot.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/plot.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,390 @@ +/* + * plot.h - plotting wraper for mathgl + * 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 . +*/ + +#ifndef PLOT_H +#define PLOT_H + + +#include "backend/filter.h" + + +#if defined(WIN32) || defined(WIN64) + //Help mathgl out a bit: we don't need the GSL on this platform + #define NO_GSL +#endif + +//Use config header to determine if we need to enable mgl2 support +#include "../config.h" +#ifdef USE_MGL2 +#include +#else +#include +#endif + +//mathgl shadows std::isnan +#undef isnan + + + +enum +{ + PLOT_TYPE_ONED, + PLOT_TYPE_MIXED, + PLOT_TYPE_ENUM_END //not a plot, just end of enum +}; + + + + +//!Return a human readable string for a given plot type +std::string plotString(unsigned int traceType); + +//!Return a human readable string for the plot error mode +std::string plotErrmodeString(unsigned int errMode); + +//!Return the plot type given a human readable string +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 +class MGLColourFixer +{ + private: + vector rs,gs,bs; + static int maxCols; + public: + //Restore the MGL colour strings + void reset(); + //Return the exact colour, if there is one + char haveExactColour(float r, float g, float b) const; + //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 + char getNextBestColour(float r, float g, float b); + + static unsigned int getMaxColours(); +}; + +//!Data class for holding info about non-overlapping +// interactive rectilinear "zones" overlaid on plots +class PlotRegion +{ + public: + //Axis along which bounds are set. Each entry is unique + vector boundAxis; + //Bounding limits for axial bind + vector > bounds; + + //Bounding region colour + float r,g,b; + //The parent filter, so region can tell who the parent is + Filter *parentFilter; + //The ID value for this region, used when interacting with parent filter + unsigned int id; + //!Unique ID for region across entire multiplot + unsigned int uniqueID; +}; + +//!Base class for data plotting +class PlotBase +{ + public: + PlotBase(){}; + virtual ~PlotBase(){}; + //The type of plot (ie what class is it?) + unsigned int plotType; + + //!Bounding box for plot - may exceed plot data area + float minX,maxX,minY,maxY; + + //!Colour of trace + float r,g,b; + //!Is trace visible? + bool visible; + //!Type of plot (lines, bars, sticks, etc) + unsigned int traceType; + //!xaxis label + std::wstring xLabel; + //!y axis label + std::wstring yLabel; + //!Plot title + std::wstring title; + + //!Use the plot title for Y data label when exporting raw data + // (true), or use the yLabel + bool titleAsRawDataLabel; + + //!Pointer to some constant object that generated this plot + const void *parentObject; + + //!Interactive, or otherwise marked plot regions + vector regions; + //ID handler for regions + UniqueIDHandler regionIDHandler; + + //!integer to show which of the n plots that the parent generated + //that this data is represented by + unsigned int parentPlotIndex; + + //Draw the plot onto a given MGL graph + virtual void drawPlot(mglGraph *graph, MGLColourFixer &fixer) const=0; + + //!Scan for the data bounds. + virtual void getBounds(float &xMin,float &xMax, + float &yMin,float &yMax) const = 0; + + //Retrieve the raw data associated with this plot. + virtual void getRawData(vector > &f, + std::vector &labels) const=0; + + //!Retrieve the ID of the non-overlapping region in X-Y space + virtual bool getRegionIdAtPosition(float x, float y, unsigned int &id) const=0; + //!Retrieve a region using its unique ID + virtual void getRegion(unsigned int id, PlotRegion &r) const=0; + + //!Get the number of regions; + size_t getNumRegions() const { return regions.size();}; + + //!Pass the region movement information to the parent filter object + virtual void moveRegion(unsigned int regionId, unsigned int method, + float newX, float newY) const=0; + + //!Obtain limit of motion for a given region movement type + virtual void moveRegionLimit(unsigned int regionId, + unsigned int movementType, float &maxX, float &maxY) const=0; + +}; + +//!1D Function f(x) Plot with ranges +// data must be a pure Function. +class Plot1D : public PlotBase +{ + private: + + //!Should plot logarithm (+1) of data? Be careful of -ve values. + bool logarithmic; + //!Data + std::vector xValues,yValues,errBars; + + + public: + Plot1D(); + + + void getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const; + + //!Set the plot data from a pair and symmetric Y error + void setData(const vector > &v); + void setData(const vector > &v,const vector &symYErr); + //!Set the plot data from two vectors and symmetric Y error + void setData(const vector &vX, const vector &vY); + void setData(const vector &vX, const vector &vY, + const vector &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); + + //!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) + float moveRegionTest(unsigned int region, unsigned int method, float newPos) const; + + //!Move a region to a new location. MUST call moveRegionTest first. + void moveRegion(unsigned int region, unsigned int method, float newPos); + + void clear(bool preserveVisibility); + + + //Draw the plot onto a given MGL graph + virtual void drawPlot(mglGraph *graph,MGLColourFixer &fixer) const; + + //Draw the associated regions + void drawRegions(mglGraph *graph, MGLColourFixer &fixer, + const mglPoint &min, const mglPoint &max) const; + + + //!Retrieve the raw data associated with the currently visible plots. + //note that this is the FULL data not the zoomed data for the current user bounds + void getRawData(std::vector > &rawData, + std::vector &labels) const; + + //!Retrieve the ID of the non-overlapping region in X-Y space + bool getRegionIdAtPosition(float x, float y, unsigned int &id) const; + + //!Retrieve a region using its unique ID + void getRegion(unsigned int id, PlotRegion &r) const; + + //!Pass the region movement information to the parent filter object + void moveRegion(unsigned int regionId, unsigned int method, float newX, float newY) const; + + //Get the region motion limits, to ensure that the selected region does not + //overlap after a move operation. Note that the output variables will only + //be set for the appropriate motion direction. Eg, an X only move will not + //set limitY. + void moveRegionLimit(unsigned int regionId, + unsigned int movementType, float &limitX, float &limitY) const; + + bool wantLogPlot() const { return logarithmic;}; + void setLogarithmic(bool p){logarithmic=p;}; +}; + +//Wrapper class for containing multiple plots +class PlotWrapper +{ + protected: + //!Has the plot changed since we last rendered it? + bool plotChanged; + //!Elements of the plot + std::vector plottingData; + + //!which plots were last visible? + std::vector > lastVisiblePlots; + + //Position independant ID handling for the + //plots inserted into the vector + UniqueIDHandler plotIDHandler; + + + //!Use user-specified bounding values? + bool applyUserBounds; + //!User mininum bounds + float xUserMin,yUserMin; + //!User maximum bounds + float xUserMax,yUserMax; + + //!Switch to enable or disable drawing of the plot legend + bool drawLegend; + + //!is user interaction with the plot supposed to be locked? + // - is used to ensure that when updating plot, UI control + // will be hinted to take correct action + bool interactionLocked; + + public: + //!Constructor + PlotWrapper(); + + //!Destructor must delete target plots + ~PlotWrapper(); + + + bool isInteractionLocked() const { return interactionLocked;}; + + void lockInteraction(bool lock=true) {interactionLocked=lock;}; + + //!Has the contents of the plot changed since the last call to resetChange? + bool hasChanged() const { return plotChanged;}; + + void resetChange() { plotChanged=false;} + + //!Erase all the plot data + void clear(bool preserveVisibility=false); + + //!Hide all plots (sets all visibility to false) + void hideAll(); + + //!Set the visibilty of a plot, based upon its uniqueID + void setVisible(unsigned int uniqueID, bool isVisible=true); + + //!Get the bounds for the plot + void scanBounds(float &xMin,float &xMax,float &yMin,float &yMax) const; + //Draw the plot onto a given MGL graph. Only one type (1D,2D etc) of plot may be visible + void drawPlot(mglGraph *graph) const; + + //!Set the X Y and title strings + void setStrings(unsigned int plotID, + const char *x, const char *y, const char *t); + void setStrings(unsigned int plotID,const std::string &x, + const std::string &y,const std::string &t); + //!Set the parent information for a given plot + void setParentData(unsigned int plotID, + const void *parentObj, unsigned int plotIndex); + + //!Set the plotting mode. + void setTraceStyle(unsigned int plotID,unsigned int mode); + + //!Set the plot colours + void setColours(unsigned int plotID, float rN,float gN,float bN); + //!Set the bounds on the plot + void setBounds(float xMin, float xMax, + float yMin,float yMax); + //!Get the bounds for the plot + void getBounds(float &xMin, float &xMax, + float &yMin,float &yMax) const; + //!Automatically use the data limits to compute bounds + void resetBounds(); + + + //!Get the number of visible plots + unsigned int getNumVisible() const; + + //!Returns true if plot is visible, based upon its uniqueID. + bool isPlotVisible(unsigned int plotID) const; + + //!Disable user bounds + void disableUserBounds(){plotChanged=true;applyUserBounds=false;}; + + //!Disable user axis bounds along one axis only + void disableUserAxisBounds(bool xAxis); + + //!Do our best to restore the visibility of the plot to what it was + //before the last clear based upon the plot data owner information. + //Note that this will erase the last stored visibility data when complete. + void bestEffortRestoreVisibility(); + + + //!Set whether to enable the legend or not + void setLegendVisible(bool vis) { drawLegend=vis;plotChanged=true;}; + + //!Add a plot to the list of available plots. Control of the pointer becomes + //transferred to this class, so do *NOT* delete it after calling this function + unsigned int addPlot(PlotBase *plot); + + //!Get the ID (return value) and the contents of the plot region at the given position. + // Returns false if no region can be found, and true if valid region found + bool getRegionIdAtPosition(float px, float py, + unsigned int &plotId, unsigned int ®ionID ) const; + + + //Return the region data for the given regionID/plotID combo + void getRegion(unsigned int plotId, unsigned int regionId, PlotRegion &r) const; + + //!Retrieve the raw data associated with the selected plots. + void getRawData(vector > > &data, std::vector > &labels) const; + + + //!obtain the type of a plot, given the plot's uniqueID + unsigned int plotType(unsigned int plotId) const; + + //Retrieve the types of visible plots + unsigned int getVisibleType() const; + + //!Obtain limit of motion for a given region movement type + void moveRegionLimit(unsigned int plotId, unsigned int regionId, + unsigned int movementType, float &maxX, float &maxY) const; + + //!Pass the region movement information to the parent filter object + void moveRegion(unsigned int plotID, unsigned int regionId, unsigned int movementType, + float newX, float newY) const; +}; + +#endif diff -Nru 3depict-0.0.12/src/backend/tree.hh 3depict-0.0.13/src/backend/tree.hh --- 3depict-0.0.12/src/backend/tree.hh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/tree.hh 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,2718 @@ +/* + * tree.hh - STL-like templated tree class. + * Copyright (C) 2001-2009, Kasper Peeters + + * 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 . +*/ + +// Distributed under the GNU General Public License version 3, +// (eventually to be changed to the Boost Software License). + +/** The tree.hh library for C++ provides an STL-like container class + for n-ary trees, templated over the data stored at the + nodes. Various types of iterators are provided (post-order, + pre-order, and others). Where possible the access methods are + compatible with the STL or alternative algorithms are + available. +*/ + + +#ifndef tree_hh_ +#define tree_hh_ + +#include +#include +#include +#include +#include +#include +#include +#include + +// HP-style construct/destroy have gone from the standard, +// so here is a copy. + +namespace kp { + +template +void constructor(T1* p, T2& val) + { + new ((void *) p) T1(val); + } + +template +void constructor(T1* p) + { + new ((void *) p) T1; + } + +template +void destructor(T1* p) + { + p->~T1(); + } + +} + +/// A node in the tree, combining links to other nodes as well as the actual data. +template +class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. + public: + tree_node_ *parent; + tree_node_ *first_child, *last_child; + tree_node_ *prev_sibling, *next_sibling; + T data; +}; // __attribute__((packed)); + +template > > +class tree { + protected: + typedef tree_node_ tree_node; + public: + /// Value of the data stored at a node. + typedef T value_type; + + class iterator_base; + class pre_order_iterator; + class post_order_iterator; + class sibling_iterator; + class leaf_iterator; + + tree(); + tree(const T&); + tree(const iterator_base&); + tree(const tree&); + ~tree(); + void operator=(const tree&); + + /// Base class for iterators, only pointers stored, no traversal logic. +#ifdef __SGI_STL_PORT + class iterator_base : public stlport::bidirectional_iterator { +#else + class iterator_base { +#endif + public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator_base(); + iterator_base(tree_node *); + + T& operator*() const; + T* operator->() const; + + /// When called, the next increment/decrement skips children of this node. + void skip_children(); + void skip_children(bool skip); + /// Number of children of the node pointed to by the iterator. + unsigned int number_of_children() const; + + sibling_iterator begin() const; + sibling_iterator end() const; + + tree_node *node; + protected: + bool skip_current_children_; + }; + + /// Depth-first iterator, first accessing the node, then its children. + class pre_order_iterator : public iterator_base { + public: + pre_order_iterator(); + pre_order_iterator(tree_node *); + pre_order_iterator(const iterator_base&); + pre_order_iterator(const sibling_iterator&); + + bool operator==(const pre_order_iterator&) const; + bool operator!=(const pre_order_iterator&) const; + pre_order_iterator& operator++(); + pre_order_iterator& operator--(); + pre_order_iterator operator++(int); + pre_order_iterator operator--(int); + pre_order_iterator& operator+=(unsigned int); + pre_order_iterator& operator-=(unsigned int); + }; + + /// Depth-first iterator, first accessing the children, then the node itself. + class post_order_iterator : public iterator_base { + public: + post_order_iterator(); + post_order_iterator(tree_node *); + post_order_iterator(const iterator_base&); + post_order_iterator(const sibling_iterator&); + + bool operator==(const post_order_iterator&) const; + bool operator!=(const post_order_iterator&) const; + post_order_iterator& operator++(); + post_order_iterator& operator--(); + post_order_iterator operator++(int); + post_order_iterator operator--(int); + post_order_iterator& operator+=(unsigned int); + post_order_iterator& operator-=(unsigned int); + + /// Set iterator to the first child as deep as possible down the tree. + void descend_all(); + }; + + /// Breadth-first iterator, using a queue + class breadth_first_queued_iterator : public iterator_base { + public: + breadth_first_queued_iterator(); + breadth_first_queued_iterator(tree_node *); + breadth_first_queued_iterator(const iterator_base&); + + bool operator==(const breadth_first_queued_iterator&) const; + bool operator!=(const breadth_first_queued_iterator&) const; + breadth_first_queued_iterator& operator++(); + breadth_first_queued_iterator operator++(int); + breadth_first_queued_iterator& operator+=(unsigned int); + + private: + std::queue traversal_queue; + }; + + /// The default iterator types throughout the tree class. + typedef pre_order_iterator iterator; + typedef breadth_first_queued_iterator breadth_first_iterator; + + /// Iterator which traverses only the nodes at a given depth from the root. + class fixed_depth_iterator : public iterator_base { + public: + fixed_depth_iterator(); + fixed_depth_iterator(tree_node *); + fixed_depth_iterator(const iterator_base&); + fixed_depth_iterator(const sibling_iterator&); + fixed_depth_iterator(const fixed_depth_iterator&); + + bool operator==(const fixed_depth_iterator&) const; + bool operator!=(const fixed_depth_iterator&) const; + fixed_depth_iterator& operator++(); + fixed_depth_iterator& operator--(); + fixed_depth_iterator operator++(int); + fixed_depth_iterator operator--(int); + fixed_depth_iterator& operator+=(unsigned int); + fixed_depth_iterator& operator-=(unsigned int); + + tree_node *top_node; + }; + + /// Iterator which traverses only the nodes which are siblings of each other. + class sibling_iterator : public iterator_base { + public: + sibling_iterator(); + sibling_iterator(tree_node *); + sibling_iterator(const sibling_iterator&); + sibling_iterator(const iterator_base&); + + bool operator==(const sibling_iterator&) const; + bool operator!=(const sibling_iterator&) const; + sibling_iterator& operator++(); + sibling_iterator& operator--(); + sibling_iterator operator++(int); + sibling_iterator operator--(int); + sibling_iterator& operator+=(unsigned int); + sibling_iterator& operator-=(unsigned int); + + tree_node *range_first() const; + tree_node *range_last() const; + tree_node *parent_; + private: + void set_parent_(); + }; + + /// Iterator which traverses only the leaves. + class leaf_iterator : public iterator_base { + public: + leaf_iterator(); + leaf_iterator(tree_node *, tree_node *top=0); + leaf_iterator(const sibling_iterator&); + leaf_iterator(const iterator_base&); + + bool operator==(const leaf_iterator&) const; + bool operator!=(const leaf_iterator&) const; + leaf_iterator& operator++(); + leaf_iterator& operator--(); + leaf_iterator operator++(int); + leaf_iterator operator--(int); + leaf_iterator& operator+=(unsigned int); + leaf_iterator& operator-=(unsigned int); + private: + tree_node *top_node; + }; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator begin() const; + /// Return iterator to the end of the tree. + inline pre_order_iterator end() const; + /// Return post-order iterator to the beginning of the tree. + post_order_iterator begin_post() const; + /// Return post-order end iterator of the tree. + post_order_iterator end_post() const; + /// Return fixed-depth iterator to the first node at a given depth from the given iterator. + fixed_depth_iterator begin_fixed(const iterator_base&, unsigned int) const; + /// Return fixed-depth end iterator. + fixed_depth_iterator end_fixed(const iterator_base&, unsigned int) const; + /// Return breadth-first iterator to the first node at a given depth. + breadth_first_queued_iterator begin_breadth_first() const; + /// Return breadth-first end iterator. + breadth_first_queued_iterator end_breadth_first() const; + /// Return sibling iterator to the first child of given node. + sibling_iterator begin(const iterator_base&) const; + /// Return sibling end iterator for children of given node. + sibling_iterator end(const iterator_base&) const; + /// Return leaf iterator to the first leaf of the tree. + leaf_iterator begin_leaf() const; + /// Return leaf end iterator for entire tree. + leaf_iterator end_leaf() const; + /// Return leaf iterator to the first leaf of the subtree at the given node. + leaf_iterator begin_leaf(const iterator_base& top) const; + /// Return leaf end iterator for the subtree at the given node. + leaf_iterator end_leaf(const iterator_base& top) const; + + /// Return iterator to the parent of a node. + template static iter parent(iter); + /// Return iterator to the previous sibling of a node. + template iter previous_sibling(iter) const; + /// Return iterator to the next sibling of a node. + template iter next_sibling(iter) const; + /// Return iterator to the next node at a given depth. + template iter next_at_same_depth(iter) const; + + /// Erase all nodes of the tree. + void clear(); + /// Erase element at position pointed to by iterator, return incremented iterator. + template iter erase(iter); + /// Erase all children of the node pointed to by iterator. + void erase_children(const iterator_base&); + + /// Insert empty node as last/first child of node pointed to by position. + template iter append_child(iter position); + template iter prepend_child(iter position); + /// Insert node as last/first child of node pointed to by position. + template iter append_child(iter position, const T& x); + template iter prepend_child(iter position, const T& x); + /// Append the node (plus its children) at other_position as last/first child of position. + template iter append_child(iter position, iter other_position); + template iter prepend_child(iter position, iter other_position); + /// Append the nodes in the from-to range (plus their children) as last/first children of position. + template iter append_children(iter position, sibling_iterator from, sibling_iterator to); + template iter prepend_children(iter position, sibling_iterator from, sibling_iterator to); + + /// Short-hand to insert topmost node in otherwise empty tree. + pre_order_iterator set_head(const T& x); + /// Insert node as previous sibling of node pointed to by position. + template iter insert(iter position, const T& x); + /// Specialisation of previous member. + sibling_iterator insert(sibling_iterator position, const T& x); + /// Insert node (with children) pointed to by subtree as previous sibling of node pointed to by position. + template iter insert_subtree(iter position, const iterator_base& subtree); + /// Insert node as next sibling of node pointed to by position. + template iter insert_after(iter position, const T& x); + /// Insert node (with children) pointed to by subtree as next sibling of node pointed to by position. + template iter insert_subtree_after(iter position, const iterator_base& subtree); + + /// Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. + template iter replace(iter position, const T& x); + /// Replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above. + template iter replace(iter position, const iterator_base& from); + /// Replace string of siblings (plus their children) with copy of a new string (with children); see above + sibling_iterator replace(sibling_iterator orig_begin, sibling_iterator orig_end, + sibling_iterator new_begin, sibling_iterator new_end); + + /// Move all children of node at 'position' to be siblings, returns position. + template iter flatten(iter position); + /// Move nodes in range to be children of 'position'. + template iter reparent(iter position, sibling_iterator begin, sibling_iterator end); + /// Move all child nodes of 'from' to be children of 'position'. + template iter reparent(iter position, iter from); + + /// Replace node with a new node, making the old node a child of the new node. + template iter wrap(iter position, const T& x); + + /// Move 'source' node (plus its children) to become the next sibling of 'target'. + template iter move_after(iter target, iter source); + /// Move 'source' node (plus its children) to become the previous sibling of 'target'. + template iter move_before(iter target, iter source); + sibling_iterator move_before(sibling_iterator target, sibling_iterator source); + /// Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target'). + template iter move_ontop(iter target, iter source); + + /// Merge with other tree, creating new branches and leaves only if they are not already present. + void merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, + bool duplicate_leaves=false); + /// Sort (std::sort only moves values of nodes, this one moves children as well). + void sort(sibling_iterator from, sibling_iterator to, bool deep=false); + template + void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); + /// Compare two ranges of nodes (compares nodes as well as tree structure). + template + bool equal(const iter& one, const iter& two, const iter& three) const; + template + bool equal(const iter& one, const iter& two, const iter& three, BinaryPredicate) const; + template + bool equal_subtree(const iter& one, const iter& two) const; + template + bool equal_subtree(const iter& one, const iter& two, BinaryPredicate) const; + /// Extract a new tree formed by the range of siblings plus all their children. + tree subtree(sibling_iterator from, sibling_iterator to) const; + void subtree(tree&, sibling_iterator from, sibling_iterator to) const; + /// Exchange the node (plus subtree) with its sibling node (do nothing if no sibling present). + void swap(sibling_iterator it); + /// Exchange two nodes (plus subtrees) + void swap(iterator, iterator); + + /// Count the total number of nodes. + size_t size() const; + /// Count the total number of nodes below the indicated node (plus one). + size_t size(const iterator_base&) const; + /// Check if tree is empty. + bool empty() const; + /// Compute the depth to the root or to a fixed other iterator. + static int depth(const iterator_base&); + static int depth(const iterator_base&, const iterator_base&); + /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. + int max_depth() const; + /// Determine the maximal depth of the tree with top node at the given position. + int max_depth(const iterator_base&) const; + /// Count the number of children of node at position. + static unsigned int number_of_children(const iterator_base&); + /// Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1. + unsigned int number_of_siblings(const iterator_base&) const; + /// Determine whether node at position is in the subtrees with root in the range. + bool is_in_subtree(const iterator_base& position, const iterator_base& begin, + const iterator_base& end) const; + /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. + bool is_valid(const iterator_base&) const; + + /// Determine the index of a node in the range of siblings to which it belongs. + unsigned int index(sibling_iterator it) const; + /// Inverse of 'index': return the n-th child of the node at position. + static sibling_iterator child(const iterator_base& position, unsigned int); + /// Return iterator to the sibling indicated by index + sibling_iterator sibling(const iterator_base& position, unsigned int); + + /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) + class iterator_base_less { + public: + bool operator()(const typename tree::iterator_base& one, + const typename tree::iterator_base& two) const + { + return one.node < two.node; + } + }; + tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid + private: + tree_node_allocator alloc_; + void head_initialise_(); + void copy_(const tree& other); + + /// Comparator class for two nodes of a tree (used for sorting and searching). + template + class compare_nodes { + public: + compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; + + bool operator()(const tree_node *a, const tree_node *b) + { + return comp_(a->data, b->data); + } + private: + StrictWeakOrdering comp_; + }; +}; + +//template +//class iterator_base_less { +// public: +// bool operator()(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) const +// { +// txtout << "operatorclass<" << one.node < two.node << std::endl; +// return one.node < two.node; +// } +//}; + +// template +// bool operator<(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator< " << one.node < two.node << std::endl; +// if(one.node < two.node) return true; +// return false; +// } +// +// template +// bool operator==(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator== " << one.node == two.node << std::endl; +// if(one.node == two.node) return true; +// return false; +// } +// +// template +// bool operator>(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) +// { +// txtout << "operator> " << one.node < two.node << std::endl; +// if(one.node > two.node) return true; +// return false; +// } + + + +// Tree + +template +tree::tree() + { + head_initialise_(); + } + +template +tree::tree(const T& x) + { + head_initialise_(); + set_head(x); + } + +template +tree::tree(const iterator_base& other) + { + head_initialise_(); + set_head((*other)); + replace(begin(), other); + } + +template +tree::~tree() + { + clear(); + alloc_.deallocate(head,1); + alloc_.deallocate(feet,1); + } + +template +void tree::head_initialise_() + { + head = alloc_.allocate(1,0); // MSVC does not have default second argument + feet = alloc_.allocate(1,0); + + head->parent=0; + head->first_child=0; + head->last_child=0; + head->prev_sibling=0; //head; + head->next_sibling=feet; //head; + + feet->parent=0; + feet->first_child=0; + feet->last_child=0; + feet->prev_sibling=head; + feet->next_sibling=0; + } + +template +void tree::operator=(const tree& other) + { + copy_(other); + } + +template +tree::tree(const tree& other) + { + head_initialise_(); + copy_(other); + } + +template +void tree::copy_(const tree& other) + { + clear(); + pre_order_iterator it=other.begin(), to=begin(); + while(it!=other.end()) { + to=insert(to, (*it)); + it.skip_children(); + ++it; + } + to=begin(); + it=other.begin(); + while(it!=other.end()) { + to=replace(to, it); + to.skip_children(); + it.skip_children(); + ++to; + ++it; + } + } + +template +void tree::clear() + { + if(head) + while(head->next_sibling!=feet) + erase(pre_order_iterator(head->next_sibling)); + } + +template +void tree::erase_children(const iterator_base& it) + { +// std::cout << "erase_children " << it.node << std::endl; + if(it.node==0) return; + + tree_node *cur=it.node->first_child; + tree_node *prev=0; + + while(cur!=0) { + prev=cur; + cur=cur->next_sibling; + erase_children(pre_order_iterator(prev)); + kp::destructor(&prev->data); + alloc_.deallocate(prev,1); + } + it.node->first_child=0; + it.node->last_child=0; +// std::cout << "exit" << std::endl; + } + +template +template +iter tree::erase(iter it) + { + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ret.skip_children(); + ++ret; + erase_children(it); + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + + kp::destructor(&cur->data); + alloc_.deallocate(cur,1); + return ret; + } + +template +typename tree::pre_order_iterator tree::begin() const + { + return pre_order_iterator(head->next_sibling); + } + +template +typename tree::pre_order_iterator tree::end() const + { + return pre_order_iterator(feet); + } + +template +typename tree::breadth_first_queued_iterator tree::begin_breadth_first() const + { + return breadth_first_queued_iterator(head->next_sibling); + } + +template +typename tree::breadth_first_queued_iterator tree::end_breadth_first() const + { + return breadth_first_queued_iterator(); + } + +template +typename tree::post_order_iterator tree::begin_post() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return post_order_iterator(tmp); + } + +template +typename tree::post_order_iterator tree::end_post() const + { + return post_order_iterator(feet); + } + +template +typename tree::fixed_depth_iterator tree::begin_fixed(const iterator_base& pos, unsigned int dp) const + { + typename tree::fixed_depth_iterator ret; + ret.top_node=pos.node; + + tree_node *tmp=pos.node; + unsigned int curdepth=0; + while(curdepthfirst_child==0) { + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + if(tmp==ret.top_node) + throw std::range_error("tree: begin_fixed out of range"); + tmp=tmp->parent; + if(tmp==0) + throw std::range_error("tree: begin_fixed out of range"); + --curdepth; + } while(tmp->next_sibling==0); + } + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + } + + ret.node=tmp; + return ret; + } + +template +typename tree::fixed_depth_iterator tree::end_fixed(const iterator_base& pos, unsigned int dp) const + { + assert(1==0); // FIXME: not correct yet: use is_valid() as a temporary workaround + tree_node *tmp=pos.node; + unsigned int curdepth=1; + while(curdepthfirst_child==0) { + tmp=tmp->next_sibling; + if(tmp==0) + throw std::range_error("tree: end_fixed out of range"); + } + tmp=tmp->first_child; + ++curdepth; + } + return tmp; + } + +template +typename tree::sibling_iterator tree::begin(const iterator_base& pos) const + { + assert(pos.node!=0); + if(pos.node->first_child==0) { + return end(pos); + } + return pos.node->first_child; + } + +template +typename tree::sibling_iterator tree::end(const iterator_base& pos) const + { + sibling_iterator ret(0); + ret.parent_=pos.node; + return ret; + } + +template +typename tree::leaf_iterator tree::begin_leaf() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return leaf_iterator(tmp); + } + +template +typename tree::leaf_iterator tree::end_leaf() const + { + return leaf_iterator(feet); + } + +template +typename tree::leaf_iterator tree::begin_leaf(const iterator_base& top) const + { + tree_node *tmp=top.node; + while(tmp->first_child) + tmp=tmp->first_child; + return leaf_iterator(tmp, top.node); + } + +template +typename tree::leaf_iterator tree::end_leaf(const iterator_base& top) const + { + return leaf_iterator(top.node, top.node); + } + +template +template +iter tree::parent(iter position) + { + assert(position.node!=0); + return iter(position.node->parent); + } + +template +template +iter tree::previous_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->prev_sibling; + return ret; + } + +template +template +iter tree::next_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->next_sibling; + return ret; + } + +template +template +iter tree::next_at_same_depth(iter position) const + { + // We make use of a temporary fixed_depth iterator to implement this. + + typename tree::fixed_depth_iterator tmp(position.node); + + ++tmp; + return iter(tmp); + +// assert(position.node!=0); +// iter ret(position); +// +// if(position.node->next_sibling) { +// ret.node=position.node->next_sibling; +// } +// else { +// int relative_depth=0; +// upper: +// do { +// ret.node=ret.node->parent; +// if(ret.node==0) return ret; +// --relative_depth; +// } while(ret.node->next_sibling==0); +// lower: +// ret.node=ret.node->next_sibling; +// while(ret.node->first_child==0) { +// if(ret.node->next_sibling==0) +// goto upper; +// ret.node=ret.node->next_sibling; +// if(ret.node==0) return ret; +// } +// while(relative_depth<0 && ret.node->first_child!=0) { +// ret.node=ret.node->first_child; +// ++relative_depth; +// } +// if(relative_depth<0) { +// if(ret.node->next_sibling==0) goto upper; +// else goto lower; +// } +// } +// return ret; + } + +template +template +iter tree::append_child(iter position) + { + assert(position.node!=head); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position) + { + assert(position.node!=head); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->prev_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, const T& x) + { + // If your program fails here you probably used 'append_child' to add the top + // node to an empty tree. From version 1.45 the top element should be added + // using 'insert'. See the documentation for further information, and sorry about + // the API change. + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position, const T& x) + { + assert(position.node!=head); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->first_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node); + + sibling_iterator aargh=append_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::prepend_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node); + + sibling_iterator aargh=prepend_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::append_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.end(), from); + ++from; + } + return ret; + } + +template +template +iter tree::prepend_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.begin(), from); + ++from; + } + return ret; + } + +template +typename tree::pre_order_iterator tree::set_head(const T& x) + { + assert(head->next_sibling==feet); + return insert(iterator(feet), x); + } + +template +template +iter tree::insert(iter position, const T& x) + { + if(position.node==0) { + position.node=feet; // Backward compatibility: when calling insert on a null node, + // insert before the feet. + } + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->next_sibling=position.node; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +typename tree::sibling_iterator tree::insert(sibling_iterator position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->next_sibling=position.node; + if(position.node==0) { // iterator points to end of a subtree + tmp->parent=position.parent_; + tmp->prev_sibling=position.range_last(); + tmp->parent->last_child=tmp; + } + else { + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + } + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +template +iter tree::insert_after(iter position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node; + tmp->next_sibling=position.node->next_sibling; + position.node->next_sibling=tmp; + + if(tmp->next_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->last_child=tmp; + } + else { + tmp->next_sibling->prev_sibling=tmp; + } + return tmp; + } + +template +template +iter tree::insert_subtree(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +template +template +iter tree::insert_subtree_after(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert_after(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +// template +// template +// iter tree::insert_subtree(sibling_iterator position, iter subtree) +// { +// // insert dummy +// iter it(insert(position, value_type())); +// // replace dummy with subtree +// return replace(it, subtree); +// } + +template +template +iter tree::replace(iter position, const T& x) + { + kp::destructor(&position.node->data); + kp::constructor(&position.node->data, x); + return position; + } + +template +template +iter tree::replace(iter position, const iterator_base& from) + { + assert(position.node!=head); + tree_node *current_from=from.node; + tree_node *start_from=from.node; + tree_node *current_to =position.node; + + // replace the node at position with head of the replacement tree at from +// std::cout << "warning!" << position.node << std::endl; + erase_children(position); +// std::cout << "no warning!" << std::endl; + tree_node* tmp = alloc_.allocate(1,0); + kp::constructor(&tmp->data, (*from)); + tmp->first_child=0; + tmp->last_child=0; + if(current_to->prev_sibling==0) { + if(current_to->parent!=0) + current_to->parent->first_child=tmp; + } + else { + current_to->prev_sibling->next_sibling=tmp; + } + tmp->prev_sibling=current_to->prev_sibling; + if(current_to->next_sibling==0) { + if(current_to->parent!=0) + current_to->parent->last_child=tmp; + } + else { + current_to->next_sibling->prev_sibling=tmp; + } + tmp->next_sibling=current_to->next_sibling; + tmp->parent=current_to->parent; + kp::destructor(¤t_to->data); + alloc_.deallocate(current_to,1); + current_to=tmp; + + // only at this stage can we fix 'last' + tree_node *last=from.node->next_sibling; + + pre_order_iterator toit=tmp; + // copy all children + do { + assert(current_from!=0); + if(current_from->first_child != 0) { + current_from=current_from->first_child; + toit=append_child(toit, current_from->data); + } + else { + while(current_from->next_sibling==0 && current_from!=start_from) { + current_from=current_from->parent; + toit=parent(toit); + assert(current_from!=0); + } + current_from=current_from->next_sibling; + if(current_from!=last) { + toit=append_child(parent(toit), current_from->data); + } + } + } while(current_from!=last); + + return current_to; + } + +template +typename tree::sibling_iterator tree::replace( + sibling_iterator orig_begin, + sibling_iterator orig_end, + sibling_iterator new_begin, + sibling_iterator new_end) + { + tree_node *orig_first=orig_begin.node; + tree_node *new_first=new_begin.node; + tree_node *orig_last=orig_first; + while((++orig_begin)!=orig_end) + orig_last=orig_last->next_sibling; + tree_node *new_last=new_first; + while((++new_begin)!=new_end) + new_last=new_last->next_sibling; + + // insert all siblings in new_first..new_last before orig_first + bool first=true; + pre_order_iterator ret; + while(1==1) { + pre_order_iterator tt=insert_subtree(pre_order_iterator(orig_first), pre_order_iterator(new_first)); + if(first) { + ret=tt; + first=false; + } + if(new_first==new_last) + break; + new_first=new_first->next_sibling; + } + + // erase old range of siblings + bool last=false; + tree_node *next=orig_first; + while(1==1) { + if(next==orig_last) + last=true; + next=next->next_sibling; + erase((pre_order_iterator)orig_first); + if(last) + break; + orig_first=next; + } + return ret; + } + +template +template +iter tree::flatten(iter position) + { + if(position.node->first_child==0) + return position; + + tree_node *tmp=position.node->first_child; + while(tmp) { + tmp->parent=position.node->parent; + tmp=tmp->next_sibling; + } + if(position.node->next_sibling) { + position.node->last_child->next_sibling=position.node->next_sibling; + position.node->next_sibling->prev_sibling=position.node->last_child; + } + else { + position.node->parent->last_child=position.node->last_child; + } + position.node->next_sibling=position.node->first_child; + position.node->next_sibling->prev_sibling=position.node; + position.node->first_child=0; + position.node->last_child=0; + + return position; + } + + +template +template +iter tree::reparent(iter position, sibling_iterator begin, sibling_iterator end) + { + tree_node *first=begin.node; + tree_node *last=first; + + assert(first!=position.node); + + if(begin==end) return begin; + // determine last node + while((++begin)!=end) { + last=last->next_sibling; + } + // move subtree + if(first->prev_sibling==0) { + first->parent->first_child=last->next_sibling; + } + else { + first->prev_sibling->next_sibling=last->next_sibling; + } + if(last->next_sibling==0) { + last->parent->last_child=first->prev_sibling; + } + else { + last->next_sibling->prev_sibling=first->prev_sibling; + } + if(position.node->first_child==0) { + position.node->first_child=first; + position.node->last_child=last; + first->prev_sibling=0; + } + else { + position.node->last_child->next_sibling=first; + first->prev_sibling=position.node->last_child; + position.node->last_child=last; + } + last->next_sibling=0; + + tree_node *pos=first; + for(;;) { + pos->parent=position.node; + if(pos==last) break; + pos=pos->next_sibling; + } + + return first; + } + +template +template iter tree::reparent(iter position, iter from) + { + if(from.node->first_child==0) return position; + return reparent(position, from.node->first_child, end(from)); + } + +template +template iter tree::wrap(iter position, const T& x) + { + assert(position.node!=0); + sibling_iterator fr=position, to=position; + ++to; + iter ret = insert(position, x); + reparent(ret, fr, to); + return ret; + } + +template +template iter tree::move_after(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->next_sibling) + if(dst->next_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; + else dst->parent->last_child=src; + src->next_sibling=dst->next_sibling; + dst->next_sibling=src; + src->prev_sibling=dst; + src->parent=dst->parent; + return src; + } + +template +template iter tree::move_before(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->prev_sibling) + if(dst->prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; + else dst->parent->first_child=src; + src->prev_sibling=dst->prev_sibling; + dst->prev_sibling=src; + src->next_sibling=dst; + src->parent=dst->parent; + return src; + } + +// specialisation for sibling_iterators +template +typename tree::sibling_iterator tree::move_before(sibling_iterator target, + sibling_iterator source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + tree_node *dst_prev_sibling; + if(dst==0) { // must then be an end iterator + dst_prev_sibling=target.parent_->last_child; + assert(dst_prev_sibling); + } + else dst_prev_sibling=dst->prev_sibling; + assert(src); + + if(dst==src) return source; + if(dst_prev_sibling) + if(dst_prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst_prev_sibling!=0) dst_prev_sibling->next_sibling=src; + else target.parent_->first_child=src; + src->prev_sibling=dst_prev_sibling; + if(dst) { + dst->prev_sibling=src; + src->parent=dst->parent; + } + src->next_sibling=dst; + return src; + } + +template +template iter tree::move_ontop(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + + // remember connection points + tree_node *b_prev_sibling=dst->prev_sibling; + tree_node *b_next_sibling=dst->next_sibling; + tree_node *b_parent=dst->parent; + + // remove target + erase(target); + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(b_prev_sibling!=0) b_prev_sibling->next_sibling=src; + else b_parent->first_child=src; + if(b_next_sibling!=0) b_next_sibling->prev_sibling=src; + else b_parent->last_child=src; + src->prev_sibling=b_prev_sibling; + src->next_sibling=b_next_sibling; + src->parent=b_parent; + return src; + } + +template +void tree::merge(sibling_iterator to1, sibling_iterator to2, + sibling_iterator from1, sibling_iterator from2, + bool duplicate_leaves) + { + sibling_iterator fnd; + while(from1!=from2) { + if((fnd=std::find(to1, to2, (*from1))) != to2) { // element found + if(from1.begin()==from1.end()) { // full depth reached + if(duplicate_leaves) + append_child(parent(to1), (*from1)); + } + else { // descend further + merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(), duplicate_leaves); + } + } + else { // element missing + insert_subtree(to2, from1); + } + ++from1; + } + } + + +template +void tree::sort(sibling_iterator from, sibling_iterator to, bool deep) + { + std::less comp; + sort(from, to, comp, deep); + } + +template +template +void tree::sort(sibling_iterator from, sibling_iterator to, + StrictWeakOrdering comp, bool deep) + { + if(from==to) return; + // make list of sorted nodes + // CHECK: if multiset stores equivalent nodes in the order in which they + // are inserted, then this routine should be called 'stable_sort'. + std::multiset > nodes(comp); + sibling_iterator it=from, it2=to; + while(it != to) { + nodes.insert(it.node); + ++it; + } + // reassemble + --it2; + + // prev and next are the nodes before and after the sorted range + tree_node *prev=from.node->prev_sibling; + tree_node *next=it2.node->next_sibling; + typename std::multiset >::iterator nit=nodes.begin(), eit=nodes.end(); + if(prev==0) { + if((*nit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*nit)->parent->first_child=(*nit); + } + else prev->next_sibling=(*nit); + + --eit; + while(nit!=eit) { + (*nit)->prev_sibling=prev; + if(prev) + prev->next_sibling=(*nit); + prev=(*nit); + ++nit; + } + // prev now points to the last-but-one node in the sorted range + if(prev) + prev->next_sibling=(*eit); + + // eit points to the last node in the sorted range. + (*eit)->next_sibling=next; + (*eit)->prev_sibling=prev; // missed in the loop above + if(next==0) { + if((*eit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*eit)->parent->last_child=(*eit); + } + else next->prev_sibling=(*eit); + + if(deep) { // sort the children of each node too + sibling_iterator bcs(*nodes.begin()); + sibling_iterator ecs(*eit); + ++ecs; + while(bcs!=ecs) { + sort(begin(bcs), end(bcs), comp, deep); + ++bcs; + } + } + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_) const + { + std::equal_to comp; + return equal(one_, two, three_, comp); + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_) const + { + std::equal_to comp; + return equal_subtree(one_, two_, comp); + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), three(three_); + +// if(one==two && is_valid(three) && three.number_of_children()!=0) +// return false; + while(one!=two && is_valid(three)) { + if(!fun(*one,*three)) + return false; + if(one.number_of_children()!=three.number_of_children()) + return false; + ++one; + ++three; + } + return true; + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), two(two_); + + if(!fun(*one,*two)) return false; + if(number_of_children(one)!=number_of_children(two)) return false; + return equal(begin(one),end(one),begin(two),fun); + } + +template +tree tree::subtree(sibling_iterator from, sibling_iterator to) const + { + tree tmp; + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + return tmp; + } + +template +void tree::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const + { + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + } + +template +size_t tree::size() const + { + size_t i=0; + pre_order_iterator it=begin(), eit=end(); + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +size_t tree::size(const iterator_base& top) const + { + size_t i=0; + pre_order_iterator it=top, eit=top; + eit.skip_children(); + ++eit; + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +bool tree::empty() const + { + pre_order_iterator it=begin(), eit=end(); + return (it==eit); + } + +template +int tree::depth(const iterator_base& it) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::depth(const iterator_base& it, const iterator_base& root) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0 && pos!=root.node) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::max_depth() const + { + int maxd=-1; + for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) + maxd=std::max(maxd, max_depth(it)); + + return maxd; + } + + +template +int tree::max_depth(const iterator_base& pos) const + { + tree_node *tmp=pos.node; + + if(tmp==0 || tmp==head || tmp==feet) return -1; + + int curdepth=0, maxdepth=0; + while(true) { // try to walk the bottom of the tree + while(tmp->first_child==0) { + if(tmp==pos.node) return maxdepth; + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + tmp=tmp->parent; + if(tmp==0) return maxdepth; + --curdepth; + } while(tmp->next_sibling==0); + } + if(tmp==pos.node) return maxdepth; + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + maxdepth=std::max(curdepth, maxdepth); + } + } + +template +unsigned int tree::number_of_children(const iterator_base& it) + { + tree_node *pos=it.node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; +// while(pos!=it.node->last_child) { +// ++ret; +// pos=pos->next_sibling; +// } + while((pos=pos->next_sibling)) + ++ret; + return ret; + } + +template +unsigned int tree::number_of_siblings(const iterator_base& it) const + { + tree_node *pos=it.node; + unsigned int ret=0; + // count forward + while(pos->next_sibling && + pos->next_sibling!=head && + pos->next_sibling!=feet) { + ++ret; + pos=pos->next_sibling; + } + // count backward + pos=it.node; + while(pos->prev_sibling && + pos->prev_sibling!=head && + pos->prev_sibling!=feet) { + ++ret; + pos=pos->prev_sibling; + } + + return ret; + } + +template +void tree::swap(sibling_iterator it) + { + tree_node *nxt=it.node->next_sibling; + if(nxt) { + if(it.node->prev_sibling) + it.node->prev_sibling->next_sibling=nxt; + else + it.node->parent->first_child=nxt; + nxt->prev_sibling=it.node->prev_sibling; + tree_node *nxtnxt=nxt->next_sibling; + if(nxtnxt) + nxtnxt->prev_sibling=it.node; + else + it.node->parent->last_child=it.node; + nxt->next_sibling=it.node; + it.node->prev_sibling=nxt; + it.node->next_sibling=nxtnxt; + } + } + +template +void tree::swap(iterator one, iterator two) + { + // if one and two are adjacent siblings, use the sibling swap + if(one.node->next_sibling==two.node) swap(one); + else if(two.node->next_sibling==one.node) swap(two); + else { + tree_node *nxt1=one.node->next_sibling; + tree_node *nxt2=two.node->next_sibling; + tree_node *pre1=one.node->prev_sibling; + tree_node *pre2=two.node->prev_sibling; + tree_node *par1=one.node->parent; + tree_node *par2=two.node->parent; + + // reconnect + one.node->parent=par2; + one.node->next_sibling=nxt2; + if(nxt2) nxt2->prev_sibling=one.node; + else par2->last_child=one.node; + one.node->prev_sibling=pre2; + if(pre2) pre2->next_sibling=one.node; + else par2->first_child=one.node; + + two.node->parent=par1; + two.node->next_sibling=nxt1; + if(nxt1) nxt1->prev_sibling=two.node; + else par1->last_child=two.node; + two.node->prev_sibling=pre1; + if(pre1) pre1->next_sibling=two.node; + else par1->first_child=two.node; + } + } + +// template +// tree::iterator tree::find_subtree( +// sibling_iterator subfrom, sibling_iterator subto, iterator from, iterator to, +// BinaryPredicate fun) const +// { +// assert(1==0); // this routine is not finished yet. +// while(from!=to) { +// if(fun(*subfrom, *from)) { +// +// } +// } +// return to; +// } + +template +bool tree::is_in_subtree(const iterator_base& it, const iterator_base& begin, + const iterator_base& end) const + { + // FIXME: this should be optimised. + pre_order_iterator tmp=begin; + while(tmp!=end) { + if(tmp==it) return true; + ++tmp; + } + return false; + } + +template +bool tree::is_valid(const iterator_base& it) const + { + if(it.node==0 || it.node==feet || it.node==head) return false; + else return true; + } + +template +unsigned int tree::index(sibling_iterator it) const + { + unsigned int ind=0; + if(it.node->parent==0) { + while(it.node->prev_sibling!=head) { + it.node=it.node->prev_sibling; + ++ind; + } + } + else { + while(it.node->prev_sibling!=0) { + it.node=it.node->prev_sibling; + ++ind; + } + } + return ind; + } + +template +typename tree::sibling_iterator tree::sibling(const iterator_base& it, unsigned int num) + { + tree_node *tmp; + if(it.node->parent==0) { + tmp=head->next_sibling; + while(num) { + tmp = tmp->next_sibling; + --num; + } + } + else { + tmp=it.node->parent->first_child; + while(num) { + assert(tmp!=0); + tmp = tmp->next_sibling; + --num; + } + } + return tmp; + } + + +template +typename tree::sibling_iterator tree::child(const iterator_base& it, unsigned int num) + { + tree_node *tmp=it.node->first_child; + while(num--) { + assert(tmp!=0); + tmp=tmp->next_sibling; + } + return tmp; + } + + + + +// Iterator base + +template +tree::iterator_base::iterator_base() + : node(0), skip_current_children_(false) + { + } + +template +tree::iterator_base::iterator_base(tree_node *tn) + : node(tn), skip_current_children_(false) + { + } + +template +T& tree::iterator_base::operator*() const + { + return node->data; + } + +template +T* tree::iterator_base::operator->() const + { + return &(node->data); + } + +template +bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::post_order_iterator::operator==(const post_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator!=(const sibling_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator==(const sibling_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator==(const leaf_iterator& other) const + { + if(other.node==this->node && other.top_node==this->top_node) return true; + else return false; + } + +template +typename tree::sibling_iterator tree::iterator_base::begin() const + { + if(node->first_child==0) + return end(); + + sibling_iterator ret(node->first_child); + ret.parent_=this->node; + return ret; + } + +template +typename tree::sibling_iterator tree::iterator_base::end() const + { + sibling_iterator ret(0); + ret.parent_=node; + return ret; + } + +template +void tree::iterator_base::skip_children() + { + skip_current_children_=true; + } + +template +void tree::iterator_base::skip_children(bool skip) + { + skip_current_children_=skip; + } + +template +unsigned int tree::iterator_base::number_of_children() const + { + tree_node *pos=node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + while(pos!=node->last_child) { + ++ret; + pos=pos->next_sibling; + } + return ret; + } + + + +// Pre-order iterator + +template +tree::pre_order_iterator::pre_order_iterator() + : iterator_base(0) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() + { + assert(this->node!=0); + if(!this->skip_current_children_ && this->node->first_child != 0) { + this->node=this->node->first_child; + } + else { + this->skip_current_children_=false; + while(this->node->next_sibling==0) { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + this->node=this->node->next_sibling; + } + return *this; + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() + { + assert(this->node!=0); + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + } + else { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + return *this; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) + { + pre_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) +{ + pre_order_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + + + +// Post-order iterator + +template +tree::post_order_iterator::post_order_iterator() + : iterator_base(0) + { + } + +template +tree::post_order_iterator::post_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::post_order_iterator::post_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::post_order_iterator::post_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator++() + { + assert(this->node!=0); + if(this->node->next_sibling==0) { + this->node=this->node->parent; + this->skip_current_children_=false; + } + else { + this->node=this->node->next_sibling; + if(this->skip_current_children_) { + this->skip_current_children_=false; + } + else { + while(this->node->first_child) + this->node=this->node->first_child; + } + } + return *this; + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator--() + { + assert(this->node!=0); + if(this->skip_current_children_ || this->node->last_child==0) { + this->skip_current_children_=false; + while(this->node->prev_sibling==0) + this->node=this->node->parent; + this->node=this->node->prev_sibling; + } + else { + this->node=this->node->last_child; + } + return *this; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator++(int) + { + post_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator--(int) + { + post_order_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +void tree::post_order_iterator::descend_all() + { + assert(this->node!=0); + while(this->node->first_child) + this->node=this->node->first_child; + } + + +// Breadth-first iterator + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator() + : iterator_base() + { + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) + : iterator_base(tn) + { + traversal_queue.push(tn); + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(const iterator_base& other) + : iterator_base(other.node) + { + traversal_queue.push(other.node); + } + +template +bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() + { + assert(this->node!=0); + + // Add child nodes and pop current node + sibling_iterator sib=this->begin(); + while(sib!=this->end()) { + traversal_queue.push(sib.node); + ++sib; + } + traversal_queue.pop(); + if(!traversal_queue.empty()) + this->node=traversal_queue.front(); + else + this->node=0; + return (*this); + } + +template +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) + { + breadth_first_queued_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + + + +// Fixed depth iterator + +template +tree::fixed_depth_iterator::fixed_depth_iterator() + : iterator_base() + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(tree_node *tn) + : iterator_base(tn), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const iterator_base& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const fixed_depth_iterator& other) + : iterator_base(other.node), top_node(other.top_node) + { + } + +template +bool tree::fixed_depth_iterator::operator==(const fixed_depth_iterator& other) const + { + if(other.node==this->node && other.top_node==top_node) return true; + else return false; + } + +template +bool tree::fixed_depth_iterator::operator!=(const fixed_depth_iterator& other) const + { + if(other.node!=this->node || other.top_node!=top_node) return true; + else return false; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator++() + { + assert(this->node!=0); + + if(this->node->next_sibling) { + this->node=this->node->next_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; // FIXME: return a proper fixed_depth end iterator once implemented + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->next_sibling==0); + lower: + this->node=this->node->next_sibling; + while(this->node->first_child==0) { + if(this->node->next_sibling==0) + goto upper; + this->node=this->node->next_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->first_child!=0) { + this->node=this->node->first_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->next_sibling==0) goto upper; + else goto lower; + } + } + return *this; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator--() + { + assert(this->node!=0); + + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->prev_sibling==0); + lower: + this->node=this->node->prev_sibling; + while(this->node->last_child==0) { + if(this->node->prev_sibling==0) + goto upper; + this->node=this->node->prev_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->last_child!=0) { + this->node=this->node->last_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->prev_sibling==0) goto upper; + else goto lower; + } + } + return *this; + +// +// +// assert(this->node!=0); +// if(this->node->prev_sibling!=0) { +// this->node=this->node->prev_sibling; +// assert(this->node!=0); +// if(this->node->parent==0 && this->node->prev_sibling==0) // head element +// this->node=0; +// } +// else { +// tree_node *par=this->node->parent; +// do { +// par=par->prev_sibling; +// if(par==0) { // FIXME: need to keep track of this! +// this->node=0; +// return *this; +// } +// } while(par->last_child==0); +// this->node=par->last_child; +// } +// return *this; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator++(int) + { + fixed_depth_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator--(int) + { + fixed_depth_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --(num); + } + return (*this); + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --(num); + } + return *this; + } + + +// Sibling iterator + +template +tree::sibling_iterator::sibling_iterator() + : iterator_base() + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(tree_node *tn) + : iterator_base(tn) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const iterator_base& other) + : iterator_base(other.node) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const sibling_iterator& other) + : iterator_base(other), parent_(other.parent_) + { + } + +template +void tree::sibling_iterator::set_parent_() + { + parent_=0; + if(this->node==0) return; + if(this->node->parent!=0) + parent_=this->node->parent; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator++() + { + if(this->node) + this->node=this->node->next_sibling; + return *this; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator--() + { + if(this->node) this->node=this->node->prev_sibling; + else { + assert(parent_); + this->node=parent_->last_child; + } + return *this; +} + +template +typename tree::sibling_iterator tree::sibling_iterator::operator++(int) + { + sibling_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::sibling_iterator tree::sibling_iterator::operator--(int) + { + sibling_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +typename tree::tree_node *tree::sibling_iterator::range_first() const + { + tree_node *tmp=parent_->first_child; + return tmp; + } + +template +typename tree::tree_node *tree::sibling_iterator::range_last() const + { + return parent_->last_child; + } + +// Leaf iterator + +template +tree::leaf_iterator::leaf_iterator() + : iterator_base(0), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) + : iterator_base(tn), top_node(top) + { + } + +template +tree::leaf_iterator::leaf_iterator(const iterator_base &other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + ++(*this); + } + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator++() + { + assert(this->node!=0); + if(this->node->first_child!=0) { // current node is no longer leaf (children got added) + while(this->node->first_child) + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node != 0 && this->node==top_node) return *this; + } + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator--() + { + assert(this->node!=0); + while (this->node->prev_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node !=0 && this->node==top_node) return *this; + } + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + return *this; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator++(int) + { + leaf_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator--(int) + { + leaf_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +#endif + +// Local variables: +// default-tab-width: 3 +// End: diff -Nru 3depict-0.0.12/src/backend/viscontrol.cpp 3depict-0.0.13/src/backend/viscontrol.cpp --- 3depict-0.0.12/src/backend/viscontrol.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/viscontrol.cpp 2013-04-10 20:41:23.000000000 +0000 @@ -0,0 +1,1890 @@ +/* + * viscontrol.cpp - visualisation-user interface glue code + * 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 . +*/ + +#include "viscontrol.h" + +#include "wxcommon.h" +#include "wxcomponents.h" +#include "gl/scene.h" + +#include "common/stringFuncs.h" +#include "common/translation.h" +#include "common/xmlHelper.h" + + +using std::list; +using std::stack; + +//Window that will be yielded to, when calling safeYield/ needs to be set in viscontrol +wxWindow *yieldWindow=0; + +wxStopWatch* delayTime=0; +//Another global - whether to abort the vis control +// operation, or not +bool *abortVisCtlOp=0; + + + +//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); + //Rate limit the updates + if(delayTime->Time() > YIELD_MS || forceYield) + { + wxSafeYield(yieldWindow); + delayTime->Start(); + } + + ASSERT(abortVisCtlOp); +#ifdef __DEBUG__ + reEntranceCanaryActive=true; +#endif + return !(*abortVisCtlOp); +} + + +VisController::VisController() +{ + targetScene=0; + targetPlots=0; + targetRawGrid=0; + doProgressAbort=false; + ASSERT(!abortVisCtlOp); + abortVisCtlOp=&doProgressAbort; + 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; + delayTime=0; +} + +void VisController::abort() +{ + ASSERT(!doProgressAbort); + doProgressAbort=true; +} + +void VisController::addFilter(Filter *f, bool isBase,size_t parentId) +{ + if(!isBase) + filterTree.addFilter(f,filterMap[parentId]); + else + filterTree.addFilter(f,0); + + //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(); +} + +void VisController::addFilterTree(FilterTree &f, bool isBase,size_t parentId) +{ + ASSERT(!(isBase && parentId==(unsigned int)-1)); + + if(isBase) + filterTree.addFilterTree(f,0); + else + filterTree.addFilterTree(f,filterMap[parentId]); + + //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(); +} + +void VisController::switchoutFilterTree(FilterTree &f) +{ + //Create a clone of the internal tree + f=filterTree; + + //Fix up the internal filterMap to reflect the contents of the new tree + //--- + // + //Build a map from old filter*->new filter * + tree::pre_order_iterator itB; + itB=filterTree.depthBegin(); + std::map filterRemap; + for(tree::pre_order_iterator itA=f.depthBegin(); itA!=f.depthEnd(); ++itA) + { + filterRemap[*itA]=*itB; + ++itB; + } + + //Overwrite the internal map + for(map::iterator it=filterMap.begin();it!=filterMap.end();++it) + it->second=filterRemap[it->second]; + + + //Swap the internal tree with our clone + f.swap(filterTree); +} + +//!Duplicate a branch of the tree to a new position. Do not copy cache, +bool VisController::copyFilter(size_t toCopy, size_t newParent,bool copyToRoot) +{ + bool ret; + if(copyToRoot) + ret=filterTree.copyFilter(filterMap[toCopy],0); + else + + ret=filterTree.copyFilter(filterMap[toCopy],filterMap[newParent]); + + if(ret) + { + //Delete the filtermap, as the current data is not valid anymore + filterMap.clear(); + } + + return ret; +} + + +const Filter* VisController::getFilterById(size_t filterId) const +{ + //If triggering this assertion, check that + //::updateWxTreeCtrl called after calling addFilterTree. + ASSERT(filterMap.size()); + + //Check that the mapping exists + ASSERT(filterMap.find(filterId)!=filterMap.end()); + return filterMap.at(filterId); +} + +size_t VisController::getIdByFilter(const Filter *f) const +{ + for(map::const_iterator it=filterMap.begin();it!=filterMap.end();++it) + { + if(it->second == f) + return it->first; + + } + + ASSERT(false); + return -1; //keep gcc quiet +} + +void VisController::getFiltersByType(std::vector &filters, unsigned int type) const +{ + filterTree.getFiltersByType(filters,type); +} + + +void VisController::removeFilterSubtree(size_t filterId) +{ + //Save current filter state to undo stack + pushUndoStack(); + filterTree.removeSubtree(filterMap[filterId]); + //Delete the filtermap, as the current data is not valid anymore + filterMap.clear(); +} + + +bool VisController::setFilterProperty(size_t filterId, + unsigned int key, const std::string &value, bool &needUpdate) +{ + //Save current filter state to undo stack + //for the case where the property change is good + pushUndoStack(); + bool setOK; + setOK=filterTree.setFilterProperty(filterMap[filterId],key,value,needUpdate); + + if(!setOK) + { + //Didn't work, so we need to discard the undo + //Pop the undo stack, but don't restore it - + // restoring would destroy the cache + popUndoStack(false); + } + + return setOK; +} + +unsigned int VisController::refreshFilterTree(bool doUpdateScene) +{ + ASSERT(!amRefreshing); + + //Analyse the filter tree structure for any errors + //-- + fta.clear(); + fta.analyse(filterTree); + //-- + + doProgressAbort=false; + amRefreshing=true; + delayTime->Start(); + + curProg.reset(); + + list refreshData; + + + //Apply any remaining updates if we have them + if(pendingUpdates) + getFilterUpdates(); + targetScene->clearBindings(); + + //Run the tree refresh system. + unsigned int errCode; + vector *> devices; + vector > consoleMessages; + errCode=filterTree.refreshFilterTree(refreshData,devices, + consoleMessages,curProg,wxYieldCallback); + + + const Filter *lastFilt=0; + for(size_t ui=0;uiAppendText(wxStr(lastFilt->getUserString())); + textConsole->AppendText(wxT("\n------------\n")); + } + textConsole->AppendText(wxStr(consoleMessages[ui].second)); + textConsole->AppendText(wxT("\n")); + } + + if(consoleMessages.size()) + textConsole->AppendText(wxT("\n")); + + + if(errCode) + { + amRefreshing=false; + return errCode; + } + + //strip off the source filter information for + //convenience in this routine + list > outData; + for(list::iterator it=refreshData.begin(); it!=refreshData.end(); ++it) + { + ASSERT(it->second.size()); + outData.push_back(it->second); + } + + + targetScene->clearObjs(); + targetScene->addSelectionDevices(devices); + + if(doUpdateScene) + updateScene(outData); + //Stop timer + delayTime->Pause(); + amRefreshing=false; + + return 0; +} + +unsigned int VisController::refreshFilterTree(list &outData) +{ + vector *> devices; + vector > consoleStrs; + return filterTree.refreshFilterTree(outData,devices, + consoleStrs,curProg,wxYieldCallback); +} + +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); +} + +void VisController::setYieldWindow(wxWindow *newYield) +{ + yieldWindow=newYield; +} + +void VisController::setWxTreeFilterViewPersistence(size_t filterId) +{ + persistentFilters.push_back(filterMap[filterId]); +} + +void VisController::updateWxTreeCtrl(wxTreeCtrl *t, const Filter *visibleFilt) +{ + upWxTreeCtrl(filterTree,t,filterMap,persistentFilters,visibleFilt); +} + +void VisController::updateFilterPropGrid(wxPropertyGrid *g,size_t filterId) const +{ + //The filterID can never be set to zero, + //except for the root item, as set by + //upWxTreeCtrl + ASSERT(filterId); + ASSERT(filterMap.size() == filterTree.size()); + + Filter *targetFilter; + targetFilter=filterMap.at(filterId); + + ASSERT(targetFilter); + + updateFilterPropertyGrid(g,targetFilter); +} + + +bool VisController::setCamProperties(size_t camUniqueID,unsigned int key, const std::string &value) +{ + return targetScene->setCamProperty(camUniqueID,key,value); +} + + + + + +bool VisController::hasUpdates() const +{ + if(pendingUpdates) + return true; + + return filterTree.hasUpdates(); + +} + +void VisController::getFilterUpdates() +{ + vector > bindings; + targetScene->getModifiedBindings(bindings); + + if(bindings.size()) + pushUndoStack(); + + for(unsigned int ui=0;ui::iterator it=filterTree.depthBegin(); + it!=filterTree.depthEnd();++it) + { + if(*it == bindings[ui].first) + { + //We are modifying the contents of + //the filter, this could make a change that + //modifies output so we need to clear + //all subtree caches to force reprocessing + filterTree.clearCache(*it); + + (*it)->setPropFromBinding(bindings[ui].second); +#ifdef DEBUG + haveBind=true; +#endif + break; + } + } + + ASSERT(haveBind); + + } + + //we have retrieved the updates. + pendingUpdates=false; +} + +//public interface to updateScene +unsigned int VisController::doUpdateScene(list > &sceneData, + bool releaseData) +{ + amRefreshing=true; + unsigned int errCode=updateScene(sceneData,releaseData); + amRefreshing=false; + return errCode; + +} +unsigned int VisController::updateScene(list > &sceneData, + bool releaseData) +{ + //Plot wrapper should be set + ASSERT(targetPlots); + //Plot window should be set + ASSERT(plotSelList) + + //Should be called from a viscontrol refresh + ASSERT(amRefreshing); + + //Lock the opengl scene interaction, + // to prevent user interaction (e.g. devices) during callbacks + targetScene->lockInteraction(); + targetPlots->lockInteraction(); + + //Buffer to transfer to scene + vector sceneDrawables; + + //erase the contents of each plot + targetPlots->clear(true); //Clear, but preserve selection information. + + vector > plotLabels; + + //-- Build buffer of new objects to send to scene + + for(list > ::iterator it=sceneData.begin(); + it!=sceneData.end(); ++it) + { + + ASSERT(it->size()); + for(unsigned int ui=0;uisize(); ui++) + { + //Filter must specify whether it is cached or not. Other values + //are inadmissible, but useful to catch uninitialised values + ASSERT((*it)[ui]->cached == 0 || (*it)[ui]->cached == 1); + + switch((*it)[ui]->getStreamType()) + { + case STREAM_TYPE_IONS: + { + //Create a new group for this stream. + // We have to have individual groups + // because of colouring/sizing concerns. + DrawManyPoints *curIonDraw; + curIonDraw=new DrawManyPoints; + + + //Obtain the ion data pointer + const IonStreamData *ionData; + ionData=((const IonStreamData *)((*it)[ui])); + + + curIonDraw->resize(ionData->data.size()); + //Slice out just the coordinate data for the + // ion pointer, run callback immediately + // after, as its a long operation + #pragma omp parallel for shared(curIonDraw,ionData) + for(size_t ui=0;uidata.size();ui++) + curIonDraw->setPoint(ui,ionData->data[ui].getPosRef()); + (*wxYieldCallback)(true); + + //Set the colour from the ionstream data + curIonDraw->setColour(ionData->r, + ionData->g, + ionData->b, + ionData->a); + //set the size from the ionstream data + curIonDraw->setSize(ionData->ionSize); + //Randomly shuffle the ion data before we draw it + curIonDraw->shuffle(); + //Run callback to update as needed, as shuffle is slow. + (*wxYieldCallback)(true); + + //place in special holder for ions, + // as we need to accumulate for display-listing + // later. + sceneDrawables.push_back(curIonDraw); + break; + } + case STREAM_TYPE_PLOT: + { + const PlotStreamData *plotData; + plotData=((PlotStreamData *)((*it)[ui])); + + //The plot should have some data in it. + ASSERT(plotData->getNumBasicObjects()); + //The plot should have a parent filter + ASSERT(plotData->parent); + //The plot should have an index, so we can keep + //filter choices between refreshes (where possible) + ASSERT(plotData->index !=(unsigned int)-1); + //Construct a new plot + unsigned int plotID; + + switch(plotData->plotMode) + { + case PLOT_MODE_1D: + { + //Create a 1D plot + Plot1D *plotNew= new Plot1D; + + plotNew->setData(plotData->xyData); + plotNew->setLogarithmic(plotData->logarithmic); + plotNew->titleAsRawDataLabel=plotData->useDataLabelAsYDescriptor; + + //Construct any regions that the plot may have + for(unsigned int ui=0;uiregions.size();ui++) + { + //add a region to the plot, + //using the region data stored + //in the plot stream + plotNew->addRegion(plotID, + plotData->regionID[ui], + plotData->regions[ui].first, + plotData->regions[ui].second, + plotData->regionR[ui], + plotData->regionG[ui], + plotData->regionB[ui],plotData->regionParent); + } + + plotID=targetPlots->addPlot(plotNew); + break; + } + default: + ASSERT(false); + } + + + //set the appearance of the plot + // ----- + targetPlots->setTraceStyle(plotID,plotData->plotStyle); + targetPlots->setColours(plotID,plotData->r, + plotData->g,plotData->b); + + std::wstring xL,yL,titleW; + std::string x,y,t; + + xL=stlStrToStlWStr(plotData->xLabel); + yL=stlStrToStlWStr(plotData->yLabel); + titleW=stlStrToStlWStr(plotData->dataLabel); + + x=stlWStrToStlStr(xL); + y=stlWStrToStlStr(yL); + t=stlWStrToStlStr(titleW); + + targetPlots->setStrings(plotID,x,y,t); + // ----- + + //set the data origin + targetPlots->setParentData(plotID,plotData->parent, + plotData->index); + + plotLabels.push_back(make_pair(plotID,plotData->dataLabel)); + + break; + } + case STREAM_TYPE_DRAW: + { + DrawStreamData *drawData; + drawData=((DrawStreamData *)((*it)[ui])); + + //Retrieve vector + const std::vector *drawObjs; + drawObjs = &(drawData->drawables); + //Loop through vector, Adding each object to the scene + if(drawData->cached) + { + ASSERT(false); + //FIXME: IMPLEMENT ME + //Create a *copy* for scene. Filter still holds + //originals, and will dispose of the pointers accordingly + //for(unsigned int ui=0;uisize();ui++) + // sceneDrawables.push_back((*drawObjs)[ui]->clone()); + } + else + { + //Place the *pointers* to the drawables in the scene + // list, to avoid copying + for(unsigned int ui=0;uisize();ui++) + sceneDrawables.push_back((*drawObjs)[ui]); + + //Although we do not delete the drawable objects + //themselves, we do delete the container + + //Zero-size the internal vector to + //prevent vector destructor from deleting pointers + //we have transferred ownership of to scene + drawData->drawables.clear(); + } + break; + } + case STREAM_TYPE_RANGE: + //silently drop rangestreams + break; + case STREAM_TYPE_VOXEL: + { + //Technically, we are violating const-ness + VoxelStreamData *vSrc = (VoxelStreamData *)((*it)[ui]); + //Create a new Field3D + Voxels *v = new Voxels; + + //Make a copy if cached; otherwise just steal it. + if(vSrc->cached) + vSrc->data.clone(*v); + else + v->swap(vSrc->data); + + switch(vSrc->representationType) + { + case VOXEL_REPRESENT_POINTCLOUD: + { + DrawField3D *d = new DrawField3D; + d->setField(v); + d->setColourMapID(0); + d->setColourMinMax(); + d->setBoxColours(vSrc->r,vSrc->g,vSrc->b,vSrc->a); + d->setPointSize(vSrc->splatSize); + d->setAlpha(vSrc->a); + d->wantsLight=false; + + sceneDrawables.push_back(d); + break; + } + case VOXEL_REPRESENT_ISOSURF: + { + DrawIsoSurface *d = new DrawIsoSurface; + + d->swapVoxels(v); + d->setColour(vSrc->r,vSrc->g, + vSrc->b,vSrc->a); + d->setScalarThresh(vSrc->isoLevel); + + d->wantsLight=true; + + sceneDrawables.push_back(d); + break; + } + default: + ASSERT(false); + ; + } + + break; + } + } + + //delete drawables as needed + if(!(*it)[ui]->cached && releaseData) + { + delete (*it)[ui]; + (*it)[ui]=0; + } + + //Run the callback to update the window as needed + (*wxYieldCallback)(true); + + } + + } + //--- + + //Construct an OpenGL display list from the dataset + + //Check how many points we have. Too many can cause the display list to crash + size_t totalIonCount=0; + for(unsigned int ui=0;uigetType() == DRAW_TYPE_MANYPOINT) + totalIonCount+=((const DrawManyPoints*)(sceneDrawables[ui]))->getNumPts(); + } + + + //Must lock UI controls, or not run callback from here on in! + //========== + + //Update the plotting UI contols + //----------- + plotSelList->Clear(); // erase wx list + + for(size_t ui=0;uiAppend(wxStr(plotLabels[ui].second),l); + } + plotLabels.clear(); + + //If there is only one spectrum, select it + if(plotSelList->GetCount() == 1 ) + plotSelList->SetSelection(0); + else if( plotSelList->GetCount() > 1) + { + //Otherwise try to use the last visibility information + //to set the selection + targetPlots->bestEffortRestoreVisibility(); + +#if defined(__WIN32__) || defined(__WIN64__) + //Bug under windows. SetSelection(wxNOT_FOUND) does not work for multi-selection list boxes + plotSelList->SetSelection(-1, false); +#else + plotSelList->SetSelection(wxNOT_FOUND); //Clear selection +#endif + for(unsigned int ui=0; uiGetCount();ui++) + { + wxListUint *l; + unsigned int plotID; + + //Retreive the uniqueID + l=(wxListUint*)plotSelList->GetClientObject(ui); + plotID = l->value; + if(targetPlots->isPlotVisible(plotID)) + plotSelList->SetSelection(ui); + } + } + targetPlots->lockInteraction(false); + //----------- + + + + 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) + vector drawIons; + for(size_t ui=0;uigetType() == DRAW_TYPE_MANYPOINT) + drawIons.push_back((DrawManyPoints*)sceneDrawables[ui]); + } + + if(totalIonCount < MAX_NUM_DRAWABLE_POINTS && drawIons.size() >1) + { + //Try to use a display list where we can. + //note that the display list requires a valid bounding box, + //so single point entities, or overlapped points can + //produce an invalid bounding box + DrawDispList *displayList; + displayList = new DrawDispList(); + + bool listStarted=false; + for(unsigned int ui=0;uigetBoundingBox(b); + if(b.isValid()) + { + + if(!listStarted) + { + displayList->startList(false); + listStarted=true; + } + displayList->addDrawable(drawIons[ui]); + delete drawIons[ui]; + } + else + targetScene->addDrawable(drawIons[ui]); + } + + if(listStarted) + { + displayList->endList(); + targetScene->addDrawable(displayList); + } + } + else + { + for(unsigned int ui=0;uiaddDrawable(drawIons[ui]); + } + + for(size_t ui=0;uigetType() != STREAM_TYPE_IONS) + targetScene->addDrawable(sceneDrawables[ui]); + } + + sceneDrawables.clear(); + targetScene->computeSceneLimits(); + targetScene->lockInteraction(false); + //=============== + + + return 0; +} + + + + +unsigned int VisController::addCam(const std::string &camName) +{ + Camera *c=targetScene->cloneActiveCam(); + c->setUserString(camName); + //Store the camera + unsigned int id = targetScene->addCam(c); + targetScene->setActiveCam(0); + return id; +} + +bool VisController::removeCam(unsigned int uniqueID) +{ + targetScene->removeCam(uniqueID); + targetScene->setDefaultCam(); + return true; +} + +bool VisController::setCam(unsigned int uniqueID) +{ + targetScene->setActiveCam(uniqueID); + return true; +} + +void VisController::updateCamPropertyGrid(wxPropertyGrid *g,unsigned int camID) const +{ + + g->clearKeys(); + if(targetScene->isDefaultCam()) + return; + + CameraProperties p; + + targetScene->getCamProperties(camID,p); + + g->setNumGroups(p.data.size()); + //Create the keys for the property grid to do its thing + for(unsigned int ui=0;uiaddKey(p.data[ui][uj].first, ui,p.keys[ui][uj], + p.types[ui][uj],p.data[ui][uj].second,string("")); + } + } + + //Let the property grid layout what it needs to + g->propertyLayout(); +} + +bool VisController::reparentFilter(size_t filter, size_t newParent) +{ + //Save current filter state to undo stack + pushUndoStack(); + + //Try to reparent this filter. It might not work, if, for example + // the new parent is actually a child of the filter we are trying to + // assign the parent to. + if(!filterTree.reparentFilter(filterMap[filter],filterMap[newParent])) + { + //Pop the undo stack, to reverse our + //push, but don't restore it, + // as this would cost us our filter caches + popUndoStack(false); + return false; + } + + 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()) + { + p->setUserString(s); + return true; + } + + return false; +} + +unsigned int VisController::numCams() const +{ + return targetScene->getNumCams(); +} + +void VisController::ensureSceneVisible(unsigned int direction) +{ + targetScene->ensureVisible(direction); +} + +bool VisController::saveState(const char *cpFilename, std::map &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 << "" <" << endl; + f<" << endl; + //write general settings + //--------------- + float backR,backG,backB; + + targetScene->getBackgroundColour(backR,backG,backB); + f << tabs(1) << "" << endl; + + f << tabs(1) << "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) << ""<< 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) << ""<< endl; + } + } + + //--------------- + + + //Write filter tree + //--------------- + if(!filterTree.saveXML(f,fileMapping,writePackage,useRelativePathsForSave)) + return false; + //--------------- + + vector camVec; + + unsigned int active=targetScene->duplicateCameras(camVec); + + //Save all cameras. + f <" << endl; + + //First camera is the "working" camera, which is unnamed + f << tabs(2) << "" << endl; + + for(unsigned int ui=0;uiwriteState(f,STATE_FORMAT_XML,2); + delete camVec[ui]; + } + f <" << endl; + + camVec.clear(); + + if(stashedFilters.size()) + { + f << tabs(1) << "" << endl; + + for(unsigned int ui=0;ui" << endl; + } + + //Save any effects + vector effectVec; + targetScene->getEffects(effectVec); + + if(effectVec.size()) + { + f <" << endl; + for(unsigned int ui=0;uiwriteState(f,STATE_FORMAT_XML,1); + f <" << endl; + + } + + + + //Close XMl tag. + f<< "" << endl; + + //Debug check to ensure we have written a valid xml file + ASSERT(isValidXML(cpFilename)); + + return true; +} + +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(); + + + 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 newCameraVec; + vector newEffectVec; + vector > newStashes; + + std::string stateDir=onlyDir(cpFilename); + unsigned int activeCam; + try + { + std::stack 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 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); + + + 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(); + + //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;uigetType()== 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;uiclearCams(); + + //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;uigetUserString().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); + } + + if(newEffectVec.size()) + { + targetScene->clearEffects(); + for(unsigned int ui=0;uiaddEffect(newEffectVec[ui]); + } + } + + //Perform sanitisation on results + return true; +} + + +void VisController::clear() +{ + filterMap.clear(); + + filterTree.clear(); + + undoFilterStack.clear(); +} + +void VisController::getCamData(std::vector > &camData) const +{ + targetScene->getCameraIDs(camData); +} + +unsigned int VisController::getActiveCamId() const +{ + return targetScene->getActiveCamId(); +} + +unsigned int VisController::exportIonStreams(const std::vector &selectedStreams, + const std::string &outFile, unsigned int format) +{ + + //test file open, and truncate file to zero bytes + ofstream f(outFile.c_str(),ios::trunc); + + if(!f) + return 1; + + f.close(); + + for(unsigned int ui=0; uigetStreamType()) + { + case STREAM_TYPE_IONS: + { + const IonStreamData *ionData; + ionData=((const IonStreamData *)(selectedStreams[ui])); + switch(format) + { + case IONFORMAT_POS: + { + //Append this ion stream to the posfile + appendPos(ionData->data,outFile.c_str()); + + break; + } + default: + ASSERT(false); + break; + } + } + } + } + + return 0; +} + + +void VisController::addStashedToFilters(const Filter *parent, unsigned int stashId) +{ + ASSERT(stashId > &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 > > plotData; + vector > labels; + //grab the data for the currently visible plots + targetPlots->getRawData(plotData,labels); + + + + //Clear the grid + if(targetRawGrid->GetNumberCols()) + targetRawGrid->DeleteCols(0,targetRawGrid->GetNumberCols()); + if(targetRawGrid->GetNumberRows()) + targetRawGrid->DeleteRows(0,targetRawGrid->GetNumberRows()); + + unsigned int curCol=0; + for(unsigned int ui=0;uiAppendCols(plotData[ui].size()); + ASSERT(labels[ui].size() == plotData[ui].size()); + + startCol=curCol; + for(unsigned int uj=0;ujSetColLabelValue(curCol,wxStr(s)); + curCol++; + } + + //set the data + for(unsigned int uj=0;uj targetRawGrid->GetNumberRows()) + targetRawGrid->AppendRows(plotData[ui][uj].size()-targetRawGrid->GetNumberRows()); + + for(unsigned int uk=0;ukSetCellValue(uk,startCol,wxStr(tmpStr)); + } + startCol++; + } + + } +} + +void VisController::setCachePercent(unsigned int newCache) +{ + filterTree.setCachePercent(newCache); +} + + +void VisController::pushUndoStack() +{ + FilterTree newTree; + newTree = filterTree; + if(undoFilterStack.size() > MAX_UNDO_SIZE) + undoFilterStack.pop_front(); + + undoFilterStack.push_back(newTree); + redoFilterStack.clear(); +} + +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(); + + if(restorePopped) + { + //Swap the current filter cache out with the undo stack result + std::swap(filterTree,undoFilterStack.back()); + + //Filter topology has changed. Update + 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()); + + //Pop the redo stack + redoFilterStack.pop_back(); + + //Filter topology has changed. Update + filterTree.initFilterTree(); +} + +void VisController::updateConsole(const std::vector &v, const Filter *f) const +{ + for(unsigned int ui=0; uigetUserString() + string(" : ") + v[ui]; + textConsole->AppendText(wxStr(s)); + textConsole->AppendText(_("\n")); + + } +} + + +bool VisController::getAxisVisible() const +{ + return targetScene->getWorldAxisVisible(); +} + + +void VisController::setStrongRandom(bool strongRand) +{ + Filter::setStrongRandom(strongRand); + + //Invalidate every filter cache. + filterTree.clearCache(0); + +} + + +void VisController::setEffects(bool enable) +{ + targetScene->setEffects(enable); +} + + +bool VisController::hasHazardousContents() const +{ + for(size_t ui=0;uiisPureDataSource(); + +} + +void VisController:: safeDeleteFilterList(std::list &outData, + size_t typeMask, bool maskPrevents) const +{ + filterTree.safeDeleteFilterList(outData,typeMask,maskPrevents); +} +//--------------- + diff -Nru 3depict-0.0.12/src/backend/viscontrol.h 3depict-0.0.13/src/backend/viscontrol.h --- 3depict-0.0.12/src/backend/viscontrol.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/backend/viscontrol.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,423 @@ +/* + * viscontrol.h - Visualisation control header; "glue" between user interface and scene + * 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 . +*/ + +#ifndef VISCONTROL_H +#define VISCONTROL_H + +#include +#include + +class VisController; +class wxGrid; +class wxPropertyGrid; +class wxTreeCtrl; + +#include "../gl/scene.h" + +#include "filtertreeAnalyse.h" +#include "backend/plot.h" + +const unsigned int MAX_UNDO_SIZE=10; + + + + + +//!Visualisation controller +/*! + * Keeps track of what visualisation controls the user has available + * such as cameras, filters and data groups. + * This is essentially responsible for interfacing between program + * data structures and the user interface. + * + * Only one of these should be instantiated at any time (such as due to abort mechanisms). + */ +class VisController +{ + private: + //!Target scene + Scene *targetScene; + //!Target Plot wrapper system + PlotWrapper *targetPlots; + //!Target raw grid + wxGrid *targetRawGrid; + + //!UI element for console output + wxTextCtrl *textConsole; + + //!UI element for selecting plots from a list (for enable/disable) + wxListBox *plotSelList; + + + //--- Data storage ---- + //!Primary data storage for filter tree + FilterTree filterTree; + + //!Analysis results for last filter tree refresh + FilterTreeAnalyse fta; + + //!Undo filter tree stack + std::deque undoFilterStack,redoFilterStack; + + //!Named, stored trees that can be put aside for secondary use + std::vector > stashedFilters; + + //!Unique IDs for stash + UniqueIDHandler stashUniqueIDs; + //-------------------- + + //!True if viscontrol should abort current operation + bool doProgressAbort; + + //!True if viscontrol is in the middle of a refresh operation + bool amRefreshing; + + //!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; + + + void clear(); + + + //!Retreive the updates to the filter tree from the scene + void getFilterUpdates(); + + + + //!Push the current filter tree onto the undo stack + void pushUndoStack(); + + + //!Erase the redo stack + void clearRedoStack(); + + + + //!Update the console strings + void updateConsole(const std::vector &v, const Filter *f) const; + + //!Force an update to the scene. + unsigned int updateScene(std::list > &outputData,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 + std::map filterMap; + + //Filters that should be able to be seen next time we show + // the wxTree control + std::vector persistentFilters; + + //Working directory for filter tree file operations + std::string workingDir; + + public: + VisController(); + ~VisController(); + + //Filter tree access functions + //----------------- + //!Run a refresh of the underlying tree. Returns 0 on success + // iff return value == 0, then scene update has been initiated + unsigned int refreshFilterTree(bool doUpdateScene=true); + + + + //!Force an update to the scene. + unsigned int doUpdateScene(std::list > &outputData, bool releaseData=true); + + //obtain the outputs from the filter tree's refresh. + // The outputs *must* be deleted with safeDeleteFilterList + unsigned int refreshFilterTree( + std::list > > &outputData); + + //Obtain a clone of the active filter tree + void cloneFilterTree(FilterTree &f) const{f=filterTree;}; + + //!Safely delete data generated by refreshFilterTree(...). + //a mask can be used to *prevent* STREAM_TYPE_blah from being deleted. Deleted items are removed from the list. + void safeDeleteFilterList(std::list &outData, + size_t typeMask=0, bool maskPrevents=true) const; + + + //!Add a new filter to the tree. set isbase=false and parentID for not + //setting a parent (ie making filter base) + void addFilter(Filter *f, bool isBase, size_t parentId); + + + //!Add a new subtree to the tree. Note that the tree will be cleared + // as a result of this operation. Control of all pointers will be handled internally. + // If you wish to use ::getFilterById you *must* rebuild the tree control with + // ::updateWxTreeCtrl + void addFilterTree(FilterTree &f,bool isBase=true, + size_t parentId=(unsigned int)-1); + + //!Grab the filter tree from the internal one, and swap the + // internal with a cloned copy. Can be used eg, to steal the cache + // Note that the passed filter tree will be destroyed. + // -> This implies the tree comes *OUT* of viscontrol, + // and a tree cannot be inserted in via this function + void switchoutFilterTree(FilterTree &f); + + //Perform a swap operation on the filter tree. + // - *must* have same topology, or you must call updateWxTreeCtrl + // - can be used to *insert* a tree into this function + void swapFilterTree(FilterTree &f) { f.swap(filterTree);} + + //!Duplicate a branch of the tree to a new position. Do not copy cache, + bool copyFilter(size_t toCopy, size_t newParent,bool copyToRoot=false) ; + + //TODO: Deprecate me - filter information should not be leaking like this! + //Get the ID of the filter from its actual pointer + size_t getIdByFilter(const Filter* f) const; + + const Filter* getFilterById(size_t filterId) const; + + //!Return all of a given type of filter from the filter tree + void getFiltersByType(std::vector &filters, unsigned int type) const; + + //!Returns true if the tree contains any state overrides (external entity referrals) + bool hasStateOverrides() const + {return filterTree.hasStateOverrides();}; + + //!Make the filters safe for the end user, assuming the filter tree could have had + // its data initialised from anywhere + void stripHazardousContents() { filterTree.stripHazardousContents();}; + + //!Get the analysis results for the last refresh + void getAnalysisResults(vector &res) const { fta.getAnalysisResults(res);} + + //!Return the number of filters currently in the main tree + size_t numFilters() const { return filterTree.size();}; + + //!Clear the cache for the filters + void purgeFilterCache() { filterTree.purgeCache();}; + + //!Delete a filter and all its children + void removeFilterSubtree(size_t filterId); + + //Move a filter from one part of the tree to another + bool reparentFilter(size_t filterID, size_t newParentID); + + //!Set the properties using a key-value result (as obtained from updatewxPropertyGrid) + /* + * The return code tells whether to reject or accept the change. + * need update tells us if the change to the filter resulted in a change to the scene + */ + bool setFilterProperty(size_t filterId,unsigned int key, + const std::string &value, bool &needUpdate); + + //!Set the filter's string + bool setFilterString(size_t id, const std::string &s); + + //!Clear all caches + void clearCache(); + + //!Clear all caches + void clearCacheByType(unsigned int type) { filterTree.clearCacheByType(type);}; + + //----------------- + + + //!Call to get viscontrol to abort current operation. Call once per abort. + void abort() ; + + //!Call to set window to be partially excluded (wx dependant) from blocking during scene updates + void setYieldWindow(wxWindow *win); + + //!Set the text console + void setConsole(wxTextCtrl *t) { textConsole = t;} + //!Set the backend scene + void setScene(Scene *theScene); + //!Set the backend plot + void setPlotWrapper(PlotWrapper *thePlots){targetPlots=thePlots;}; + //!Set the listbox for plot selection + void setPlotList(wxListBox *box){plotSelList=box;}; + + + //!Set the backend grid control for raw data + void setRawGrid(wxGrid *theRawGrid){targetRawGrid=theRawGrid;}; + + + //!Write out the filters into a wxtreecontrol. + // optional argument is the fitler to keep visible in the control + void updateWxTreeCtrl(wxTreeCtrl *t,const Filter *f=0); + //!Update a wxtGrid with the properties for a given filter + void updateFilterPropGrid(wxPropertyGrid *g,size_t filterId) const; + + + + + //!Set the camera to use in the scene + bool setCam(unsigned int uniqueID) ; + + //!Remove a camera from the scene + bool removeCam(unsigned int uniqueID); + + //!Add a new camera to the scene + 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; + + //!Return the number of cameras + unsigned int numCams() const ; + + //!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, + unsigned int key, const std::string &value); + + + //!Ensure visible + void ensureSceneVisible(unsigned int direction); + + + + //!Return the current working directory for when loading/saving state file contents + std::string getWorkDir() const { return workingDir;}; + + //!Set current working dir used when saving state files + void setWorkDir(const std::string &wd) { workingDir=wd;}; + + + //!Save the viscontrol state: writes an XML file containing the viscontrol state + bool saveState(const char *filename, std::map &fileMapping, + bool writePackage=false) 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; + + //!Load the viscontrol state, optionally merging this tree with the currently loaded tree. Also, as an option, we can bypass updating any UI data, for debug purposes + 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;}; + + //!Set whether to use relative paths when saving + void setUseRelPaths(bool useRelPaths){ useRelativePathsForSave=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 > &camData) const; + + //!Get the active camera ID + unsigned int getActiveCamId() const; + + //!export given filterstream data pointers + static unsigned int exportIonStreams(const std::vector &selected, + const std::string &outFile, unsigned int format=IONFORMAT_POS); + + //!Returns true if the filter is in the midst of a refresh + bool isRefreshing() const {return amRefreshing; } + + //!Inform viscontrol that it has new updates to filters from external sources (eg bindings) + void setUpdates() { pendingUpdates=true;}; + + //!Returns true if the scene has updates that need to be processed + bool hasUpdates() const; + + + //"Stash" operations + // - The stashes are secondary trees that are not part of the update + // but can be stored for reference (eg to recall common tree sequences) + //---- + //!Create a new stash. Returns ID for stash + unsigned int stashFilters(unsigned int filterID, const char *stashName); + + //!Add a stash as a subtree for the specified parent filter + void addStashedToFilters(const Filter *parentFilter, unsigned int stashID); + + //!Delete a stash using its uniqueID + void deleteStash(unsigned int stashID); + + //!Retreive the stash filters + void getStashes(std::vector > &stashes) const; + + //!Retreive a given stash tree by ID + void getStashTree(unsigned int stashId, FilterTree &) const; + + //!Get the number of stashes + unsigned int getNumStashes() const { return stashedFilters.size();} + + //---- + + void updateRawGrid() const; + + //!Set the percentage of ram to use for cache. 0 to disable + void setCachePercent(unsigned int percent); + + + //!restore top filter tree from undo stack + void popUndoStack(bool restorePopped=true); + + //!restore top filter tree from redo stack + void popRedoStack(); + + //!Get the size of the undo stack + unsigned int getUndoSize() const { return undoFilterStack.size();}; + //!Get the size of the redo stack + unsigned int getRedoSize() const { return redoFilterStack.size();}; + + //!Get the current progress + ProgressData getProgress() const { return curProg;} + + //!reset the progress data + void resetProgress() { curProg.reset();}; + + //!Return the scene's world axis visibility + bool getAxisVisible() const; + + //!Set whether filter should use strong or weak randomisation + void setStrongRandom(bool strongRand); + + //!Set whether to use effects or not + void setEffects(bool enable); + + + //!return true if the primary tree contains hazardous filters + bool hasHazardousContents() const ; + + //!Ask that next time we build the tree, this filter is kept visible/selected. + // may be used repeatedly to make more items visible, + // prior to calling updateWxTreeCtrl. + // filterId must exist during call. + void setWxTreeFilterViewPersistence(size_t filterId); + + //Erase the filters that will persist in the view + void clearTreeFilterViewPersistence() { persistentFilters.clear();} + + //!Ask if a given filter is a pure data source + bool filterIsPureDataSource(size_t filterId) const ; + +#ifdef DEBUG + //Check that the tree conrol is synced up to the filter map correctly + void checkTree(wxTreeCtrl *t); +#endif +}; + + +#endif diff -Nru 3depict-0.0.12/src/basics.cpp 3depict-0.0.13/src/basics.cpp --- 3depict-0.0.12/src/basics.cpp 2012-11-18 15:40:49.000000000 +0000 +++ 3depict-0.0.13/src/basics.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1642 +0,0 @@ -/* - * basics.cpp - basic functions header - * Copyright (C) 2012, 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 . -*/ - -#include "basics.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "translation.h" - -#ifdef __APPLE__ - #include - #include - #include - #include -#elif defined __linux__ - //Needed for getting ram total usage under linux - #include -#endif - -using std::string; -using std::vector; -using std::list; - - -//Name of the DTD file for state loading -const char *DTD_NAME="threeDepict-state.dtd"; -//Program name -const char *PROGRAM_NAME = "3Depict"; -//Program version -const char *PROGRAM_VERSION = "0.0.12"; -//Path to font for Default FTGL font -const char *FONT_FILE= "FreeSans.ttf"; - -const char *TEXT_LOAD_ERR_STRINGS[] = { "", - NTRANS("Error opening file"), - NTRANS("Error whilst reading file contents"), - NTRANS("Error interpreting field in file"), - NTRANS("Inconsistent number of columns found") - }; - -//default font to use. -std::string defaultFontFile; - -std::string getMaxVerStr(const std::vector &verStrings) -{ - std::vector > > verNum; - std::vector thisVer; - - - //break string up into numeric components - for(unsigned int ui=0;ui strVerNum; - strVerNum.clear(); - - // period or hyphen are valid version number separators - splitStrsRef(verStrings[ui].c_str(),".-",strVerNum); - - //Check to see if we can interpret the values - for(unsigned int uj=0;uj 1) - { - unsigned int thisMax; - thisMax=0; - - for(unsigned int ui=0;ui=minB ) - || (minA<=maxB && maxA >=maxB) ) - return true; - - // B- A- B+ - // B- A+ B+ - if(( minB <= minA && maxB >=minA ) - || (minB<=maxA && maxB >=maxA) ) - return true; - - return false; - -} - - -bool dummyCallback(bool) -{ - return true; -} - -std::string onlyFilename( const std::string& path) -{ -#if defined(_WIN32) || defined(_WIN64) - //windows uses "\" as path sep, just to be different - return path.substr( path.find_last_of( '\\' ) +1 ); -#else - //The entire world, including the interwebs, uses "/" as the path sep. - return path.substr( path.find_last_of( '/' ) +1 ); -#endif -} - -std::string onlyDir( const std::string& path) -{ -#if defined(_WIN32) || defined(_WIN64) - //windows uses "\" as path sep, just to be different - return path.substr(0, path.find_last_of( '\\' ) +1 ); -#else - //The entire world, including the interwebs, uses "/" as the path sep. - return path.substr(0, path.find_last_of( '/' ) +1 ); -#endif -} - -void setDefaultFontFile(const std::string &font) -{ - defaultFontFile=font; -} - -std::string getDefaultFontFile() -{ - return defaultFontFile; -} - -void nullifyMarker(char *buffer, char marker) -{ - while(*(buffer)) - { - if(*buffer == marker) - { - *buffer='\0'; - break; - } - buffer++; - } -} - -bool parsePointStr(const std::string &str,Point3D &pt) -{ - //Needs to be at minimum #,#,# - if(str.size()< 5) - return false; - - string tmpStr; - tmpStr=stripWhite(str); - - - //Two strings must be in sync - std::string allowableStartChars, allowableEndChars; - allowableStartChars="([{<'"; - allowableEndChars=")]}>'"; - - size_t startPos,endPos; - startPos=allowableStartChars.find(tmpStr[0]); - endPos=allowableEndChars.find(tmpStr[tmpStr.size()-1]); - - //Strip the start/end chars - if(startPos !=std::string::npos && endPos != std::string::npos) - tmpStr=tmpStr.substr(1,tmpStr.size()-1); - else if (startPos !=endPos) - return false; //we had one start bracket, but not the other... - - //First try splitting with non-whitespace separators, - // there should be exactly 3 components - vector components; - const char *NONWHITE_SEPARATOR=",;|_"; - splitStrsRef(tmpStr.c_str(),NONWHITE_SEPARATOR, - components); - if(components.size()!=3) - return false; - components.clear(); - - //Now try splitting with whitespace components, dropping empty - // strings. As we have already cheked the non-whitespace components - // additional components muts be whitespace only, which is fine. - - const char *ALLOWABLE_SEPARATORS=",; \t|_"; - - splitStrsRef(tmpStr.c_str(),ALLOWABLE_SEPARATORS, - components); - for(size_t ui=0;ui::iterator rmIt; - rmIt=std::remove(components.begin(),components.end(),string("")); - components.erase(rmIt,components.end()); - - if(components.size()!=3) - return false; - - float p[3]; - for(size_t ui=0;ui<3;ui++) - { - if(stream_cast(p[ui],components[ui])) - return false; - } - - - pt.setValueArr(p); - - return true; -} - -void ucharToHexStr(unsigned char c, std::string &s) -{ - s=" "; - char h1,h2; - - h1 = c/16; - h2 = c%16; - - if(h1 < 10) - { - s[0]=(h1+'0'); - } - else - s[0]=((h1-10)+'a'); - - if(h2 < 10) - { - s[1]=(h2+'0'); - } - else - s[1]=((h2-10)+'a'); - -} - -void hexStrToUChar(const std::string &s, unsigned char &c) -{ - ASSERT(s.size() ==2); - - ASSERT((s[0] >= '0' && s[0] <= '9') || - (s[0] >= 'a' && s[0] <= 'f')); - ASSERT((s[1] >= '0' && s[1] <= '9') || - (s[1] >= 'a' && s[1] <= 'f')); - - int high,low; - if(s[0] <= '9' && s[0] >='0') - high = s[0]-(int)'0'; - else - high = s[0] -(int)'a' + 10; - - if(s[1] <= '9' && s[1] >='0') - low = s[1]-(int)'0'; - else - low = s[1] -(int)'a' + 10; - - c = 16*high + low; -} - -std::string convertFileStringToCanonical(const std::string &s) -{ - //We call unix the "canonical" format. - //otherwise we substitute "\"s for "/"s -#if (__WIN32) || (__WIN64) - string r; - for(unsigned int ui=0;ui > comboString, - unsigned int curChoice) -{ - ASSERT(curChoice < comboString.size()) - - string s,sTmp; - stream_cast(sTmp,curChoice); - s=sTmp + string(":"); - for(unsigned int ui=0;ui choices; - splitStrsRef(s.c_str(),',',choices); - - ASSERT(activeChoice < choices.size()); - tmpStr = choices[activeChoice]; - - return tmpStr.substr(tmpStr.find("|")+1,tmpStr.size()-1); -} - -void choiceStringToVector(const std::string &choiceString, - std::vector &choices, unsigned int &selected) -{ - ASSERT(isMaybeChoiceString(choiceString)); - - //Convert ID1|string 1, .... IDN|string n to vectors, - // stripping off the ID value - size_t colonPos; - colonPos = choiceString.find(":"); - - std::string s; - s=choiceString.substr(colonPos,choiceString.size()-colonPos); - splitStrsRef(s.c_str(),',',choices); - - for(size_t ui=0;ui &sVec) -{ - //Create a truncated vector and reserve mem. - std::vector tVec; - tVec.reserve(sVec.size()); - std::string s; - for(unsigned int ui=0;ui &v ) -{ - const char *thisMark, *lastMark; - string str; - v.clear(); - - //check for null string - if(!*cpStr) - return; - thisMark=cpStr; - lastMark=cpStr; - while(*thisMark) - { - if(*thisMark==delim) - { - str.assign(lastMark,thisMark-lastMark); - v.push_back(str); - - thisMark++; - lastMark=thisMark; - } - else - thisMark++; - } - - if(thisMark!=lastMark) - { - str.assign(lastMark,thisMark-lastMark); - v.push_back(str); - } - -} - -//Split strings around any of a string of delimiters -void splitStrsRef(const char *cpStr, const char *delim,std::vector &v ) -{ - const char *thisMark, *lastMark; - string str; - v.clear(); - - //check for null string - if(!(*cpStr)) - return; - thisMark=cpStr; - lastMark=cpStr; - while(*thisMark) - { - //Loop over possible delmiters to determine if thiis char is a delimeter - bool isDelim; - const char *tmp; - tmp=delim; - isDelim=false; - while(*tmp) - { - if(*thisMark==*tmp) - { - isDelim=true; - break; - } - tmp++; - } - - if(isDelim) - { - str.assign(lastMark,thisMark-lastMark); - v.push_back(str); - - thisMark++; - lastMark=thisMark; - } - else - thisMark++; - } - - if(thisMark!=lastMark) - { - str.assign(lastMark,thisMark-lastMark); - v.push_back(str); - } - -} - -//Compute the number of ticks require to achieve the -void tickSpacingsFromInterspace(float start, float end, - float interSpacing, std::vector &spacings) -{ - ASSERT(interSpacing > sqrt(std::numeric_limits::epsilon())); - unsigned int nTicks; - - if(end < start) - std::swap(end,start); - - nTicks=(unsigned int)((end-start)/interSpacing); - if(!nTicks) - { - ASSERT(!spacings.size()); - return; - } - - spacings.resize(nTicks); - for(unsigned int ui=0;ui &spacings) -{ - if(!nTicks) - { - ASSERT(!spacings.size()); - return; - } - - spacings.resize(nTicks+1); - - float delta; - delta= (end-start)/nTicks; - for(unsigned int ui=0;ui=2*TIMESTOPS[ui]) - { -#ifdef DEBUG - std::string s=(PLURAL_FUZZY_STRING[ui]); - ASSERT(s.size()); -#endif - return TRANS(PLURAL_FUZZY_STRING[ui]); - } - - //stop decending - if ( delta>=TIMESTOPS[ui]) - return TRANS(SINGLE_FUZZY_STRING[ui]); - } - - return TRANS("moments ago"); -} - - -void BoundCube::setBounds(const std::vector &points) -{ - - setInverseLimits(); - for(unsigned int ui=0; ui bounds[uj][1]) - { - { - bounds[uj][1] = points[ui].getValue(uj); - valid[uj][1]=true; - } - } - } - } - -#ifdef DEBUG - for(unsigned int ui=0; ui::max(); - bounds[1][0] = std::numeric_limits::max(); - bounds[2][0] = std::numeric_limits::max(); - - bounds[0][1] = -std::numeric_limits::max(); - bounds[1][1] = -std::numeric_limits::max(); - bounds[2][1] = -std::numeric_limits::max(); - - valid[0][0] =false; - valid[1][0] =false; - valid[2][0] =false; - - valid[0][1] =false; - valid[1][1] =false; - valid[2][1] =false; -} -bool BoundCube::isValid() const -{ - for(unsigned int ui=0;ui<3; ui++) - { - if(!valid[ui][0] || !valid[ui][1]) - return false; - } - - return true; -} - -bool BoundCube::isFlat() const -{ - //Test the limits being inverted or equated - for(unsigned int ui=0;ui<3; ui++) - { - if(fabs(bounds[ui][0] - bounds[ui][1]) < std::numeric_limits::epsilon()) - return true; - } - - return false; -} - -bool BoundCube::isNumericallyBig() const -{ - const float TOO_BIG=sqrt(std::numeric_limits::max()); - for(unsigned int ui=0;ui<2; ui++) - { - for(unsigned int uj=0;uj<3; uj++) - { - if(TOO_BIG < fabs(bounds[uj][ui])) - return true; - } - } - return false; -} - -void BoundCube::expand(const BoundCube &b) -{ - //Check both lower and upper limit. - //Moving to other cubes value as needed - - if(!b.isValid()) - return; - - for(unsigned int ui=0; ui<3; ui++) - { - if(b.bounds[ui][0] < bounds[ui][0]) - { - bounds[ui][0] = b.bounds[ui][0]; - valid[ui][0] = true; - } - - if(b.bounds[ui][1] > bounds[ui][1]) - { - bounds[ui][1] = b.bounds[ui][1]; - valid[ui][1] = true; - } - } -} - -void BoundCube::expand(const Point3D &p) -{ - //If self not valid, ensure that it will be after this run - for(unsigned int ui=0; ui<3; ui++) - { - //Check lower bound is lower to new pt - if(bounds[ui][0] > p[ui]) - bounds[ui][0] = p[ui]; - - //Check upper bound is upper to new pt - if(bounds[ui][1] < p[ui]) - bounds[ui][1] = p[ui]; - } -} - -void BoundCube::expand(float f) -{ - //If self not valid, ensure that it will be after this run - for(unsigned int ui=0; ui<3; ui++) - { - //Check lower bound is lower to new pt - bounds[ui][0]-=f; - - //Check upper bound is upper to new pt - bounds[ui][1]+=f; - } -} - -void BoundCube::setBounds(const Point3D *p, unsigned int n) -{ - bounds[0][0] = std::numeric_limits::max(); - bounds[1][0] = std::numeric_limits::max(); - bounds[2][0] = std::numeric_limits::max(); - - bounds[0][1] = -std::numeric_limits::max(); - bounds[1][1] = -std::numeric_limits::max(); - bounds[2][1] = -std::numeric_limits::max(); - - for(unsigned int ui=0;ui p[ui][uj]) - { - bounds[uj][0] = p[ui][uj]; - valid[uj][0] = true; - } - - - if(bounds[uj][1] < p[ui][uj]) - { - bounds[uj][1] = p[ui][uj]; - valid[uj][1] = true; - } - } - } -} - -void BoundCube::setBounds( const Point3D &p1, const Point3D &p2) -{ - for(unsigned int ui=0; ui<3; ui++) - { - bounds[ui][0]=std::min(p1[ui],p2[ui]); - bounds[ui][1]=std::max(p1[ui],p2[ui]); - valid[ui][0]= true; - valid[ui][1]= true; - } - -} -void BoundCube::getBounds(Point3D &low, Point3D &high) const -{ - for(unsigned int ui=0; ui<3; ui++) - { - ASSERT(valid[ui][0] && valid[ui][1]); - low.setValue(ui,bounds[ui][0]); - high.setValue(ui,bounds[ui][1]); - } -} - -float BoundCube::getLargestDim() const -{ - float f; - f=getSize(0); - f=std::max(getSize(1),f); - return std::max(getSize(2),f); -} - -bool BoundCube::containsPt(const Point3D &p) const -{ - for(unsigned int ui=0; ui<3; ui++) - { - ASSERT(valid[ui][0] && valid[ui][1]); - if(p.getValue(ui) < bounds[ui][0] || p.getValue(ui) > bounds[ui][1]) - return false; - } - return true; -} - -float BoundCube::getSize(unsigned int dim) const -{ - ASSERT(dim < 3); -#ifdef DEBUG - for(unsigned int ui=0;ui<3; ui++) - { - ASSERT(valid[0][1] && valid [0][0]); - } -#endif - return fabs(bounds[dim][1] - bounds[dim][0]); -} - -//checks intersection with sphere [centre,centre+radius) -bool BoundCube::intersects(const Point3D &pt, float sqrRad) -{ - Point3D nearPt; - - //Find the closest point on the cube to the sphere - for(unsigned int ui=0;ui<3;ui++) - { - if(pt.getValue(ui) <= bounds[ui][0]) - { - nearPt.setValue(ui,bounds[ui][0]); - continue; - } - - if(pt.getValue(ui) >=bounds[ui][1]) - { - nearPt.setValue(ui,bounds[ui][1]); - continue; - } - - nearPt.setValue(ui,pt[ui]); - } - - //now test the distance from nrPt to pt - //Note that the touching case is considered to be an intersection - return (nearPt.sqrDist(pt) <=sqrRad); -} - -Point3D BoundCube::getCentroid() const -{ -#ifdef DEBUG - for(unsigned int ui=0;ui<3; ui++) - { - ASSERT(valid[ui][1] && valid [ui][0]); - } -#endif - return Point3D(bounds[0][1] + bounds[0][0], - bounds[1][1] + bounds[1][0], - bounds[2][1] + bounds[2][0])/2.0f; -} - -float BoundCube::getMaxDistanceToBox(const Point3D &queryPt) const -{ -#ifdef DEBUG - for(unsigned int ui=0;ui<3; ui++) - { - ASSERT(valid[ui][1] && valid [ui][0]); - } -#endif - - float maxDistSqr=0.0f; - - //Could probably be a bit more compact. - - - //Set lower and upper corners on the bounding rectangle - Point3D p[2]; - p[0] = Point3D(bounds[0][0],bounds[1][0],bounds[2][0]); - p[1] = Point3D(bounds[0][1],bounds[1][1],bounds[2][1]); - - //Count binary-wise selecting upper and lower limits, to enumerate all 8 verticies. - for(unsigned int ui=0;ui<9; ui++) - { - maxDistSqr=std::max(maxDistSqr, - queryPt.sqrDist(Point3D(p[ui&1][0],p[(ui&2) >> 1][1],p[(ui&4) >> 2][2]))); - } - - return sqrtf(maxDistSqr); -} - -bool BoundCube::containedInSphere(const Point3D &queryPt,float sqrDist) const -{ -#ifdef DEBUG - for(unsigned int ui=0;ui<3; ui++) - { - ASSERT(valid[ui][1] && valid [ui][0]); - } -#endif - - - //Could probably be a bit more compact. - - - //Set lower and upper corners on the bounding rectangle - Point3D p[2]; - p[0].setValue(bounds[0][0],bounds[1][0],bounds[2][0]); - p[1].setValue(bounds[0][1],bounds[1][1],bounds[2][1]); - - //Count binary-wise selecting upper and lower limits, to enumerate all 8 verticies. - for(unsigned int ui=0;ui<9; ui++) - { - if(queryPt.sqrDist(Point3D(p[ui&1][0],p[(ui&2) >> 1][1],p[(ui&4) >> 2][2])) > sqrDist) - return false; - } - - return true; -} - -const BoundCube &BoundCube::operator=(const BoundCube &b) -{ - for(unsigned int ui=0;ui<3; ui++) - { - for(unsigned int uj=0;uj<2; uj++) - { - valid[ui][uj] = b.valid[ui][uj]; - bounds[ui][uj] = b.bounds[ui][uj]; - - } - } - - return *this; -} - -std::ostream &operator<<(std::ostream &stream, const BoundCube& b) -{ - stream << "Bounds :Low ("; - stream << b.bounds[0][0] << ","; - stream << b.bounds[1][0] << ","; - stream << b.bounds[2][0] << ") , High ("; - - stream << b.bounds[0][1] << ","; - stream << b.bounds[1][1] << ","; - stream << b.bounds[2][1] << ")" << std::endl; - - - stream << "Bounds Valid: Low ("; - stream << b.valid[0][0] << ","; - stream << b.valid[1][0] << ","; - stream << b.valid[2][0] << ") , High ("; - - stream << b.valid[0][1] << ","; - stream << b.valid[1][1] << ","; - stream << b.valid[2][1] << ")" << std::endl; - - return stream; -} - -bool getFilesize(const char *fname, size_t &size) -{ - std::ifstream f(fname,std::ios::binary); - - if(!f) - return false; - - f.seekg(0,std::ios::end); - - size = f.tellg(); - - return true; -} - -void UniqueIDHandler::clear() -{ - idList.clear(); -} - -unsigned int UniqueIDHandler::getPos(unsigned int id) const -{ - - for(list >::const_iterator it=idList.begin(); - it!=idList.end(); ++it) - { - if(id == it->second) - return it->first; - } - ASSERT(false); - return 0; -} - -void UniqueIDHandler::killByPos(unsigned int pos) -{ - for(list >::iterator it=idList.begin(); - it!=idList.end(); ++it) - { - if(pos == it->first) - { - idList.erase(it); - break; - } - } - - //Decreement the items, which were further along, in order to maintin the mapping - for(list >::iterator it=idList.begin(); - it!=idList.end(); ++it) - { - if( it->first > pos) - it->first--; - } -} - -unsigned int UniqueIDHandler::getId(unsigned int pos) const -{ - for(list >::const_iterator it=idList.begin(); - it!=idList.end(); ++it) - { - if(pos == it->first) - return it->second; - } - - ASSERT(false); - return 0; -} - -unsigned int UniqueIDHandler::genId(unsigned int pos) -{ - - //Look for each element number as a unique value in turn - //This is guaranteed to return by the pigeonhole principle (we are testing - //a larget set (note <=)). - for(unsigned int ui=0;ui<=idList.size(); ui++) - { - bool idTaken; - idTaken=false; - for(list >::iterator it=idList.begin(); - it!=idList.end(); ++it) - { - if(ui == it->second) - { - idTaken=true; - break; - } - } - - if(!idTaken) - { - idList.push_back(std::make_pair(pos,ui)); - return ui; - } - } - - ASSERT(false); - return 0; -} - -void UniqueIDHandler::getIds(std::vector &idVec) const -{ - //most wordy way of saying "spin through list" ever. - for(list >::const_iterator it=idList.begin(); - it!=idList.end(); ++it) - idVec.push_back(it->second); -} - - - -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - #include - //Windows.h is a nasty name clashing horrible thing. - //Put it last to avoid clashing with std:: stuff (eg max & min) - -#endif - -// Total ram in MB -int getTotalRAM() -{ -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - int ret; - MEMORYSTATUS MemStat; - - // Zero structure - memset(&MemStat, 0, sizeof(MemStat)); - - // Get RAM snapshot - ::GlobalMemoryStatus(&MemStat); - ret= MemStat.dwTotalPhys / (1024*1024); - return ret; -#elif __APPLE__ || __FreeBSD__ - - int ret; - uint64_t mem; - size_t len = sizeof(mem); - - sysctlbyname("hw.physmem", &mem, &len, NULL, 0); - - ret = (int)(mem/(1024*1024)); - return ret; -#elif __linux__ - struct sysinfo sysInf; - sysinfo(&sysInf); - return ((size_t)(sysInf.totalram)*(size_t)(sysInf.mem_unit)/(1024*1024)); -#else - #error Unknown platform, no getTotalRAM function defined. -#endif -} - -size_t getAvailRAM() -{ -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) - int ret ; - MEMORYSTATUS MemStat; - // Zero structure - memset(&MemStat, 0, sizeof(MemStat)); - - // Get RAM snapshot - ::GlobalMemoryStatus(&MemStat); - ret= MemStat.dwAvailPhys / (1024*1024); - return ret; - -#elif __APPLE__ || __FreeBSD__ - int ret ; - uint64_t memsize; - - size_t pagesize; - mach_port_t sls_port = mach_host_self(); - mach_msg_type_number_t vmCount = HOST_VM_INFO_COUNT; - vm_statistics_data_t vm; - kern_return_t error; - - error = host_statistics(sls_port , HOST_VM_INFO , (host_info_t) &vm, &vmCount); - pagesize = (unsigned long)sysconf(_SC_PAGESIZE); - memsize = (vm.free_count + vm.inactive_count) * pagesize;//(vm.wire_count + vm.active_count + vm.inactive_count + vm.free_count + vm.zero_fill_count ) * pagesize; - ret = (size_t)(memsize/(1024*1024)); - return ret; -#elif __linux__ - struct sysinfo sysInf; - sysinfo(&sysInf); - - return ((size_t)(sysInf.freeram + sysInf.bufferram)*(size_t)(sysInf.mem_unit)/(1024*1024)); -#else - #error Unknown platform, no getAvailRAM function defined. -#endif -} - -bool strhas(const char *cpTest, const char *cpPossible) -{ - const char *search; - while(*cpTest) - { - search=cpPossible; - while(*search) - { - if(*search == *cpTest) - return true; - search++; - } - cpTest++; - } - - return false; -} - -//A routine for loading numeric data from a text file -unsigned int loadTextData(const char *cpFilename, vector > &dataVec,vector &headerVec, const char *delim) -{ - const unsigned int BUFFER_SIZE=4096; - char inBuffer[BUFFER_SIZE]; - - unsigned int num_fields=0; - - dataVec.clear(); - //Open a file in text mode - std::ifstream CFile(cpFilename); - - if(!CFile) - return ERR_FILE_OPEN; - - //Drop the headers, if any - string str; - vector strVec; - bool atHeader=true; - - vector prevStrs; - while(!CFile.eof() && atHeader) - { - //Grab a line from the file - CFile.getline(inBuffer,BUFFER_SIZE); - - if(!CFile.good()) - return ERR_FILE_FORMAT; - - prevStrs=strVec; - //Split the strings around the tab char - splitStrsRef(inBuffer,delim,strVec); - - if(!strhas(inBuffer,"0123456789")) - continue; - - - //Skip blank lines or lines that are only spaces - if(strVec.empty() || - (strVec.size() == 1 && strVec[0] == "") ) - continue; - - num_fields = strVec.size(); - dataVec.resize(num_fields); - //Check to see if we are in the header - if(atHeader) - { - //If we have the right number of fields - //we might be not in the header anymore - if(num_fields >= 1 && strVec[0].size()) - { - float f; - //Assume we are not reading the header - atHeader=false; - - vector values; - //Confirm by checking all values - for(unsigned int ui=0; ui> f; - if(ss.fail()) - return ERR_FILE_FORMAT; - dataVec[ui].push_back(f); - - } - //========= - - } - //Grab a line from the file - CFile.getline(inBuffer,BUFFER_SIZE); - - if(!CFile.good() && !CFile.eof()) - return ERR_FILE_FORMAT; - } - - return 0; -} - -unsigned int loadTextStringData(const char *cpFilename, vector > &dataVec,const char *delim) -{ - const unsigned int BUFFER_SIZE=4096; - - dataVec.clear(); - //Open a file in text mode - std::ifstream CFile(cpFilename); - - if(!CFile) - return ERR_FILE_OPEN; - - char *inBuffer= new char[BUFFER_SIZE]; - //Grab a line from the file - CFile.getline(inBuffer,BUFFER_SIZE); - while(!CFile.eof()) - { - vector strVec; - strVec.clear(); - - //Split the strings around the tab char - splitStrsRef(inBuffer,delim,strVec); - stripZeroEntries(strVec); - - //Check the number of fields - //========= - if(strVec.size()) - dataVec.push_back(strVec); - //========= - - //Grab a line from the file - CFile.getline(inBuffer,BUFFER_SIZE); - - if(!CFile.good() && !CFile.eof()) - return ERR_FILE_FORMAT; - } - - return 0; -} - -#ifdef DEBUG -bool isValidXML(const char *filename) -{ - //Debug check to ensure we have written a valid xml file - std::string command; - unsigned int result; - -//Windows doesn't really have a /dev/null device, rather it has a reserved file name "NUL" or "nul" -//http://technet.microsoft.com/en-gb/library/cc961816.aspx -#if defined(WIN32) || defined(WIN64) - command = std::string("xmllint --version > NUL 2> NUL"); -#else - command = std::string("xmllint --version >/dev/null 2>/dev/null"); -#endif - result=system(command.c_str()); - if(!result) - { - //Windows' shell handles escapes differently, workaround - #if defined(WIN32) || defined(WIN64) - command = std::string("xmllint --noout \"") + filename + string("\""); - #else - command = std::string("xmllint --noout \'") + filename + string("\'"); - #endif - result=system(command.c_str()); - return result ==0; - } - - //Debug check ineffective - WARN(!result,"xmllint not installed in system PATH, cannot perform debug check") - return true; -} -#endif - - diff -Nru 3depict-0.0.12/src/basics.h 3depict-0.0.13/src/basics.h --- 3depict-0.0.12/src/basics.h 2012-11-18 15:15:22.000000000 +0000 +++ 3depict-0.0.13/src/basics.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,853 +0,0 @@ -/* - * basics.h - Basic functionality header - * Copyright (C) 2012, 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 . -*/ - - -#ifndef BASICS_H -#define BASICS_H -//!Basic objects header file - -#include "assertion.h" -#include "mathfuncs.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class K3DTree; - - -std::string boolStrEnc(bool b); - -bool dummyCallback(bool); - -extern const char *DTD_NAME; -extern const char *PROGRAM_NAME; -extern const char *PROGRAM_VERSION; -extern const char *FONT_FILE; - -#define ARRAYSIZE(f) (sizeof (f) / sizeof(*f)) - - - -//C file peek function -inline int fpeek(FILE *stream) -{ - int c; - - c = fgetc(stream); - ungetc(c, stream); - - return c; -} - -bool rangesOverlap(size_t minA, size_t maxA, - size_t minB, size_t maxB); - - -//!Text file loader errors -enum -{ - ERR_FILE_OPEN=1, - ERR_FILE_FORMAT, - ERR_FILE_NUM_FIELDS, - ERR_FILE_ENUM_END // not an error, just end of enum -}; - -extern const char *TEXT_LOAD_ERR_STRINGS[]; - - - template -bool hasFirstInPairVec(const std::vector > &v, const std::pair &r) -{ - for(size_t ui=0;ui &spacings); - -void tickSpacingsFromFixedNum(float start, float end, - unsigned int nTicks, std::vector &spacings); - -//!Get a "human-like" version of the time elapsed between new and original time period -std::string veryFuzzyTimeSince( time_t origTime, time_t newTime); - - -//!A routine for loading numeric data from a text file -unsigned int loadTextData(const char *cpFilename, - std::vector > &dataVec, - std::vector &header,const char *delim); - -//!Load non-numeric data from a text file into ragged array, using specified delimiters -unsigned int loadTextStringData(const char *cpFilename, - std::vector > &dataVec, - const char *delim); - - -template -bool writeTextFile(const char *cpFilename, - const std::vector > &dataVec, const char delim='\t') -{ - std::ofstream f(cpFilename); - - if(!f) - return false; - - for(unsigned int ui=0;uiidN are integers -std::string choiceString(std::vector > comboString, - unsigned int curChoice); - -//Convert a choice string, such as generated by "choiceString", into a vector of strings -void choiceStringToVector(const std::string &str, - std::vector &choices, unsigned int &selected); - -#ifdef DEBUG -//!Obtain whether or not the string is a choice string -bool isMaybeChoiceString(const std::string &s); -#endif -//!Generate a string with leading digits up to maxDigit (eg, if maxDigit is 424, and thisDigit is 1 -//leading digit will generate the string 001 -std::string digitString(unsigned int thisDigit, unsigned int maxDigit); - -//!Returns Choice from string (see choiceString(...) for string format) -std::string getActiveChoice(const std::string &choiceString); - -//!Convert a choiceString() into something that a wxGridCellChoiceEditor will accept -std::string wxChoiceParamString(std::string choiceString); - - -inline std::string stlWStrToStlStr(const std::wstring& s) -{ - std::string temp(s.length(),' '); - std::copy(s.begin(), s.end(), temp.begin()); - return temp; -} - -inline std::wstring stlStrToStlWStr(const std::string& s) -{ - std::wstring temp(s.length(),L' '); - std::copy(s.begin(), s.end(), temp.begin()); - return temp; -} - -//!Template function to cast and object to another by the stringstream -//IO operator -template bool stream_cast(T1 &result, const T2 &obj) -{ - std::stringstream ss; - ss << obj; - ss >> result; - return ss.fail(); -} - -//!Replace first instance of marker with null terminator -void nullifyMarker(char *buffer, char marker); - -//retrieve the active bit in a power of two sequence -inline unsigned int getBitNum(unsigned int u) -{ - ASSERT(u); - unsigned int j=0; - while(!(u &1) ) - { - u=u>>1; - j++; - } - - return j; -} - - -inline bool isVersionNumberString(const std::string &s) -{ - for(unsigned int ui=0;ui &s); - -//Convert a point string from its "C" language representation to a point value -bool parsePointStr(const std::string &str,Point3D &pt); - - -//Parse a colour string, such as #aabbccdd into its RGBA 8-bit components -bool parseColString(const std::string &str, - unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a); - -//Convert an RGBA 8-bit/channel quadruplet into its hexadecimal colour string -void genColString(unsigned char r, unsigned char g, - unsigned char b, unsigned char a, std::string &s); -//Convert an RGB 8-bit/channel quadruplet into its hexadecimal colour string -void genColString(unsigned char r, unsigned char g, - unsigned char b, std::string &s); - -//!Retrieve the maximum version string from a list of version strings -std::string getMaxVerStr(const std::vector &verStrings); - -//!Strip whitespace -std::string stripWhite(const std::string &str); - -//!Split string references using a single delimiter. -void splitStrsRef(const char *cpStr, const char delim,std::vector &v ); - -//!Split string references using any of a given string of delimiters -void splitStrsRef(const char *cpStr, const char *delim,std::vector &v ); - -//!A class to manage "tear-off" ID values, to allow for indexing without knowing position. -//You simply ask for a new unique ID. and it maintains the position->ID mapping -//TODO: Extend to any unique type, rather than just int (think iterators..., pointers) -class UniqueIDHandler -{ - private: - //!position-ID pairings - std::list > idList; - - public: - //!Generate a unique ID value, storing the position ID pair - unsigned int genId(unsigned int position); - //!Remove a uniqueID using its position - void killByPos(unsigned int position); - //!Get the position from its unique ID - unsigned int getPos(unsigned int id) const; - //!Get the uniqueID from the position - unsigned int getId(unsigned int pos) const; - - //!Get all unique IDs - void getIds(std::vector &idvec) const; - //!Clear the mapping - void clear(); - //!Get the number of elements stored - unsigned int size() const {return idList.size();}; -}; - -//!Get total filesize in bytes -bool getFilesize(const char *fname, size_t &size); - -//!get total ram in MB -int getTotalRAM(); - -//!Get available ram in MB -size_t getAvailRAM(); - - -#ifdef DEBUG -bool isValidXML(const char *filename); -#endif - -inline std::string tabs(unsigned int nTabs) -{ - std::string s; - s.resize(nTabs); - std::fill(s.begin(),s.end(),'\t'); - return s; -} - -class ComparePairFirst -{ - public: - template - bool operator()(const std::pair< T1, T2 > &p1, const std::pair &p2) const - { - return p1.first< p2.first; - } -}; - -class ComparePairSecond -{ - public: - template - bool operator()(const std::pair< T1, T2 > &p1, const std::pair &p2) const - { - return p1.second< p2.second; - } -}; - - -class ComparePairFirstReverse -{ - public: - template - bool operator()(const std::pair< T1, T2 > &p1, const std::pair &p2) const - { - return p1.first> p2.first; - } -}; - -//! A helper class to define a bounding cube -class BoundCube -{ - //!bounding values (x,y,z) (lower,upper) - float bounds[3][2]; - //!Is the cube set? - bool valid[3][2]; -public: - - BoundCube() { - setInvalid(); - } - - void setBounds(float xMin,float yMin,float zMin, - float xMax,float yMax,float zMax) { - bounds[0][0]=xMin; bounds[1][0]=yMin; bounds[2][0]=zMin; - bounds[0][1]=xMax; bounds[1][1]=yMax; bounds[2][1]=zMax; - valid[0][0]=true; valid[1][0]=true; valid[2][0]=true; - valid[0][1]=true; valid[1][1]=true; valid[2][1]=true; - } - - void setBounds(const BoundCube &b) - { - for(unsigned int ui=0;ui<3;ui++) - { - bounds[ui][0] = b.bounds[ui][0]; - valid[ui][0] = b.valid[ui][0]; - bounds[ui][1] = b.bounds[ui][1]; - valid[ui][1] = b.valid[ui][1]; - } - } - void setInvalid() - { - valid[0][0]=false; valid[1][0]=false; valid[2][0]=false; - valid[0][1]=false; valid[1][1]=false; valid[2][1]=false; - } - - //Set the cube to be "inside out" at the limits of numeric results; - void setInverseLimits(); - - void setBound(unsigned int bound, unsigned int minMax, float value) { - ASSERT(bound <3 && minMax < 2); - bounds[bound][minMax]=value; - valid[bound][minMax]=true; - }; - - float getBound(unsigned int bound, unsigned int minMax) const { - ASSERT(bound <3 && minMax < 2); - ASSERT(valid[bound][minMax]==true); - return bounds[bound][minMax]; - }; - //!Return the centroid - Point3D getCentroid() const; - - //!Get the bounds - void getBounds(Point3D &low, Point3D &high) const ; - - //!Return the size - float getSize(unsigned int dim) const; - - //! Returns true if all bounds are valid - bool isValid() const; - - //! Returns true if any bound is of null thickness - bool isFlat() const; - - //!Returns true if any bound of datacube is considered to be "large" in magnitude compared to - // floating pt data type. - bool isNumericallyBig() const; - - //!Obtain bounds from an array of Point3Ds - void setBounds( const Point3D *ptArray, unsigned int nPoints); - //!Use two points to set bounds -- does not need to be high,low. this is worked out/ - void setBounds( const Point3D &p, const Point3D &q); - //!Obtain bounds from an array of Point3Ds - void setBounds(const std::vector &ptArray); - //!Checks if a point intersects a sphere of centre Pt, radius^2 sqrRad - bool intersects(const Point3D &pt, float sqrRad); - //Check to see if the point is contained in, or part of the walls - //of the cube - bool containsPt(const Point3D &pt) 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; - - //!Returns maximum distnace to box corners (which is an upper bound on max box distance). - //Bounding box must be valid. - float getMaxDistanceToBox(const Point3D &pt) const; - - //Get the largest dimension of the bound cube - float getLargestDim() const; - - //Return the rectilinear volume represented by this prism. - float volume() const { return (bounds[0][1] - bounds[0][0])* - (bounds[1][1] - bounds[1][0])*(bounds[2][1] - bounds[2][0]);} - void limits(); - const BoundCube &operator=(const BoundCube &); - //!Expand (as needed) volume such that the argument bounding cube is enclosed by this one - void expand(const BoundCube &b); - //!Expand such that point is contained in this volume. Existing volume must be valid - void expand(const Point3D &p); - //!Expand by a specified thickness - void expand(float v); - - - friend std::ostream &operator<<(std::ostream &stream, const BoundCube& b); - - //FIXME: Hack! - friend class K3DTree; - friend class K3DTreeMk2; -}; - - - -//!Return only the filename component -std::string onlyFilename( const std::string& path ); -//!Return only the directory name component of the full path -std::string onlyDir( const std::string& path ); - -//OK, this is a bit tricky. We override the operators to call -//a callback, so the UI updates keep happening, even inside the STL function -//---- -template -class GreaterWithCallback -{ - private: - bool (*callback)(bool); - //!Reduction frequency (use callback every k its) - unsigned int redMax; - //!Current reduction counter - unsigned int reduction; - //!pointer to progress value - unsigned int *prgPtr; - public: - //!Second argument is a "reduction" value to set the number of calls - //to the random functor before initiating a callback - GreaterWithCallback( bool (*ptr)(bool),unsigned int red) : callback(ptr), redMax(red), reduction(red) - {}; - - bool operator()(const T &a, const T &b) - { - if(!reduction--) - { - reduction=redMax; - //Execute callback - (*callback)(false); - } - - return a < b; - } -}; - - -template -class EqualWithCallback -{ - private: - bool (*callback)(bool); - //!Reduction frequency (use callback every k its) - unsigned int redMax; - //!Current reduction counter - unsigned int reduction; - //!pointer to progress value - unsigned int *prgPtr; - public: - //!Second argument is a "reduction" value to set the number of calls - //to the random functor before initiating a callback - EqualWithCallback( bool (*ptr)(bool),unsigned int red) : callback(ptr), redMax(red), reduction(red) - { }; - - bool operator()(const T &a, const T &b) - { - if(!reduction--) - { - reduction=redMax; - //Execute callback - (*callback)(false); - } - - return a ==b; - } -}; -//---- - - -//Randomly select subset. Subset will be (somewhat) sorted on output -template size_t randomSelect(std::vector &result, const std::vector &source, - RandNumGen &rng, size_t num,unsigned int &progress,bool (*callback)(bool), bool strongRandom=false) -{ - const unsigned int NUM_CALLBACK=50000; - //If there are not enough points, just copy it across in whole - if(source.size() <= num) - { - num=source.size(); - result.resize(source.size()); - for(size_t ui=0; ui ticks; - ticks.resize(numTicksNeeded); - - //Create an array of numTicksNeededbers and fill - for(size_t ui=0; ui gFunctor(callback,50000); - std::sort(ticks.begin(),ticks.end(),gFunctor); - EqualWithCallback eqFunctor(callback,50000); - std::vector::iterator newLast; - newLast=std::unique(ticks.begin(),ticks.end()); - ticks.erase(newLast,ticks.end()); - - std::vector moreTicks; - //Top up with unique entries - while(ticks.size() +moreTicks.size() < numTicksNeeded) - { - size_t index; - - //This is actually not too bad. the collision probability is at most 50% - //due the switching behaviour above, for any large number of items - //So this is at worst case nlog(n) (I think) - index =(size_t)(rng.genUniformDev()*(float)(source.size()-1)); - if(!binary_search(ticks.begin(),ticks.end(),index) && - std::find(moreTicks.begin(),moreTicks.end(),index) ==moreTicks.end()) - moreTicks.push_back(index); - - } - - ticks.reserve(numTicksNeeded); - for(size_t ui=0;ui::iterator it=ticks.begin();it!=ticks.end();++it) - { - - result[pos]=source[*it]; - pos++; - if(!curProg--) - { - progress= (unsigned int)((float)(pos)/((float)num)*100.0f); - (*callback)(false); - curProg=NUM_CALLBACK; - } - } - } - else - { - //Sort the ticks properly (mostly sorted anyway..) - std::sort(ticks.begin(),ticks.end(),gFunctor); - - unsigned int curTick=0; - for(size_t ui=0;ui (ui-curTick)); - result[ui-curTick]=source[ui]; - } - - if(!curProg--) - { - progress= (unsigned int)(((float)(ui)/(float)source.size())*100.0f); - (*callback)(false); - curProg=NUM_CALLBACK; - } - } - } - - ticks.clear(); - } - else - { - //Use a weak randomisation - LinearFeedbackShiftReg l; - - //work out the mask level we need to use - size_t i=1; - unsigned int j=0; - while(i < (source.size()<<1)) - { - i=i<<1; - j++; - } - - //linear shift table starts at 3. - if(j<3) { - j=3; - i = 1 << j; - } - - size_t start; - //start at a random position in the linear state - start =(size_t)(rng.genUniformDev()*i); - l.setMaskPeriod(j); - l.setState(start); - - size_t ui=0; - unsigned int curProg=NUM_CALLBACK; - //generate unique weak random numbers. - while(ui size_t randomDigitSelection(std::vector &result, const size_t max, - RandNumGen &rng, size_t num,unsigned int &progress,bool (*callback)(bool), - bool strongRandom=false) -{ - //If there are not enough points, just copy it across in whole - if(max <=num) - { - num=max; - result.resize(max); - for(size_t ui=0; ui ticks; - ticks.resize(numTicksNeeded); - - //Create an array of numTicksNeededbers and fill - for(size_t ui=0; ui gFunctor(callback,50000); - std::sort(ticks.begin(),ticks.end(),gFunctor); - EqualWithCallback eqFunctor(callback,50000); - - std::vector::iterator itLast; - itLast=std::unique(ticks.begin(),ticks.end(),eqFunctor); - ticks.erase(itLast,ticks.end()); - std::vector moreTicks; - //Top up with unique entries - while(ticks.size() +moreTicks.size() < numTicksNeeded) - { - size_t index; - - //This is actually not too bad. the collision probability is at most 50% - //due the switching behaviour above, for any large number of items - //So this is at worst case nlog(n) (I think) - index =(size_t)(rng.genUniformDev()*(float)(max-1)); - if(!binary_search(ticks.begin(),ticks.end(),index) && - std::find(moreTicks.begin(),moreTicks.end(),index) ==moreTicks.end()) - moreTicks.push_back(index); - - } - - ticks.reserve(numTicksNeeded); - for(size_t ui=0;ui::iterator it=ticks.begin();it!=ticks.end();++it) - { - - result[pos]=*it; - pos++; - if(!curProg--) - { - progress= (unsigned int)((float)(curProg)/((float)num)*100.0f); - (*callback)(false); - curProg=CURPROG; - } - } - } - else - { - //Sort the ticks properly (mostly sorted anyway..) - std::sort(ticks.begin(),ticks.end(),gFunctor); - - unsigned int curTick=0; - for(size_t ui=0;ui. -*/ - -#include "cameras.h" -#include "mathfuncs.h" -#include "xmlHelper.h" - -#include "commonConstants.h" - -//MacOS is "special" and puts it elsewhere -#ifdef __APPLE__ - #include -#else - #include -#endif -#include "translation.h" - -#include -#include -#include - -using std::string; -using std::vector; -using std::pair; - -//TODO: FIXME: Orthogonal camera zooming is very slow, compared to -// perspective camera dolly. Check equations of motion for equivalence -const float ORTHO_SPEED_HACK=1.05; - - -//!Key types for property setting and getting via property grids -enum -{ - KEY_LOOKAT_LOCK, - KEY_LOOKAT_ORIGIN, - KEY_LOOKAT_TARGET, - KEY_LOOKAT_UPDIRECTION, - KEY_LOOKAT_FOV, - KEY_LOOKAT_PROJECTIONMODE, - KEY_LOOKAT_ORTHOSCALE -}; - - - -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() -{ -} - - -Point3D Camera::getOrigin() const -{ - return origin; -} - -Point3D Camera::getViewDirection() const -{ - return viewDirection; -} - -Point3D Camera::getUpDirection() const -{ - return upDirection; -} - -void Camera::setOrigin(const Point3D &pt) -{ - if(lock) - return; - origin=pt; -} - -void Camera::setViewDirection(const Point3D &pt) -{ - if(lock) - return; - viewDirection=pt; - viewDirection.normalise(); -} - -void Camera::setUpDirection(const Point3D &pt) -{ - if(lock) - return; - upDirection = pt; - upDirection.normalise(); -} - -void Camera::forwardsDolly(float moveRate) -{ - if(lock) - return; - origin=origin+ viewDirection*moveRate; -} - -void Camera::move(float moveLR, float moveUD) -{ - if(lock) - return; - //Right is the cross product of up and - //view direction (check sign) - //Up is simply the up vector - origin+=upDirection*moveUD + (upDirection.crossProd(viewDirection))*moveLR; -} - -void Camera::translate(float moveLR, float moveUD) -{ - if(lock) - return; - //This camera has no target. Just do plain move - move(moveLR,moveUD); -} - -void Camera::pivot(float lrRad, float udRad) -{ - if(lock) - return; - Point3f viewNew, rotateAxis; - - //rotate normalised rOrig around axis one then two - viewNew.fx=viewDirection[0]; - viewNew.fy=viewDirection[1]; - viewNew.fz=viewDirection[2]; - - //rotate around "right" axis - Point3D tmp = upDirection.crossProd(viewDirection); - rotateAxis.fx=tmp[0]; - rotateAxis.fy=tmp[1]; - rotateAxis.fz=tmp[2]; - quat_rot(&viewNew,&rotateAxis,udRad); - - //rotate around original "up" axis - rotateAxis.fx=upDirection[0]; - rotateAxis.fy=upDirection[1]; - rotateAxis.fz=upDirection[2]; - quat_rot(&viewNew,&rotateAxis,lrRad); - - viewDirection[0] = rotateAxis.fx; - viewDirection[1] = rotateAxis.fy; - viewDirection[2] = rotateAxis.fz; - -} - -//===== - - -//===== - -CameraLookAt::CameraLookAt() : target(Point3D(0,0,0)),fovAngle(90.0f), - nearPlane(1.0f), frustumDistortion(0.0f) -{ - origin=Point3D(0.0f,0.0f,1.0f); - viewDirection=Point3D(0.0f,0.0f,-1.0f); - upDirection=Point3D(0.0f,1.0f,0.0f); - - typeNum=CAM_LOOKAT; - projectionMode=PROJECTION_MODE_PERSPECTIVE; -} - -Camera *CameraLookAt::clone() const -{ - CameraLookAt *retCam = new CameraLookAt; - - retCam->origin =origin; - retCam->viewDirection=viewDirection; - retCam->upDirection =upDirection; - retCam->projectionMode=projectionMode; - retCam->orthoScale=orthoScale; - retCam->typeNum=typeNum; - retCam->userString=userString; - retCam->lock=lock; - - retCam->target = target; - retCam->fovAngle = fovAngle; - retCam->nearPlane=nearPlane; - retCam->farPlane=farPlane; - - - return retCam; -} - -CameraLookAt::~CameraLookAt() -{ -} - -void CameraLookAt::setTarget(const Point3D &pt) -{ - ASSERT(pt.sqrDist(origin)>10.0f*std::numeric_limits::epsilon()); - target=pt; - recomputeViewDirection(); -} - -Point3D CameraLookAt::getTarget() const -{ - return target; -} - -void CameraLookAt::doPerspCalcs(float aspectRatio, const BoundCube &bc,bool loadIdentity) const -{ - ASSERT(projectionMode == PROJECTION_MODE_PERSPECTIVE); - - glMatrixMode (GL_PROJECTION); - if(loadIdentity) - glLoadIdentity(); - - //As the far plane is dynamically computed, similarly - //bring the near plane to a constant factor of the far plane - // that way, when the far plane comes in, so should the near plane - // this factor is only somewhat arbitrary, as it is based upon the - // number of significant figures in a 32 bit float - const float NEAR_PLANE_FACTOR=1.0f/10000.0f; - - farPlane = 1.5f*bc.getMaxDistanceToBox(origin); - gluPerspective(fovAngle/2.0,aspectRatio,farPlane*NEAR_PLANE_FACTOR,farPlane); - glMatrixMode(GL_MODELVIEW); - - glTranslatef(origin[0],origin[1],origin[2]); - - //As gluperspective defaults to viewing down the 0,0,-1 axis - //we must rotate the scene such that the view direction - //is brought into line with the default view vector - Point3D rotVec,defaultDir(0,0,-1.0f); - float rotAngle; - - - rotVec = viewDirection.crossProd(defaultDir); - - - rotAngle = 180.0f/M_PI * viewDirection.angle(defaultDir); - - glRotatef(-rotAngle,rotVec[0],rotVec[1],rotVec[2]); - - //Camera roll - //Default "up" direction - defaultDir[2] = 1.0f; - rotVec = upDirection.crossProd(defaultDir); - rotAngle = 180.0f/M_PI * upDirection.angle(defaultDir); - glRotatef(-rotAngle, rotVec[0], rotVec[1],rotVec[2]); - -} - -void CameraLookAt::setOrigin(const Point3D &newOrigin) -{ - if(lock) - return; - ASSERT(newOrigin.sqrDist(target)>std::numeric_limits::epsilon()); - origin=newOrigin; - recomputeViewDirection(); -} - -void CameraLookAt::apply(float aspect, const BoundCube &bc, bool loadIdentity) const -{ - - glMatrixMode (GL_PROJECTION); - if(loadIdentity) - glLoadIdentity(); - - farPlane = 1.5*bc.getMaxDistanceToBox(origin); - switch(projectionMode) - { - - case PROJECTION_MODE_PERSPECTIVE: - { - - gluPerspective(fovAngle/2.0,aspect,nearPlane,farPlane); - glMatrixMode(GL_MODELVIEW); - break; - - } - case PROJECTION_MODE_ORTHOGONAL: - { - glOrtho(-orthoScale*aspect,orthoScale*aspect,-orthoScale,orthoScale,nearPlane,farPlane); - glMatrixMode(GL_MODELVIEW); - break; - } - default: - ASSERT(false); - - } - - ASSERT(origin.sqrDist(target)>std::numeric_limits::epsilon()); - gluLookAt(origin[0],origin[1],origin[2], - target[0],target[1],target[2], - upDirection[0],upDirection[1],upDirection[2]); -} - -void CameraLookAt::apply(float aspect,const BoundCube &b,bool loadIdentity, - float leftRestrict,float rightRestrict, - float bottomRestrict,float topRestrict) const -{ - ASSERT(leftRestrict < rightRestrict); - ASSERT(bottomRestrict< topRestrict); - - glMatrixMode (GL_PROJECTION); - if(loadIdentity) - glLoadIdentity(); - - farPlane = 1.5*b.getMaxDistanceToBox(origin); - switch(projectionMode) - { - - case PROJECTION_MODE_PERSPECTIVE: - { - float width,height; - height = tan(fovAngle/2.0*M_PI/180.0f)*nearPlane; - width= height*aspect; - - - //Frustum uses eye coordinates. - if(fabs(frustumDistortion) < std::numeric_limits::epsilon()) - glFrustum(leftRestrict*width,rightRestrict*width,bottomRestrict*height, - topRestrict*height,nearPlane,farPlane); - else - { - float workingDist=farPlane;//sqrtf((target-origin).sqrMag()); - glFrustum(leftRestrict*width+frustumDistortion*nearPlane/workingDist, - rightRestrict*width+frustumDistortion*nearPlane/workingDist, - bottomRestrict*height, topRestrict*height,nearPlane,farPlane); - } - break; - } - case PROJECTION_MODE_ORTHOGONAL: - { - float l,r,b,t; - - //FIXME:I have no idea why it is 2x...AFAIK it should just be ONE. - //but this works, and one does not. - l = 2*leftRestrict*orthoScale*aspect; - r= 2*rightRestrict*orthoScale*aspect; - b= 2*bottomRestrict*orthoScale; - t = 2*topRestrict*orthoScale; - - glOrtho(l,r,b,t,nearPlane,farPlane); - break; - } - default: - ASSERT(false); - } - - glMatrixMode(GL_MODELVIEW); - - ASSERT(origin.sqrDist(target)>std::numeric_limits::epsilon()); - gluLookAt(origin[0],origin[1],origin[2], - target[0],target[1],target[2], - upDirection[0],upDirection[1],upDirection[2]); - -} - -void CameraLookAt::translate(float moveLR, float moveUD) -{ - if(lock) - return; - float fovMultiplier=1.0f; - if(projectionMode== PROJECTION_MODE_PERSPECTIVE) - { - - //Try to move such that the target sweeps our field of view - //at a constant rate. Standard normaliser is view length at - //a 90* camera - //Use tan.. to normalise motion rate - //Prevent numerical error near tan( 90*) - if(fovAngle < 175.0f) - fovMultiplier = tan(fovAngle/2.0*M_PI/180.0); - else - fovMultiplier = tan(175.0f/2.0*M_PI/180.0); - } - - - moveLR=moveLR*sqrtf(target.sqrDist(origin)*fovMultiplier); - moveUD=moveUD*sqrtf(target.sqrDist(origin)*fovMultiplier); - - origin+=upDirection*moveUD + (upDirection.crossProd(viewDirection))*moveLR; - target+=upDirection*moveUD + (upDirection.crossProd(viewDirection))*moveLR; -} - -void CameraLookAt::forwardsDolly(float moveRate) -{ - if(lock) - return; - - if(projectionMode == PROJECTION_MODE_PERSPECTIVE) - { - Point3D newOrigin; - - //Prevent camera orientation inversion, which occurs when moving past the target - if(moveRate > sqrt(target.sqrDist(origin))) - { - if((target-origin).sqrMag() < sqrtf(std::numeric_limits::epsilon())) - return; - - //Yes, this simplifies analytically. However i think the numerics come into play. - float moveInv = 1.0/(fabs(moveRate) + std::numeric_limits::epsilon()); - newOrigin=origin+viewDirection*moveInv/(1.0+moveInv); - - } - else - { - //scale moverate by orbit distance - moveRate = moveRate*sqrtf(target.sqrDist(origin)); - newOrigin=origin+viewDirection*moveRate; - } - - //Only accept origin change if it is sufficiently far from the target - if(newOrigin.sqrDist(target)>sqrtf(std::numeric_limits::epsilon())) - origin=newOrigin; - } - else - { - float deltaSqr; - deltaSqr = (target-origin).sqrMag(); - if(deltaSqr< sqrtf(std::numeric_limits::epsilon())) - return; - - Point3D virtualOrigin; - virtualOrigin = origin+viewDirection*moveRate; - - float factor; - factor = virtualOrigin.sqrDist(target)/deltaSqr; - if( factor > 1.0) - factor*=ORTHO_SPEED_HACK; - else - factor/=ORTHO_SPEED_HACK; - - orthoScale*=factor; - } -} - - -//Clockwise roll looking from camera view by rollRad radians -void CameraLookAt::roll(float rollRad) -{ - if(lock) - return; - Point3f rNew,rotateAxis; - - rotateAxis.fx=viewDirection[0]; - rotateAxis.fy=viewDirection[1]; - rotateAxis.fz=viewDirection[2]; - - rNew.fx=upDirection[0]; - rNew.fy=upDirection[1]; - rNew.fz=upDirection[2]; - quat_rot(&rNew,&rotateAxis,rollRad); - - upDirection=Point3D(rNew.fx,rNew.fy,rNew.fz); - recomputeUpDirection(); -} - -void CameraLookAt::pivot(float leftRightRad,float updownRad) -{ - if(lock) - return; - - Point3f rNew,rotateAxis; - Point3D tmp; - //rotate normalised rOrig around axis one then two - tmp=target-origin; - rNew.fx=tmp[0]; - rNew.fy=tmp[1]; - rNew.fz=tmp[2]; - - //rotate around "right" axis - tmp = upDirection.crossProd(viewDirection); - tmp.normalise(); - rotateAxis.fx=tmp[0]; - rotateAxis.fy=tmp[1]; - rotateAxis.fz=tmp[2]; - quat_rot(&rNew,&rotateAxis,updownRad); - - Point3D newDir; - newDir=Point3D(rNew.fx,rNew.fy,rNew.fz)+origin; - - //rotate around original "up" axis - rotateAxis.fx=upDirection[0]; - rotateAxis.fy=upDirection[1]; - rotateAxis.fz=upDirection[2]; - quat_rot(&rNew,&rotateAxis,leftRightRad); - - newDir+= Point3D(rNew.fx,rNew.fy,rNew.fz); - target = target+newDir; - target.normalise(); - target*=sqrtf((target).sqrDist(origin)); - - recomputeViewDirection(); - recomputeUpDirection(); -} - -//Make a given bounding box visible, as much as possible -void CameraLookAt::ensureVisible(const BoundCube &boundCube, unsigned int face) -{ - if(lock) - return; - //Face is defined by the following net - // 0 - // 1 2 3 - // 4 - // 5 - //2 is the face directed to the +ve x axis, - //with the "up"" vector on the 3 aligned to z, - //so "0" is parallel to the Z axis and is "visible" - //from the top +ve side of the z axis (at sufficient distance) - - //To make the camera visible, we must place the camera - //outside the box, on the correct face, - //at sufficient distance to ensure that the face closest - //to the box is visible at the current FOV. - - //Box centroid - Point3D boxCentroid = boundCube.getCentroid(); - - //Vector from box face to camera - Point3D faceOutVector, tmpUpVec; - - //I labelled a physical box to work this table out. - float boxToFrontDist,faceSize[2]; - switch(face) - { - case 0: - faceOutVector = Point3D(0,0,1); - boxToFrontDist=boundCube.getSize(2); - tmpUpVec = Point3D(0,1,0); - faceSize[0]=boundCube.getSize(0); - faceSize[1]=boundCube.getSize(1); - break; - case 1: - faceOutVector = Point3D(0,-1,0); - boxToFrontDist=boundCube.getSize(1); - tmpUpVec = Point3D(1,0,0); - faceSize[0]=boundCube.getSize(1); - faceSize[1]=boundCube.getSize(0); - break; - case 2: - faceOutVector = Point3D(0,1,0); - boxToFrontDist=boundCube.getSize(1); - tmpUpVec =Point3D(1,0,0); - faceSize[0]=boundCube.getSize(0); - faceSize[1]=boundCube.getSize(2); - break; - case 3: - faceOutVector = Point3D(1,0,0); - boxToFrontDist=boundCube.getSize(0); - tmpUpVec = Point3D(0,0,1); - faceSize[0]=boundCube.getSize(1); - faceSize[1]=boundCube.getSize(2); - break; - case 4: - faceOutVector = Point3D(0,0,-1); - boxToFrontDist=boundCube.getSize(2); - tmpUpVec = Point3D(0,1,0); - faceSize[0]=boundCube.getSize(0); - faceSize[1]=boundCube.getSize(1); - break; - case 5: - faceOutVector = Point3D(-1,0,0); - boxToFrontDist=boundCube.getSize(0); - tmpUpVec = Point3D(0,0,1); - faceSize[0]=boundCube.getSize(1); - faceSize[1]=boundCube.getSize(2); - break; - default: - ASSERT(false); - } - - - //Convert box to front distance to vector from - //centroid to front face. - boxToFrontDist/=2.0f; - float halfMaxFaceDim=std::max(faceSize[0],faceSize[1])/2.0; - - - ASSERT(fovAngle > 0); - - //Set camera target to inside box - target=boxCentroid; - - float outDistance; - if(projectionMode == PROJECTION_MODE_PERSPECTIVE) - { - //Minimal camera distance is given trigonometrically. - //Add aditional 1 to ensure that nearplane does not clip object - outDistance=1.0+boxToFrontDist+halfMaxFaceDim/tan((fovAngle*M_PI/180)/2.0f); - } - else - { - outDistance=boxToFrontDist+halfMaxFaceDim; - } - - //Multiply by 1.4 to give a bit of border. - origin=boxCentroid+faceOutVector*1.4*outDistance; - - orthoScale = sqrtf(target.sqrDist(origin))/2.0; - - - //Set the default up direction - upDirection=tmpUpVec; - - //Reset the view direction - recomputeViewDirection(); - //Ensure up direction orthogonal - recomputeUpDirection(); - nearPlane = 1; -} - -void CameraLookAt::recomputeViewDirection() -{ - viewDirection=origin-target; - viewDirection.normalise(); -} -void CameraLookAt::recomputeUpDirection() -{ - //Use cross product of view and up to generate an across vector. - Point3D across; - upDirection.normalise(); - across = viewDirection.crossProd(upDirection); - across.normalise(); - - //Regenerate up vector by reversing the cross with a normalised across vector - upDirection = across.crossProd(viewDirection); - - upDirection.normalise(); -} - - -void CameraLookAt::move(float moveLRAngle, float moveUDAngle) -{ - if(lock) - return; - - //Think of the camera as moving around the surface of a sphere - Point3f curOrig; - curOrig.fx = origin[0] - target[0]; - curOrig.fy = origin[1] - target[1]; - curOrig.fz = origin[2] - target[2]; - - //Perform "up" rotation - Point3D rotateAxis; - - rotateAxis=upDirection; - Point3f r,u; - r.fx = rotateAxis[0]; - r.fy = rotateAxis[1]; - r.fz = rotateAxis[2]; - - u.fx = upDirection[0]; - u.fy = upDirection[1]; - u.fz = upDirection[2]; - - //Perform quaternion rotation around this aixs - quat_rot(&curOrig,&r, moveLRAngle); - quat_rot(&curOrig,&u, moveLRAngle); - - recomputeViewDirection(); - //Perform across rotation - rotateAxis =upDirection.crossProd(viewDirection).normalise(); - r.fx = rotateAxis[0]; - r.fy = rotateAxis[1]; - r.fz = rotateAxis[2]; - quat_rot(&curOrig,&r, moveUDAngle); - //Get transformed coordinates - origin[0] = target[0] + curOrig.fx; - origin[1] = target[1] + curOrig.fy; - origin[2] = target[2] + curOrig.fz; - recomputeViewDirection(); -} - -void CameraLookAt::getProperties(CameraProperties &p) const -{ - p.data.clear(); - p.types.clear(); - p.keys.clear(); - - vector > s; - vector type,keys; - - if(lock) - s.push_back(std::make_pair(TRANS("Lock"),"1")); - else - s.push_back(std::make_pair(TRANS("Lock"),"0")); - - type.push_back(PROPERTY_TYPE_BOOL); - keys.push_back(KEY_LOOKAT_LOCK); - - string ptStr; - stream_cast(ptStr,origin); - s.push_back(std::make_pair(TRANS("Origin"), ptStr)); - type.push_back(PROPERTY_TYPE_POINT3D); - keys.push_back(KEY_LOOKAT_ORIGIN); - - stream_cast(ptStr,target); - s.push_back(std::make_pair(TRANS("Target"), ptStr)); - type.push_back(PROPERTY_TYPE_POINT3D); - keys.push_back(KEY_LOOKAT_TARGET); - - stream_cast(ptStr,upDirection); - s.push_back(std::make_pair(TRANS("Up Dir."), ptStr)); - type.push_back(PROPERTY_TYPE_POINT3D); - keys.push_back(KEY_LOOKAT_UPDIRECTION); - - vector > choices; - string tmp; - - - tmp=TRANS("Perspective"); - choices.push_back(make_pair((unsigned int)PROJECTION_MODE_PERSPECTIVE,tmp)); - tmp=TRANS("Orthogonal"); - choices.push_back(make_pair((unsigned int)PROJECTION_MODE_ORTHOGONAL,tmp)); - tmp= choiceString(choices,projectionMode); - - s.push_back(std::make_pair(TRANS("Projection"), tmp)); - type.push_back(PROPERTY_TYPE_CHOICE); - keys.push_back(KEY_LOOKAT_PROJECTIONMODE); - - switch(projectionMode) - { - case PROJECTION_MODE_PERSPECTIVE: - stream_cast(tmp,fovAngle); - s.push_back(std::make_pair(TRANS("Field of View (deg)"), tmp)); - type.push_back(PROPERTY_TYPE_REAL); - keys.push_back(KEY_LOOKAT_FOV); - break; - case PROJECTION_MODE_ORTHOGONAL: - stream_cast(tmp,orthoScale); - s.push_back(std::make_pair(TRANS("View size"), tmp)); - type.push_back(PROPERTY_TYPE_REAL); - keys.push_back(KEY_LOOKAT_ORTHOSCALE); - break; - - } - - p.data.push_back(s); - p.keys.push_back(keys); - p.types.push_back(type); -} - -bool CameraLookAt::setProperty(unsigned int key, const string &value) -{ - - switch(key) - { - case KEY_LOOKAT_LOCK: - { - if(value == "1") - lock=true; - else if (value == "0") - lock=false; - else - return false; - - break; - } - case KEY_LOOKAT_ORIGIN: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - //Disallow origin to be set to same as target - if(newPt.sqrDist(target) < sqrtf(std::numeric_limits::epsilon())) - return false; - - origin= newPt; - - break; - } - case KEY_LOOKAT_TARGET: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - //Disallow origin to be set to same as target - if(newPt.sqrDist(origin) < sqrtf(std::numeric_limits::epsilon())) - return false; - target = newPt; - - break; - } - case KEY_LOOKAT_UPDIRECTION: - { - Point3D newDir; - if(!parsePointStr(value,newDir)) - return false; - - //View direction and up direction may not be the same - if(viewDirection.crossProd(newDir).sqrMag() < - sqrtf(std::numeric_limits::epsilon())) - return false; - - upDirection=newDir; - //Internal up direction should be perp. to view direction. - //use double cross product method to restore - recomputeUpDirection(); - break; - } - case KEY_LOOKAT_FOV: - { - float newFOV; - if(stream_cast(newFOV,value)) - return false; - - fovAngle=newFOV; - break; - } - case KEY_LOOKAT_PROJECTIONMODE: - { - size_t ltmp; - if(value == TRANS("Perspective")) - ltmp=PROJECTION_MODE_PERSPECTIVE; - else if( value == TRANS("Orthogonal")) - { - if(projectionMode!=PROJECTION_MODE_ORTHOGONAL) - { - //use the distance to the target as the orthographic - //scaling size (size of parallel frustrum) - orthoScale=sqrtf(target.sqrDist(origin)); - } - - ltmp=PROJECTION_MODE_ORTHOGONAL; - - } - else - { - ASSERT(false); - return false; - } - - if(ltmp>=PROJECTION_MODE_ENUM_END) - return false; - - projectionMode=ltmp; - - break; - } - case KEY_LOOKAT_ORTHOSCALE: - { - float newOrthoScale; - if(stream_cast(newOrthoScale,value)) - return false; - - orthoScale=newOrthoScale; - break; - } - - - default: - ASSERT(false); - } - return true; -} - -bool CameraLookAt::writeState(std::ostream &f, unsigned int format, - unsigned int nTabs) const -{ - switch(format) - { - case STATE_FORMAT_XML: - { - using std::endl; - - f << tabs(nTabs) << "" << endl; - ASSERT(userString.size()); - f << tabs(nTabs+1) << "" << endl; - f << tabs(nTabs+1) << "" << endl; - f << tabs(nTabs+1) << "" << endl; - - if(lock) - f<< tabs(nTabs+1) << "" << endl; - else - f<< tabs(nTabs+1) << "" << endl; - f << tabs(nTabs+1) << "" << endl; - f << tabs(nTabs+1) << "" << endl; - f << tabs(nTabs+1) << "" << endl; - - f<< tabs(nTabs+1) << "" << endl; - f<< tabs(nTabs+1) << "" << endl; - f << tabs(nTabs) << "" << endl; - - return true; - } - default: - ASSERT(false); - } -} - -bool CameraLookAt::readState(xmlNodePtr nodePtr) -{ - //Retrieve user string - if(!XMLGetNextElemAttrib(nodePtr,userString,"userstring","value")) - return false; - if(!userString.size()) - return false; - - std::string tmpStr; - - //Retrieve projection mode - if(!XMLGetNextElemAttrib(nodePtr,projectionMode,"projectionmode","value")) - return false; - if(projectionMode > PROJECTION_MODE_ENUM_END) - return false; - - //Retrieve orthographic scaling - if(!XMLGetNextElemAttrib(nodePtr,orthoScale,"orthoscale","value")) - return false; - if(orthoScale <=0 || std::isnan(orthoScale)) - return false; - - - float x,y,z; - xmlChar *xmlString; - - - //retrieve lock state - if(XMLHelpFwdToElem(nodePtr,"lock")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - - std::string strTmp; - strTmp=(char*)xmlString; - if(strTmp == "1") - lock=true; - else if(strTmp == "0") - lock=false; - else - return false; - - //Retrieve origin - //==== - if(XMLHelpFwdToElem(nodePtr,"origin")) - return false; - //--Get X value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(x,tmpStr)) - return false; - - //--Get Z value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(y,tmpStr)) - return false; - - //--Get Y value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(z,tmpStr)) - return false; - - origin=Point3D(x,y,z); - //==== - - //Retrieve target - //==== - if(XMLHelpFwdToElem(nodePtr,"target")) - return false; - //--Get X value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(x,tmpStr)) - return false; - - //--Get Z value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(y,tmpStr)) - return false; - - //--Get Y value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(z,tmpStr)) - return false; - target=Point3D(x,y,z); - //==== - - //Retrieve up direction - //==== - if(XMLHelpFwdToElem(nodePtr,"updirection")) - return false; - //--Get X value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(x,tmpStr)) - return false; - - //--Get Z value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(y,tmpStr)) - return false; - - //--Get Y value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(z,tmpStr)) - return false; - upDirection=Point3D(x,y,z); - //==== - - - //Get the FOV angle - //==== - if(!XMLGetNextElemAttrib(nodePtr,fovAngle,"fovangle","value")) - return false; - if(fovAngle<=0) - return false; - //==== - - //Get the near plane - //==== - if(!XMLGetNextElemAttrib(nodePtr,nearPlane,"nearplane","value")) - return false; - //==== - - recomputeViewDirection(); - return true; -} - -float CameraLookAt::getViewWidth(float depth) const -{ - if(projectionMode == PROJECTION_MODE_PERSPECTIVE) - return depth*tan(fovAngle/2.0f*M_PI/180.0); - else if(projectionMode == PROJECTION_MODE_ORTHOGONAL) - return -orthoScale*2.0f; //FIXME: Why is this negative??! - - ASSERT(false); -} - -std::ostream& operator<<(std::ostream &strm, const Camera &c) -{ - strm << "origin: " << c.origin << std::endl; - strm << "View Direction: " << c.viewDirection << std::endl; - strm << "Up Direction: "<< c.upDirection << std::endl; - return strm; -} - -std::ostream& operator<<(std::ostream &strm, const CameraLookAt &c) -{ - strm << "origin: " << c.origin << std::endl; - strm << "Target : " << c.target << std::endl; - - strm << "View Direction: " << c.viewDirection << std::endl; - strm << "Up Direction: "<< c.upDirection << std::endl; - - - strm << "FOV (deg) : " << c.fovAngle << std::endl; - strm << "Clip planes: " << c.nearPlane << " (near) " << std::endl; - return strm; -} - - - diff -Nru 3depict-0.0.12/src/cameras.h 3depict-0.0.13/src/cameras.h --- 3depict-0.0.12/src/cameras.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/cameras.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -/* - * cameras.h - 3D cameras for opengl - * Copyright (C) 2012, 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 . -*/ - -#ifndef CAMERAS_H -#define CAMERAS_H - -#include "basics.h" - -//libxml2 headers -#ifdef ATTRIBUTE_PRINTF - #pragma push_macro("ATTRIBUTE_PRINTF") - #include - #pragma pop_macro(" ATTRIBUTE_PRINTF") -#else - #include - #undef ATTRIBUTE_PRINTF -#endif - -enum CAM_ENUM -{ - CAM_FREE=1, - CAM_LOOKAT -}; - -enum -{ - PROJECTION_MODE_PERSPECTIVE, - PROJECTION_MODE_ORTHOGONAL, - PROJECTION_MODE_ENUM_END //not a valid mode. -}; - -class CameraProperties -{ - public: - //Filter property data, one per output, each is value then name - std::vector > > data; - //Data types for each single element - std::vector > types; - - //!Key numbers for filter. Must be unique per set - std::vector > keys; - -}; - -//!An abstract base class for a camera -class Camera -{ - protected: - - bool lock; - //!Camera location - Point3D origin; - //!Direction camera is looking in - Point3D viewDirection; - //!Up direction for camera (required to work out "roll") - Point3D upDirection; - - //!Projection mode (otho, perspective...)_ - unsigned int projectionMode; - - //!The current orthographic scaling - float orthoScale; - - //!Type number - unsigned int typeNum; - //!user string, e.g. camera name - std::string userString; - public: - //!constructor - Camera(); - //!Destructor - virtual ~Camera(); - //!Duplication routine. Must delete returned pointer manually. - virtual Camera *clone() const=0; - - //!Streaming output operator, presents human readable text - friend std::ostream &operator<<(std::ostream &stream, const Camera &); - - //!Return the origin of the camera - Point3D getOrigin() const; - //!Return the view direction for the camera - Point3D getViewDirection() const; - //!Return the up direction for the camera - Point3D getUpDirection() const; - - //!return the projection mode - unsigned int getProjectionMode() const{ return projectionMode;}; - - //!Set the camera's position - virtual void setOrigin(const Point3D &); - //!set the direction that the camera looks towards - void setViewDirection(const Point3D &); - //!set the direction that the camera considers "up" - void setUpDirection(const Point3D &); - - //!Set the user string - void setUserString(const std::string &newString){ userString=newString;}; - //!Get the user string - std::string getUserString() const { return userString;}; - - //!Do a forwards "dolly",where the camera moves along its viewing axis. In ortho mode, instead of moving along axis, a scaling is performed - virtual void forwardsDolly(float dollyAmount); - - //!Move the camera origin - virtual void move(float leftRightAmount,float UpDownAmount); - - //!Move the camera origin - virtual void translate(float leftRightAmount,float UpDownAmount); - - //!pivot the camera - /* First pivots the camera around the across direction - * second pivot sthe camera around the up direction - */ - virtual void pivot(float rollAroundAcross, float rollaroundUp); - - //!Roll around the view direction - virtual void roll(float roll) =0; - //!Applies the camera settings to openGL. Ensures the far planes - //is set to make the whole scene visible - virtual void apply(float outputRatio,const BoundCube &b,bool loadIdentity=true) const=0; - //!Applies the camera settings to openGL, restricting the viewport (range (-1, 1)) - virtual void apply(float outputRatio,const BoundCube &b,bool loadIdentity, - float leftRestrict,float rightRestrict, - float bottomRestrict, float topRestrict) const=0; - //!Ensures that the given boundingbox should look nice, and be visible - virtual void ensureVisible(const BoundCube &b, unsigned int face=3)=0; - - //!Obtain the properties specific to a camera - virtual void getProperties(CameraProperties &p) const =0; - //!Set the camera property from a key & string pair - virtual bool setProperty(unsigned int key, const std::string &value) =0; - - unsigned int type() const {return typeNum;}; - - //!Write the state of the camera - virtual bool writeState(std::ostream &f, unsigned int format, unsigned int tabs) const =0; - - //!Read the state of the camera from XML document - virtual bool readState(xmlNodePtr nodePtr)=0; - -}; - -//!A perspective camera that looks at a specific location -class CameraLookAt : public Camera -{ - protected: - //!Location for camera to look at - Point3D target; - - void recomputeViewDirection(); - - //!Perspective FOV - float fovAngle; - - //!Near clipping plane distance. - float nearPlane; - //!Far plane is computed on-the-fly. cannot be set directly. Oh no! mutable. gross! - mutable float farPlane; - - //!Distort to the viewing frustum. (eg for stero) ( a frustum is a rectangular pyramid with the top cut off) - float frustumDistortion; - - //!Do the perspective calculations - void doPerspCalcs(float aspect,const BoundCube &bc,bool loadIdentity) const; - - public: - //!Constructor - CameraLookAt(); - - //!Streaming output operator, presents human readable text - friend std::ostream &operator<<(std::ostream &stream, const CameraLookAt &); - //!clone function - Camera *clone() const; - //!Destructor - virtual ~CameraLookAt(); - //!Set the look at target - void setOrigin(const Point3D &); - //!Set the look at target - void setTarget(const Point3D &); - //!Get the look at target - Point3D getTarget() const; - - //!Get the camera's FOV angle (full angle across) - float getFOV() const {return fovAngle;} - - //!Applies the view transform - void apply(float outAspect, const BoundCube &boundCube,bool loadIdentity=true) const; - - //!Do a forwards "dolly",where the camera moves along its viewing axis - void forwardsDolly(float dollyAmount); - - //!Move the camera origin - void move(float leftRightAmount,float UpDownAmount); - //!Simulate pivot of camera - /* Actually I pivot by moving the target internally. - */ - void pivot(float lrRad,float udRad); - - void translate(float lrTrans, float udTrans); - - - - //Clockwise roll looking from camera view by rollRad radians - void roll(float rollRad); - - //!Ensure that up direction is perpendicular to view direction - void recomputeUpDirection(); - - //!Ensure that the box is visible - /*! Face is set by cube net - 0 - 1 2 3 - 4 - 5 - 2 is the face directed to the +ve x axis, - with the "up"" vector on the 3 aligned to z, - so "0" is perpendicular to the Z axis and is "visible" - */ - virtual void ensureVisible(const BoundCube &b, unsigned int face=3); - - //!Return the user-settable properties of the camera - void getProperties(CameraProperties &p) const; - //!Set the camera property from a key & string pair - bool setProperty(unsigned int key, const std::string &value); - - //!Write the state of the camera - bool writeState(std::ostream &f, unsigned int format, unsigned int tabs=0) const; - - //!Read the state of the camera - bool readState(xmlNodePtr nodePtr) ; - - //!Apply, restricting viewport to subresgion - virtual void apply(float outputRatio,const BoundCube &b,bool loadIdentity, - float leftRestrict,float rightRestrict, - float topRestrict, float bottomRestrict) const; - - float getViewWidth(float depth) const; - - void setFrustumDistort(float offset){frustumDistortion=offset;}; - -}; - -#endif diff -Nru 3depict-0.0.12/src/colourmap.cpp 3depict-0.0.13/src/colourmap.cpp --- 3depict-0.0.12/src/colourmap.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/colourmap.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,246 +0,0 @@ -/* - * colourmap.cpp - contiuum colourmap header - * Copyright (C) 2010, ViewerGTKQt project - * Modifed by D Haley 2011 - - * 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 . -*/ - - -#include -#include -#include "colourmap.h" -#include - -#include "translation.h" - -void jetColorMap(unsigned char *rgb,float value,float min,float max) -{ - float max4=(max-min)/4; - value-=min; - if (value==HUGE_VAL) - { - rgb[0]=rgb[1]=rgb[2]=255; - } - else if (value<0) - { - rgb[0]=rgb[1]=rgb[2]=0; - } - else if (value1){ - rgb[0]=rgb[1]=rgb[2]=255; - return; - } - - rgb[0]=192;rgb[1]=0;rgb[2]=0; - rgb[0]+=(unsigned char)(63*value); - rgb[1]+=(unsigned char)(255*value); - if(value>0.5) - rgb[2]+=(unsigned char)(255*2*(value-0.5)); -} - -void negativeColorMap(unsigned char *rgb,float value,float min,float max) -{ - value-=min; - max-=min; - rgb[0]=0;rgb[1]=0;rgb[2]=0; - - if(max>std::numeric_limits::epsilon()) - value/=max; - if(value<0) return; - if(value>1){ - rgb[1]=rgb[2]=255; - return; - } - - rgb[1]+=(unsigned char)(255*value); - if(value>0.5) - rgb[2]+=(unsigned char)(255*2*(value-0.5)); - -} - -void colorMap(unsigned char *rgb,float value,float min,float max) -{ - if(value>0) - positiveColorMap(rgb,value,0,max); - else - negativeColorMap(rgb,value,min,0); -} - -void cyclicColorMap(unsigned char *rgb,float value,float min,float max) -{ - float max3=(max-min)/3; - value-=(max-min)*(float)floor((value-min)/(max-min)); - if(value. -*/ - -#ifndef _COLORMAP_H_ -#define _COLORMAP_H_ - -#include - -const unsigned int NUM_COLOURMAPS=8; - -//!get colour for specific map -/* 0 jetColorMap | 5 colorMap - * 1 hotColorMap | 6 blueColorMap - * 2 coldColorMap | 7 randColorMap - * 3 grayColorMap | - * 4 cyclicColorMap | - * - * returns char in 0->255 range - */ -void colourMapWrap(unsigned int mapID,unsigned char *rgb, float value, float min,float max); - -std::string getColourMapName(unsigned int mapID); - -#endif - diff -Nru 3depict-0.0.12/src/common/assertion.h 3depict-0.0.13/src/common/assertion.h --- 3depict-0.0.12/src/common/assertion.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/assertion.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * common/assertion.h - Program assertion 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 . + */ + +#ifndef ASSERTION_H +#define ASSERTION_H + +#ifdef DEBUG + #include + #include + + #include + + void dh_assert(const char * const filename, const unsigned int lineNumber); + void dh_warn(const char * const filename, const unsigned int lineNumber, + const char *message); + + #ifndef ASSERT + #define ASSERT(f) if(!(f)) {dh_assert(__FILE__,__LINE__);} + #endif + + #ifndef WARN + #define WARN(f,g) if(!(f)) { dh_warn(__FILE__,__LINE__,g);} + #endif + + inline void dh_assert(const char * const filename, const unsigned int lineNumber) + { + std::cerr << "ASSERTION ERROR!" << std::endl; + std::cerr << "Filename: " << filename << std::endl; + std::cerr << "Line number: " << lineNumber << std::endl; + + std::cerr << "Do you wish to continue?(y/n)"; + char y = 'a'; + while (y != 'n' && y != 'y') + std::cin >> y; + + if (y != 'y') + exit(1); + } + + inline void dh_warn(const char * const filename, const unsigned int lineNumber,const char *message) + { + std::cerr << "Warning to programmer." << std::endl; + std::cerr << "Filename: " << filename << std::endl; + std::cerr << "Line number: " << lineNumber << std::endl; + std::cerr << message << std::endl; + } + + //Debug timing routines + #define DEBUG_TIME_START() timeval TIME_DEBUG_t; gettimeofday(&TIME_DEBUG_t,NULL); + #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;} + #endif + + //A hack to generate compile time asserts (thanks Internet). + //This causes gcc to give "duplicate case value", if the predicate is false + #define COMPILE_ASSERT(pred) \ + switch(0){case 0:case pred:;} + + +#else + #define ASSERT(f) + #define COMPILE_ASSERT(f) + #define WARN(f,g) + #define TEST(f,g) + #define glError() + + +#endif + +#endif diff -Nru 3depict-0.0.12/src/common/basics.cpp 3depict-0.0.13/src/common/basics.cpp --- 3depict-0.0.12/src/common/basics.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/basics.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,1071 @@ +/* + * basics.cpp - basic functions 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 . +*/ + +#include "common/basics.h" + +#include "common/constants.h" + +#include "common/stringFuncs.h" + +#include "common/translation.h" + +#ifdef __APPLE__ + #include + #include + #include + #include +#elif defined __linux__ + //Needed for getting ram total usage under Linux + #include +#endif + +using std::string; +using std::vector; +using std::list; + + +//Name of the DTD file for state loading +const char *DTD_NAME="threeDepict-state.dtd"; +//Program name +const char *PROGRAM_NAME = "3Depict"; +//Program version +const char *PROGRAM_VERSION = "0.0.13"; +//Path to font for Default FTGL font +const char *FONT_FILE= "FreeSans.ttf"; + +const char *TEXT_LOAD_ERR_STRINGS[] = { "", + NTRANS("Error opening file"), + NTRANS("Error whilst reading file contents"), + NTRANS("Error interpreting field in file"), + NTRANS("Inconsistent number of columns found") + }; + +//default font to use. +std::string defaultFontFile; + +unsigned int getBitNum(unsigned int u) +{ + ASSERT(u); + unsigned int j=0; + while(!(u &1) ) + { + u=u>>1; + j++; + } + + return j; +} + +std::string boolStrEnc(bool b) +{ + if(b) + return "1"; + else + return "0"; +} + +bool rangesOverlap(size_t minA, size_t maxA, + size_t minB, size_t maxB) +{ + + ASSERT(minA <= maxA); + ASSERT(minB<=maxB); + + // A- B- A+ + // A- B+ A+ + if( (minA <= minB && maxA >=minB ) + || (minA<=maxB && maxA >=maxB) ) + return true; + + // B- A- B+ + // B- A+ B+ + if(( minB <= minA && maxB >=minA ) + || (minB<=maxA && maxB >=maxA) ) + return true; + + return false; + +} + +bool dummyCallback(bool) +{ + return true; +} + +void setDefaultFontFile(const std::string &font) +{ + defaultFontFile=font; +} + +std::string getDefaultFontFile() +{ + return defaultFontFile; +} + +//Compute the number of ticks require to achieve the +void tickSpacingsFromInterspace(float start, float end, + float interSpacing, std::vector &spacings) +{ + ASSERT(interSpacing > sqrt(std::numeric_limits::epsilon())); + unsigned int nTicks; + + if(end < start) + std::swap(end,start); + + nTicks=(unsigned int)((end-start)/interSpacing); + if(!nTicks) + { + ASSERT(!spacings.size()); + return; + } + + spacings.resize(nTicks); + for(unsigned int ui=0;ui &spacings) +{ + if(!nTicks) + { + ASSERT(!spacings.size()); + return; + } + + spacings.resize(nTicks+1); + + float delta; + delta= (end-start)/nTicks; + for(unsigned int ui=0;ui=2*TIMESTOPS[ui]) + { +#ifdef DEBUG + std::string s=(PLURAL_FUZZY_STRING[ui]); + ASSERT(s.size()); +#endif + return TRANS(PLURAL_FUZZY_STRING[ui]); + } + + //stop descending + if ( delta>=TIMESTOPS[ui]) + return TRANS(SINGLE_FUZZY_STRING[ui]); + } + + return TRANS("moments ago"); +} + +float BoundCube::getBound(unsigned int bound, unsigned int minMax) const +{ + ASSERT(bound <3 && minMax < 2); + ASSERT(valid[bound][minMax]==true); + return bounds[bound][minMax]; +} + +void BoundCube::setBound(unsigned int bound, unsigned int minMax, float value) +{ + ASSERT(bound <3 && minMax < 2); + bounds[bound][minMax]=value; + valid[bound][minMax]=true; +} + +void BoundCube::setBounds(const std::vector &points) +{ + + setInverseLimits(); + for(unsigned int ui=0; ui bounds[uj][1]) + { + { + bounds[uj][1] = points[ui].getValue(uj); + valid[uj][1]=true; + } + } + } + } + +#ifdef DEBUG + for(unsigned int ui=0; ui::max(); + bounds[1][0] = std::numeric_limits::max(); + bounds[2][0] = std::numeric_limits::max(); + + bounds[0][1] = -std::numeric_limits::max(); + bounds[1][1] = -std::numeric_limits::max(); + bounds[2][1] = -std::numeric_limits::max(); + + valid[0][0] =false; + valid[1][0] =false; + valid[2][0] =false; + + valid[0][1] =false; + valid[1][1] =false; + valid[2][1] =false; +} + +bool BoundCube::isValid() const +{ + for(unsigned int ui=0;ui<3; ui++) + { + if(!valid[ui][0] || !valid[ui][1]) + return false; + } + + return true; +} + +bool BoundCube::isFlat() const +{ + //Test the limits being inverted or equated + for(unsigned int ui=0;ui<3; ui++) + { + if(fabs(bounds[ui][0] - bounds[ui][1]) < std::numeric_limits::epsilon()) + return true; + } + + return false; +} + +bool BoundCube::isNumericallyBig() const +{ + const float TOO_BIG=sqrt(std::numeric_limits::max()); + for(unsigned int ui=0;ui<2; ui++) + { + for(unsigned int uj=0;uj<3; uj++) + { + if(TOO_BIG < fabs(bounds[uj][ui])) + return true; + } + } + return false; +} + +void BoundCube::expand(const BoundCube &b) +{ + //Check both lower and upper limit. + //Moving to other cubes value as needed + + if(!b.isValid()) + return; + + for(unsigned int ui=0; ui<3; ui++) + { + if(b.bounds[ui][0] < bounds[ui][0]) + { + bounds[ui][0] = b.bounds[ui][0]; + valid[ui][0] = true; + } + + if(b.bounds[ui][1] > bounds[ui][1]) + { + bounds[ui][1] = b.bounds[ui][1]; + valid[ui][1] = true; + } + } +} + +void BoundCube::expand(const Point3D &p) +{ + //If self not valid, ensure that it will be after this run + for(unsigned int ui=0; ui<3; ui++) + { + //Check lower bound is lower to new pt + if(bounds[ui][0] > p[ui]) + bounds[ui][0] = p[ui]; + + //Check upper bound is upper to new pt + if(bounds[ui][1] < p[ui]) + bounds[ui][1] = p[ui]; + } +} + +void BoundCube::expand(float f) +{ + //If self not valid, ensure that it will be after this run + for(unsigned int ui=0; ui<3; ui++) + { + //Check lower bound is lower to new pt + bounds[ui][0]-=f; + + //Check upper bound is upper to new pt + bounds[ui][1]+=f; + } +} + +void BoundCube::setBounds(const Point3D *p, unsigned int n) +{ + bounds[0][0] = std::numeric_limits::max(); + bounds[1][0] = std::numeric_limits::max(); + bounds[2][0] = std::numeric_limits::max(); + + bounds[0][1] = -std::numeric_limits::max(); + bounds[1][1] = -std::numeric_limits::max(); + bounds[2][1] = -std::numeric_limits::max(); + + for(unsigned int ui=0;ui p[ui][uj]) + { + bounds[uj][0] = p[ui][uj]; + valid[uj][0] = true; + } + + + if(bounds[uj][1] < p[ui][uj]) + { + bounds[uj][1] = p[ui][uj]; + valid[uj][1] = true; + } + } + } +} + +void BoundCube::setBounds( const Point3D &p1, const Point3D &p2) +{ + for(unsigned int ui=0; ui<3; ui++) + { + bounds[ui][0]=std::min(p1[ui],p2[ui]); + bounds[ui][1]=std::max(p1[ui],p2[ui]); + valid[ui][0]= true; + valid[ui][1]= true; + } + +} +void BoundCube::getBounds(Point3D &low, Point3D &high) const +{ + for(unsigned int ui=0; ui<3; ui++) + { + ASSERT(valid[ui][0] && valid[ui][1]); + low.setValue(ui,bounds[ui][0]); + high.setValue(ui,bounds[ui][1]); + } +} + +float BoundCube::getLargestDim() const +{ + float f; + f=getSize(0); + f=std::max(getSize(1),f); + return std::max(getSize(2),f); +} + +bool BoundCube::containsPt(const Point3D &p) const +{ + for(unsigned int ui=0; ui<3; ui++) + { + ASSERT(valid[ui][0] && valid[ui][1]); + if(p.getValue(ui) < bounds[ui][0] || p.getValue(ui) > bounds[ui][1]) + return false; + } + return true; +} + +float BoundCube::getSize(unsigned int dim) const +{ + ASSERT(dim < 3); +#ifdef DEBUG + for(unsigned int ui=0;ui<3; ui++) + { + ASSERT(valid[0][1] && valid [0][0]); + } +#endif + return fabs(bounds[dim][1] - bounds[dim][0]); +} + +//checks intersection with sphere [centre,centre+radius) +bool BoundCube::intersects(const Point3D &pt, float sqrRad) +{ + Point3D nearPt; + + //Find the closest point on the cube to the sphere + for(unsigned int ui=0;ui<3;ui++) + { + if(pt.getValue(ui) <= bounds[ui][0]) + { + nearPt.setValue(ui,bounds[ui][0]); + continue; + } + + if(pt.getValue(ui) >=bounds[ui][1]) + { + nearPt.setValue(ui,bounds[ui][1]); + continue; + } + + nearPt.setValue(ui,pt[ui]); + } + + //now test the distance from nrPt to pt + //Note that the touching case is considered to be an intersection + return (nearPt.sqrDist(pt) <=sqrRad); +} + +Point3D BoundCube::getCentroid() const +{ +#ifdef DEBUG + for(unsigned int ui=0;ui<3; ui++) + { + ASSERT(valid[ui][1] && valid [ui][0]); + } +#endif + return Point3D(bounds[0][1] + bounds[0][0], + bounds[1][1] + bounds[1][0], + bounds[2][1] + bounds[2][0])/2.0f; +} + +float BoundCube::getMaxDistanceToBox(const Point3D &queryPt) const +{ +#ifdef DEBUG + for(unsigned int ui=0;ui<3; ui++) + { + ASSERT(valid[ui][1] && valid [ui][0]); + } +#endif + + float maxDistSqr=0.0f; + + + //Set lower and upper corners on the bounding rectangle + Point3D p[2]; + p[0] = Point3D(bounds[0][0],bounds[1][0],bounds[2][0]); + p[1] = Point3D(bounds[0][1],bounds[1][1],bounds[2][1]); + + //Count binary-wise selecting upper and lower limits, to enumerate all 8 vertices. + for(unsigned int ui=0;ui<9; ui++) + { + maxDistSqr=std::max(maxDistSqr, + queryPt.sqrDist(Point3D(p[ui&1][0],p[(ui&2) >> 1][1],p[(ui&4) >> 2][2]))); + } + + return sqrtf(maxDistSqr); +} + +bool BoundCube::containedInSphere(const Point3D &queryPt,float sqrDist) const +{ +#ifdef DEBUG + for(unsigned int ui=0;ui<3; ui++) + { + ASSERT(valid[ui][1] && valid [ui][0]); + } +#endif + + + //Set lower and upper corners on the bounding rectangle + Point3D p[2]; + p[0].setValue(bounds[0][0],bounds[1][0],bounds[2][0]); + p[1].setValue(bounds[0][1],bounds[1][1],bounds[2][1]); + + //Count binary-wise selecting upper and lower limits, to enumerate all 8 verticies. + for(unsigned int ui=0;ui<9; ui++) + { + if(queryPt.sqrDist(Point3D(p[ui&1][0],p[(ui&2) >> 1][1],p[(ui&4) >> 2][2])) > sqrDist) + return false; + } + + return true; +} + +const BoundCube &BoundCube::operator=(const BoundCube &b) +{ + for(unsigned int ui=0;ui<3; ui++) + { + for(unsigned int uj=0;uj<2; uj++) + { + valid[ui][uj] = b.valid[ui][uj]; + bounds[ui][uj] = b.bounds[ui][uj]; + + } + } + + return *this; +} + +std::ostream &operator<<(std::ostream &stream, const BoundCube& b) +{ + stream << "Bounds :Low ("; + stream << b.bounds[0][0] << ","; + stream << b.bounds[1][0] << ","; + stream << b.bounds[2][0] << ") , High ("; + + stream << b.bounds[0][1] << ","; + stream << b.bounds[1][1] << ","; + stream << b.bounds[2][1] << ")" << std::endl; + + + stream << "Bounds Valid: Low ("; + stream << b.valid[0][0] << ","; + stream << b.valid[1][0] << ","; + stream << b.valid[2][0] << ") , High ("; + + stream << b.valid[0][1] << ","; + stream << b.valid[1][1] << ","; + stream << b.valid[2][1] << ")" << std::endl; + + return stream; +} + +bool getFilesize(const char *fname, size_t &size) +{ + std::ifstream f(fname,std::ios::binary); + + if(!f) + return false; + + f.seekg(0,std::ios::end); + + size = f.tellg(); + + return true; +} + +void UniqueIDHandler::clear() +{ + idList.clear(); +} + +unsigned int UniqueIDHandler::getPos(unsigned int id) const +{ + + for(list >::const_iterator it=idList.begin(); + it!=idList.end(); ++it) + { + if(id == it->second) + return it->first; + } + ASSERT(false); + return 0; +} + +void UniqueIDHandler::killByPos(unsigned int pos) +{ + for(list >::iterator it=idList.begin(); + it!=idList.end(); ++it) + { + if(pos == it->first) + { + idList.erase(it); + break; + } + } + + //Decrement the items, which were further along, in order to maintain the mapping + for(list >::iterator it=idList.begin(); + it!=idList.end(); ++it) + { + if( it->first > pos) + it->first--; + } +} + +unsigned int UniqueIDHandler::getId(unsigned int pos) const +{ + for(list >::const_iterator it=idList.begin(); + it!=idList.end(); ++it) + { + if(pos == it->first) + return it->second; + } + + ASSERT(false); + return 0; +} + +unsigned int UniqueIDHandler::genId(unsigned int pos) +{ + + //Look for each element number as a unique value in turn + //This is guaranteed to return by the pigeonhole principle (we are testing + //a target set (note <=)). + for(unsigned int ui=0;ui<=idList.size(); ui++) + { + bool idTaken; + idTaken=false; + for(list >::iterator it=idList.begin(); + it!=idList.end(); ++it) + { + if(ui == it->second) + { + idTaken=true; + break; + } + } + + if(!idTaken) + { + idList.push_back(std::make_pair(pos,ui)); + return ui; + } + } + + ASSERT(false); + return 0; +} + +void UniqueIDHandler::getIds(std::vector &idVec) const +{ + //most wordy way of saying "spin through list" ever. + for(list >::const_iterator it=idList.begin(); + it!=idList.end(); ++it) + idVec.push_back(it->second); +} + + + +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + #include + //Windows.h is a nasty name clashing horrible thing. + //Put it last to avoid clashing with std:: stuff (eg max & min) + +#endif + +// Total ram in MB +int getTotalRAM() +{ +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + int ret; + MEMORYSTATUS MemStat; + + // Zero structure + memset(&MemStat, 0, sizeof(MemStat)); + + // Get RAM snapshot + ::GlobalMemoryStatus(&MemStat); + ret= MemStat.dwTotalPhys / (1024*1024); + return ret; +#elif __APPLE__ || __FreeBSD__ + + int ret; + uint64_t mem; + size_t len = sizeof(mem); + + sysctlbyname("hw.physmem", &mem, &len, NULL, 0); + + ret = (int)(mem/(1024*1024)); + return ret; +#elif __linux__ + struct sysinfo sysInf; + sysinfo(&sysInf); + return ((size_t)(sysInf.totalram)*(size_t)(sysInf.mem_unit)/(1024*1024)); +#else + #error Unknown platform, no getTotalRAM function defined. +#endif +} + +size_t getAvailRAM() +{ +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + int ret ; + MEMORYSTATUS MemStat; + // Zero structure + memset(&MemStat, 0, sizeof(MemStat)); + + // Get RAM snapshot + ::GlobalMemoryStatus(&MemStat); + ret= MemStat.dwAvailPhys / (1024*1024); + return ret; + +#elif __APPLE__ || __FreeBSD__ + int ret ; + uint64_t memsize; + + size_t pagesize; + mach_port_t sls_port = mach_host_self(); + mach_msg_type_number_t vmCount = HOST_VM_INFO_COUNT; + vm_statistics_data_t vm; + kern_return_t error; + + error = host_statistics(sls_port , HOST_VM_INFO , (host_info_t) &vm, &vmCount); + pagesize = (unsigned long)sysconf(_SC_PAGESIZE); + memsize = (vm.free_count + vm.inactive_count) * pagesize;//(vm.wire_count + vm.active_count + vm.inactive_count + vm.free_count + vm.zero_fill_count ) * pagesize; + ret = (size_t)(memsize/(1024*1024)); + return ret; +#elif __linux__ + struct sysinfo sysInf; + sysinfo(&sysInf); + + return ((size_t)(sysInf.freeram + sysInf.bufferram)*(size_t)(sysInf.mem_unit)/(1024*1024)); +#else + #error Unknown platform, no getAvailRAM function defined. +#endif +} + +bool strhas(const char *cpTest, const char *cpPossible) +{ + while(*cpTest) + { + const char *search; + search=cpPossible; + while(*search) + { + if(*search == *cpTest) + return true; + search++; + } + cpTest++; + } + + return false; +} + +//A routine for loading numeric data from a text file +unsigned int loadTextData(const char *cpFilename, vector > &dataVec,vector &headerVec, const char *delim) +{ + const unsigned int BUFFER_SIZE=4096; + char inBuffer[BUFFER_SIZE]; + + unsigned int num_fields=0; + + dataVec.clear(); + //Open a file in text mode + std::ifstream CFile(cpFilename); + + if(!CFile) + return ERR_FILE_OPEN; + + //Drop the headers, if any + string str; + vector strVec; + bool atHeader=true; + + vector prevStrs; + while(!CFile.eof() && atHeader) + { + //Grab a line from the file + CFile.getline(inBuffer,BUFFER_SIZE); + + if(!CFile.good()) + return ERR_FILE_FORMAT; + + prevStrs=strVec; + //Split the strings around the deliminator c + splitStrsRef(inBuffer,delim,strVec); + stripZeroEntries(strVec); + + + //Skip blank lines or lines that are only spaces + if(strVec.empty()) + continue; + + num_fields = strVec.size(); + dataVec.resize(num_fields); + //Check to see if we are in the header + if(atHeader) + { + //If we have the right number of fields + //we might be not in the header anymore + if(num_fields >= 1 && strVec[0].size()) + { + float f; + //Assume we are not reading the header + atHeader=false; + + vector values; + //Confirm by checking all values + for(unsigned int ui=0; ui> f; + if(ss.fail()) + return ERR_FILE_FORMAT; + dataVec[ui].push_back(f); + + } + //========= + + } + //Grab a line from the file + CFile.getline(inBuffer,BUFFER_SIZE); + + if(!CFile.good() && !CFile.eof()) + return ERR_FILE_FORMAT; + } + + return 0; +} + +unsigned int loadTextStringData(const char *cpFilename, vector > &dataVec,const char *delim) +{ + const unsigned int BUFFER_SIZE=4096; + + dataVec.clear(); + //Open a file in text mode + std::ifstream CFile(cpFilename); + + if(!CFile) + return ERR_FILE_OPEN; + + char *inBuffer= new char[BUFFER_SIZE]; + //Grab a line from the file + CFile.getline(inBuffer,BUFFER_SIZE); + while(!CFile.eof()) + { + vector strVec; + strVec.clear(); + + //Split the strings around the tab char + splitStrsRef(inBuffer,delim,strVec); + stripZeroEntries(strVec); + + //Check the number of fields + //========= + if(strVec.size()) + dataVec.push_back(strVec); + //========= + + //Grab a line from the file + CFile.getline(inBuffer,BUFFER_SIZE); + + if(!CFile.good() && !CFile.eof()) + return ERR_FILE_FORMAT; + } + + return 0; +} + +#ifdef DEBUG +bool isValidXML(const char *filename) +{ + //Debug check to ensure we have written a valid xml file + std::string command; + unsigned int result; + +//Windows doesn't really have a /dev/null device, rather it has a reserved file name "NUL" or "nul" +//http://technet.microsoft.com/en-gb/library/cc961816.aspx +#if defined(WIN32) || defined(WIN64) + command = std::string("xmllint --version > NUL 2> NUL"); +#else + command = std::string("xmllint --version >/dev/null 2>/dev/null"); +#endif + result=system(command.c_str()); + if(!result) + { + //Windows' shell handles escapes differently, workaround + #if defined(WIN32) || defined(WIN64) + command = std::string("xmllint --noout \"") + filename + string("\""); + #else + command = std::string("xmllint --noout \'") + filename + string("\'"); + #endif + result=system(command.c_str()); + return result ==0; + } + + //Debug check ineffective + WARN(!result,"xmllint not installed in system PATH, cannot perform debug check") + return true; +} +#endif + + diff -Nru 3depict-0.0.12/src/common/basics.h 3depict-0.0.13/src/common/basics.h --- 3depict-0.0.12/src/common/basics.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/basics.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,723 @@ +/* + * common/basics.h - Basic functionality 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 . +*/ + + +#ifndef BASICS_H +#define BASICS_H +//!Basic objects header file + +#include "mathfuncs.h" +#include "common/assertion.h" + + +#include +#include +#include +#include +#include + +class K3DTree; + + +bool dummyCallback(bool); + +extern const char *DTD_NAME; +extern const char *PROGRAM_NAME; +extern const char *PROGRAM_VERSION; +extern const char *FONT_FILE; + + + + +//C file peek function +inline int fpeek(FILE *stream) +{ + int c; + + c = fgetc(stream); + ungetc(c, stream); + + return c; +} + +bool rangesOverlap(size_t minA, size_t maxA, + size_t minB, size_t maxB); + + +//!Text file loader errors +enum +{ + ERR_FILE_OPEN=1, + ERR_FILE_FORMAT, + ERR_FILE_NUM_FIELDS, + ERR_FILE_ENUM_END // not an error, just end of enum +}; + +extern const char *TEXT_LOAD_ERR_STRINGS[]; + + +template +bool hasFirstInPairVec(const std::vector > &v, const std::pair &r) +{ + for(size_t ui=0;ui &spacings); + +void tickSpacingsFromFixedNum(float start, float end, + unsigned int nTicks, std::vector &spacings); + +//!Get a "human-like" version of the time elapsed between new and original time period +std::string veryFuzzyTimeSince( time_t origTime, time_t newTime); + + +//!A routine for loading numeric data from a text file +unsigned int loadTextData(const char *cpFilename, + std::vector > &dataVec, + std::vector &header,const char *delim); + +//!Load non-numeric data from a text file into ragged array, using specified delimiters +unsigned int loadTextStringData(const char *cpFilename, + std::vector > &dataVec, + const char *delim); + + +template +bool writeTextFile(const char *cpFilename, + const std::vector > &dataVec, const char delim='\t') +{ + std::ofstream f(cpFilename); + + if(!f) + return false; + + for(unsigned int ui=0;ui bool stream_cast(T1 &result, const T2 &obj) +{ + std::stringstream ss; + ss << obj; + ss >> result; + return ss.fail(); +} + +//!Replace first instance of marker with null terminator +void nullifyMarker(char *buffer, char marker); + +//retrieve the active bit in a power of two sequence +unsigned int getBitNum(unsigned int u); + +//!A class to manage "tear-off" ID values, to allow for indexing without knowing position. +//You simply ask for a new unique ID. and it maintains the position->ID mapping +// as position could change if an element was removed, but ID cannot +//TODO: Extend to any unique type, rather than just int (think iterators..., pointers) +class UniqueIDHandler +{ + private: + //!position-ID pairings + std::list > idList; + + public: + //!Generate a unique ID value, storing the position ID pair + unsigned int genId(unsigned int position); + //!Remove a uniqueID using its position + void killByPos(unsigned int position); + //!Get the position from its unique ID + unsigned int getPos(unsigned int id) const; + //!Get the uniqueID from the position + unsigned int getId(unsigned int pos) const; + + //!Get all unique IDs + void getIds(std::vector &idvec) const; + //!Clear the mapping + void clear(); + //!Get the number of elements stored + unsigned int size() const {return idList.size();}; +}; + +//!Get total filesize in bytes +bool getFilesize(const char *fname, size_t &size); + +//!get total ram in MB +int getTotalRAM(); + +//!Get available ram in MB +size_t getAvailRAM(); + + +#ifdef DEBUG +bool isValidXML(const char *filename); +#endif + + +class ComparePairFirst +{ + public: + template + bool operator()(const std::pair< T1, T2 > &p1, const std::pair &p2) const + { + return p1.first< p2.first; + } +}; + +class ComparePairSecond +{ + public: + template + bool operator()(const std::pair< T1, T2 > &p1, const std::pair &p2) const + { + return p1.second< p2.second; + } +}; + + +class ComparePairFirstReverse +{ + public: + template + bool operator()(const std::pair< T1, T2 > &p1, const std::pair &p2) const + { + return p1.first> p2.first; + } +}; + +//! A helper class to define a bounding cube +class BoundCube +{ + //!bounding values (x,y,z) (lower,upper) + float bounds[3][2]; + //!Is the cube set? + bool valid[3][2]; +public: + + BoundCube() { + setInvalid(); + } + + void setBounds(float xMin,float yMin,float zMin, + float xMax,float yMax,float zMax) { + bounds[0][0]=xMin; bounds[1][0]=yMin; bounds[2][0]=zMin; + bounds[0][1]=xMax; bounds[1][1]=yMax; bounds[2][1]=zMax; + valid[0][0]=true; valid[1][0]=true; valid[2][0]=true; + valid[0][1]=true; valid[1][1]=true; valid[2][1]=true; + } + + void setBounds(const BoundCube &b) + { + for(unsigned int ui=0;ui<3;ui++) + { + bounds[ui][0] = b.bounds[ui][0]; + valid[ui][0] = b.valid[ui][0]; + bounds[ui][1] = b.bounds[ui][1]; + valid[ui][1] = b.valid[ui][1]; + } + } + void setInvalid() + { + valid[0][0]=false; valid[1][0]=false; valid[2][0]=false; + valid[0][1]=false; valid[1][1]=false; valid[2][1]=false; + } + + //Set the cube to be "inside out" at the limits of numeric results; + void setInverseLimits(); + + void setBound(unsigned int bound, unsigned int minMax, float value) ; + + //Retrieve a specified bound, minMax=0 for min, =1 for max + float getBound(unsigned int bound, unsigned int minMax) const ; + //!Return the centroid + Point3D getCentroid() const; + + //!Get the bounds + void getBounds(Point3D &low, Point3D &high) const ; + + //!Return the size + float getSize(unsigned int dim) const; + + //! Returns true if all bounds are valid + bool isValid() const; + + //! Returns true if any bound is of null thickness + bool isFlat() const; + + //!Returns true if any bound of datacube is considered to be "large" in magnitude compared to + // floating pt data type. + bool isNumericallyBig() const; + + //!Obtain bounds from an array of Point3Ds + void setBounds( const Point3D *ptArray, unsigned int nPoints); + //!Use two points to set bounds -- does not need to be high,low. this is worked out/ + void setBounds( const Point3D &p, const Point3D &q); + //!Obtain bounds from an array of Point3Ds + void setBounds(const std::vector &ptArray); + //!Checks if a point intersects a sphere of centre Pt, radius^2 sqrRad + bool intersects(const Point3D &pt, float sqrRad); + //Check to see if the point is contained in, or part of the walls + //of the cube + bool containsPt(const Point3D &pt) 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; + + //!Returns maximum distnace to box corners (which is an upper bound on max box distance). + //Bounding box must be valid. + float getMaxDistanceToBox(const Point3D &pt) const; + + //Get the largest dimension of the bound cube + float getLargestDim() const; + + //Return the rectilinear volume represented by this prism. + float volume() const { return (bounds[0][1] - bounds[0][0])* + (bounds[1][1] - bounds[1][0])*(bounds[2][1] - bounds[2][0]);} + void limits(); + const BoundCube &operator=(const BoundCube &); + //!Expand (as needed) volume such that the argument bounding cube is enclosed by this one + void expand(const BoundCube &b); + //!Expand such that point is contained in this volume. Existing volume must be valid + void expand(const Point3D &p); + //!Expand by a specified thickness + void expand(float v); + + + friend std::ostream &operator<<(std::ostream &stream, const BoundCube& b); + + //FIXME: Hack! + friend class K3DTree; + friend class K3DTreeMk2; +}; + + + + +//OK, this is a bit tricky. We override the operators to call +//a callback, so the UI updates keep happening, even inside the STL function +//---- +template +class GreaterWithCallback +{ + private: + bool (*callback)(bool); + //!Reduction frequency (use callback every k its) + unsigned int redMax; + //!Current reduction counter + unsigned int reduction; + //!pointer to progress value + unsigned int *prgPtr; + public: + //!Second argument is a "reduction" value to set the number of calls + //to the random functor before initiating a callback + GreaterWithCallback( bool (*ptr)(bool),unsigned int red) : callback(ptr), redMax(red), reduction(red) + {}; + + bool operator()(const T &a, const T &b) + { + if(!reduction--) + { + reduction=redMax; + //Execute callback + (*callback)(false); + } + + return a < b; + } +}; + + +template +class EqualWithCallback +{ + private: + bool (*callback)(bool); + //!Reduction frequency (use callback every k its) + unsigned int redMax; + //!Current reduction counter + unsigned int reduction; + //!pointer to progress value + unsigned int *prgPtr; + public: + //!Second argument is a "reduction" value to set the number of calls + //to the random functor before initiating a callback + EqualWithCallback( bool (*ptr)(bool),unsigned int red) : callback(ptr), redMax(red), reduction(red) + { }; + + bool operator()(const T &a, const T &b) + { + if(!reduction--) + { + reduction=redMax; + //Execute callback + (*callback)(false); + } + + return a ==b; + } +}; +//---- + + +//Randomly select subset. Subset will be (somewhat) sorted on output +template size_t randomSelect(std::vector &result, const std::vector &source, + RandNumGen &rng, size_t num,unsigned int &progress,bool (*callback)(bool), bool strongRandom=false) +{ + const unsigned int NUM_CALLBACK=50000; + //If there are not enough points, just copy it across in whole + if(source.size() <= num) + { + num=source.size(); + result.resize(source.size()); + for(size_t ui=0; ui ticks; + ticks.resize(numTicksNeeded); + + //Create an array of numTicksNeededbers and fill + for(size_t ui=0; ui gFunctor(callback,50000); + std::sort(ticks.begin(),ticks.end(),gFunctor); + EqualWithCallback eqFunctor(callback,50000); + std::vector::iterator newLast; + newLast=std::unique(ticks.begin(),ticks.end()); + ticks.erase(newLast,ticks.end()); + + std::vector moreTicks; + //Top up with unique entries + while(ticks.size() +moreTicks.size() < numTicksNeeded) + { + size_t index; + + //This is actually not too bad. the collision probability is at most 50% + //due the switching behaviour above, for any large number of items + //So this is at worst case nlog(n) (I think) + index =(size_t)(rng.genUniformDev()*(float)(source.size()-1)); + if(!binary_search(ticks.begin(),ticks.end(),index) && + std::find(moreTicks.begin(),moreTicks.end(),index) ==moreTicks.end()) + moreTicks.push_back(index); + + } + + ticks.reserve(numTicksNeeded); + for(size_t ui=0;ui::iterator it=ticks.begin();it!=ticks.end();++it) + { + + result[pos]=source[*it]; + pos++; + if(!curProg--) + { + progress= (unsigned int)((float)(pos)/((float)num)*100.0f); + (*callback)(false); + curProg=NUM_CALLBACK; + } + } + } + else + { + //Sort the ticks properly (mostly sorted anyway..) + std::sort(ticks.begin(),ticks.end(),gFunctor); + + unsigned int curTick=0; + for(size_t ui=0;ui (ui-curTick)); + result[ui-curTick]=source[ui]; + } + + if(!curProg--) + { + progress= (unsigned int)(((float)(ui)/(float)source.size())*100.0f); + (*callback)(false); + curProg=NUM_CALLBACK; + } + } + } + + ticks.clear(); + } + else + { + //Use a weak randomisation + LinearFeedbackShiftReg l; + + //work out the mask level we need to use + size_t i=1; + unsigned int j=0; + while(i < (source.size()<<1)) + { + i=i<<1; + j++; + } + + //linear shift table starts at 3. + if(j<3) { + j=3; + i = 1 << j; + } + + size_t start; + //start at a random position in the linear state + start =(size_t)(rng.genUniformDev()*i); + l.setMaskPeriod(j); + l.setState(start); + + size_t ui=0; + unsigned int curProg=NUM_CALLBACK; + //generate unique weak random numbers. + while(ui size_t randomDigitSelection(std::vector &result, const size_t max, + RandNumGen &rng, size_t num,unsigned int &progress,bool (*callback)(bool), + bool strongRandom=false) +{ + //If there are not enough points, just copy it across in whole + if(max <=num) + { + num=max; + result.resize(max); + for(size_t ui=0; ui ticks; + ticks.resize(numTicksNeeded); + + //Create an array of numbers and fill + for(size_t ui=0; ui gFunctor(callback,50000); + std::sort(ticks.begin(),ticks.end(),gFunctor); + EqualWithCallback eqFunctor(callback,50000); + + std::vector::iterator itLast; + itLast=std::unique(ticks.begin(),ticks.end(),eqFunctor); + ticks.erase(itLast,ticks.end()); + std::vector moreTicks; + //Top up with unique entries + while(ticks.size() +moreTicks.size() < numTicksNeeded) + { + size_t index; + + //This is actually not too bad. the collision probability is at most 50% + //due the switching behaviour above, for any large number of items + //So this is at worst case nlog(n) (I think) + index =(size_t)(rng.genUniformDev()*(float)(max-1)); + if(!binary_search(ticks.begin(),ticks.end(),index) && + std::find(moreTicks.begin(),moreTicks.end(),index) ==moreTicks.end()) + moreTicks.push_back(index); + + } + + ticks.reserve(numTicksNeeded); + for(size_t ui=0;ui::iterator it=ticks.begin();it!=ticks.end();++it) + { + + result[pos]=*it; + pos++; + if(!curProg--) + { + progress= (unsigned int)((float)(curProg)/((float)num)*100.0f); + (*callback)(false); + curProg=CURPROG; + } + } + } + else + { + //Sort the ticks properly (mostly sorted anyway..) + std::sort(ticks.begin(),ticks.end(),gFunctor); + + unsigned int curTick=0; + for(size_t ui=0;ui. +*/ + + +#include +#include +#include "colourmap.h" +#include + +#include "common/translation.h" + +void jetColorMap(unsigned char *rgb,float value,float min,float max) +{ + float max4=(max-min)/4; + value-=min; + if (value==HUGE_VAL) + { + rgb[0]=rgb[1]=rgb[2]=255; + } + else if (value<0) + { + rgb[0]=rgb[1]=rgb[2]=0; + } + else if (value1){ + rgb[0]=rgb[1]=rgb[2]=255; + return; + } + + rgb[0]=192;rgb[1]=0;rgb[2]=0; + rgb[0]+=(unsigned char)(63*value); + rgb[1]+=(unsigned char)(255*value); + if(value>0.5) + rgb[2]+=(unsigned char)(255*2*(value-0.5)); +} + +void negativeColorMap(unsigned char *rgb,float value,float min,float max) +{ + value-=min; + max-=min; + rgb[0]=0;rgb[1]=0;rgb[2]=0; + + if(max>std::numeric_limits::epsilon()) + value/=max; + if(value<0) return; + if(value>1){ + rgb[1]=rgb[2]=255; + return; + } + + rgb[1]+=(unsigned char)(255*value); + if(value>0.5) + rgb[2]+=(unsigned char)(255*2*(value-0.5)); + +} + +void colorMap(unsigned char *rgb,float value,float min,float max) +{ + if(value>0) + positiveColorMap(rgb,value,0,max); + else + negativeColorMap(rgb,value,min,0); +} + +void cyclicColorMap(unsigned char *rgb,float value,float min,float max) +{ + float max3=(max-min)/3; + value-=(max-min)*(float)floor((value-min)/(max-min)); + if(value. +*/ + +#ifndef _COLORMAP_H_ +#define _COLORMAP_H_ + +#include + +const unsigned int NUM_COLOURMAPS=8; + +//!get colour for specific map +/* 0 jetColorMap | 5 colorMap + * 1 hotColorMap | 6 blueColorMap + * 2 coldColorMap | 7 randColorMap + * 3 grayColorMap | + * 4 cyclicColorMap | + * + * returns char in 0->255 range + */ +void colourMapWrap(unsigned int mapID,unsigned char *rgb, float value, float min,float max); + +std::string getColourMapName(unsigned int mapID); + +#endif + diff -Nru 3depict-0.0.12/src/common/constants.h 3depict-0.0.13/src/common/constants.h --- 3depict-0.0.12/src/common/constants.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/constants.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * common/constants.h - Common constants used across program + * 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 . + */ +#ifndef COMMONCONSTANTS_H +#define COMMONCONSTANTS_H + +//C-style Array size macro +#define THREEDEP_ARRAYSIZE(f) (sizeof (f) / sizeof(*f)) +//C++1x availabilty (as far as we are concerned) +#if __cplusplus > 199711L + #define HAVE_CPP1X 1 +#endif + +enum +{ + PLOT_TRACE_LINES=0, + PLOT_TRACE_BARS, + PLOT_TRACE_STEPS, + PLOT_TRACE_STEM, + PLOT_TRACE_POINTS, + PLOT_TRACE_ENDOFENUM +}; + +//Plot types +enum +{ + PLOT_MODE_1D, + PLOT_MODE_2D, + PLOT_MODE_ENUM_END +}; + + +//Plot error types +enum +{ + PLOT_ERROR_NONE, + PLOT_ERROR_MOVING_AVERAGE, + PLOT_ERROR_ENDOFENUM +}; + +//!State file output formats +enum +{ + STATE_FORMAT_XML=1 +}; + +//!Property types for wxPropertyGrid +enum +{ + PROPERTY_TYPE_BOOL=1, + PROPERTY_TYPE_INTEGER, + PROPERTY_TYPE_REAL, + PROPERTY_TYPE_COLOUR, + PROPERTY_TYPE_STRING, + PROPERTY_TYPE_POINT3D, + PROPERTY_TYPE_CHOICE, + PROPERTY_TYPE_ENUM_END //Not a prop, just end of enum +}; + + +//!Movement types for plot +enum +{ + REGION_MOVE_EXTEND_XMINUS, + REGION_MOVE_TRANSLATE_X, + REGION_MOVE_EXTEND_XPLUS +}; + + +//!Structure to handle error bar drawing in plot +struct PLOT_ERROR +{ + //!Plot data estimator mode + unsigned int mode; + //!Number of data points for moving average + unsigned int movingAverageNum; + //!Edge mode + unsigned int edgeMode; +}; + +#endif diff -Nru 3depict-0.0.12/src/common/endianTest.h 3depict-0.0.13/src/common/endianTest.h --- 3depict-0.0.12/src/common/endianTest.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/endianTest.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * endianttest.h - Platform endian testing + * 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 . +*/ + +#ifndef _ENDIAN_TEST_H_ +#define _ENDIAN_TEST_H_ +#if defined (_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#define __LITTLE_ENDIAN__ +#else +#ifdef __linux__ +#include +#endif +#endif + +#ifdef __BYTE_ORDER +//if both are not defined it is TRUE! +#if __BYTE_ORDER == __BIG_ENDIAN +#ifndef __BIG_ENDIAN__ +#define __BIG_ENDIAN__ +#endif +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#ifndef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ +#endif +#elif __BYTE_ORDER == __PDP_ENDIAN +#ifndef __ARM_ENDIAN__ +#define __ARM_ENDIAN__ +#endif +#else +#error "Endian determination failed" +#endif +#endif + +const int ENDIAN_TEST=1; +//Run-time detection +inline int is_bigendian() { return (*(char*)&ENDIAN_TEST) == 0 ;} + +inline int is_littleendian() { return (*(char*)&ENDIAN_TEST) == 1 ;} + + +inline void floatSwapBytes(float *inFloat) +{ + //Use a union to avoid strict-aliasing error + union FloatSwapUnion{ + float f; + char c[4]; + } ; + FloatSwapUnion fa,fb; + fa.f = *inFloat; + + fb.c[0] = fa.c[3]; + fb.c[1] = fa.c[2]; + fb.c[2] = fa.c[1]; + fb.c[3] = fa.c[0]; + + *inFloat=fb.f; +} + +#endif diff -Nru 3depict-0.0.12/src/common/mathfuncs.cpp 3depict-0.0.13/src/common/mathfuncs.cpp --- 3depict-0.0.12/src/common/mathfuncs.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/mathfuncs.cpp 2013-04-10 20:41:55.000000000 +0000 @@ -0,0 +1,763 @@ +/* + * mathfuncs.cpp - Miscellaneous mathematical functions implementation. + * 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 . +*/ + +#include "../config.h" + +#include "common/basics.h" +#include "common/stringFuncs.h" + +#include + +using std::string; +using std::vector; + +const int MBIG = std::numeric_limits::max(); + +void Point3D::copyValueArr(float *valArr) const +{ + ASSERT(valArr); + //compiler should unroll this automatically + for(unsigned int ui=0; ui<3; ui++) + { + *(valArr+ui) = *(value+ui); + } +} + +float Point3D::operator[](unsigned int ui) const +{ + ASSERT(ui < 3); + return value[ui]; +} + +float &Point3D::operator[](unsigned int ui) +{ + ASSERT(ui < 3); + return value[ui]; +} + +bool Point3D::operator==(const Point3D &pt) const +{ + return (value[0] == pt.value[0] && value[1] == pt.value[1] && value[2] == pt.value[2]); +} + +const Point3D &Point3D::operator=(const Point3D &pt) +{ + value [0] = pt.value[0]; + value [1] = pt.value[1]; + value [2] = pt.value[2]; + return *this; +} + +const Point3D &Point3D::operator+=(const Point3D &pt) +{ + for(unsigned int ui=0;ui<3; ui++) + value[ui]+= pt.value[ui]; + + return *this; +} + +const Point3D Point3D::operator+(const Point3D &pt) const +{ + Point3D ptTmp; + + for(unsigned int ui=0;ui<3; ui++) + ptTmp.value[ui] = value[ui] + pt.value[ui]; + + return ptTmp; +} + +const Point3D Point3D::operator+(float f) const +{ + Point3D pTmp; + for(unsigned int ui=0;ui<3; ui++) + pTmp.value[ui] = value[ui] + f; + + return pTmp; +} + +const Point3D Point3D::operator-(const Point3D &pt) const +{ + Point3D ptTmp; + + for(unsigned int ui=0;ui<3; ui++) + ptTmp.value[ui] = value[ui] - pt.value[ui]; + + return ptTmp; +} + +const Point3D Point3D::operator-() const +{ + Point3D ptTmp; + + for(unsigned int ui=0;ui<3; ui++) + ptTmp.value[ui] = -value[ui]; + + return ptTmp; +} + +const Point3D &Point3D::operator*=(const float scale) +{ + value[0] = value[0]*scale; + value[1] = value[1]*scale; + value[2] = value[2]*scale; + + return *this; +} + +const Point3D Point3D::operator*(float scale) const +{ + Point3D tmpPt; + + tmpPt.value[0] = value[0]*scale; + tmpPt.value[1] = value[1]*scale; + tmpPt.value[2] = value[2]*scale; + + return tmpPt; +} + +const Point3D Point3D::operator*(const Point3D &pt) const +{ + Point3D tmpPt; + + tmpPt.value[0] = value[0]*pt[0]; + tmpPt.value[1] = value[1]*pt[1]; + tmpPt.value[2] = value[2]*pt[2]; + + return tmpPt; +} + +const Point3D Point3D::operator/(float scale) const +{ + Point3D tmpPt; + + scale = 1.0f/scale; + tmpPt.value[0] = value[0]*scale; + tmpPt.value[1] = value[1]*scale; + tmpPt.value[2] = value[2]*scale; + + return tmpPt; +} + +float Point3D::sqrDist(const Point3D &pt) const +{ + return (pt.value[0]-value[0])*(pt.value[0]-value[0])+ + (pt.value[1]-value[1])*(pt.value[1]-value[1])+ + (pt.value[2]-value[2])*(pt.value[2]-value[2]); +} + +float Point3D::dotProd(const Point3D &pt) const +{ + //Return the inner product + return value[0]*pt.value[0] + value[1]*pt.value[1] + value[2]*pt.value[2]; +} + +Point3D Point3D::crossProd(const Point3D &pt) const +{ + Point3D cross; + + cross.value[0] = (pt.value[2]*value[1] - pt.value[1]*value[2]); + cross.value[1] = -(value[0]*pt.value[2] - pt.value[0]*value[2]); + cross.value[2] = (value[0]*pt.value[1] - value[1]*pt.value[0]); + + return cross; +} + +bool Point3D::insideBox(const Point3D &farPoint) const +{ + + return (value[0] < farPoint.value[0] && value[0] >=0) && + (value[1] < farPoint.value[1] && value[1] >=0) && + (value[2] < farPoint.value[2] && value[2] >=0); +} + +bool Point3D::insideBox(const Point3D &lowPt,const Point3D &highPt) const +{ + + return (value[0] < highPt.value[0] && value[0] >=lowPt.value[0]) && + (value[1] < highPt.value[1] && value[1] >=lowPt.value[1]) && + (value[2] < highPt.value[2] && value[2] >=lowPt.value[2]); +} + +//This is different to +=, because it generates no return value +void Point3D::add(const Point3D &obj) +{ + value[0] = obj.value[0] + value[0]; + value[1] = obj.value[1] + value[1]; + value[2] = obj.value[2] + value[2]; +} + +void Point3D::extend(float distance) +{ + ASSERT(sqrMag() > 0.0f); + + Point3D p; + p=*this; + p.normalise(); + *this+=p*distance; +} + +float Point3D::sqrMag() const +{ + return value[0]*value[0] + value[1]*value[1] + value[2]*value[2]; +} + +Point3D Point3D::normalise() +{ + float mag = sqrtf(sqrMag()); + + value[0]/=mag; + value[1]/=mag; + value[2]/=mag; + + return *this; +} + +void Point3D::negate() +{ + value[0] = -value[0]; + value[1] = -value[1]; + value[2] = -value[2]; +} + +float Point3D::angle(const Point3D &pt) const +{ + return acos(dotProd(pt)/(sqrtf(sqrMag()*pt.sqrMag()))); +} + +bool Point3D::orthogonalise(const Point3D &pt) +{ + Point3D crossp; + crossp=this->crossProd(pt); + + //They are co-linear, or near-enough to be not resolvable. + if(crossp.sqrMag() < sqrt(std::numeric_limits::epsilon())) + return false; + crossp.normalise(); + + crossp=crossp.crossProd(pt); + *this=crossp.normalise()*sqrt(this->sqrMag()); + + return true; +} + +bool Point3D::parse(const std::string &str) +{ + //Needs to be at minimum #,#,# + if(str.size()< 5) + return false; + + string tmpStr; + tmpStr=stripWhite(str); + + + //Two strings must be in sync + std::string allowableStartChars, allowableEndChars; + allowableStartChars="([{<'"; + allowableEndChars=")]}>'"; + + size_t startPos,endPos; + startPos=allowableStartChars.find(tmpStr[0]); + endPos=allowableEndChars.find(tmpStr[tmpStr.size()-1]); + + //Strip the start/end chars + if(startPos !=std::string::npos && endPos != std::string::npos) + tmpStr=tmpStr.substr(1,tmpStr.size()-1); + else if (startPos !=endPos) + return false; //we had one start bracket, but not the other... + + //First try splitting with non-whitespace separators, + // there should be exactly 3 components + vector components; + const char *NONWHITE_SEPARATOR=",;|_"; + splitStrsRef(tmpStr.c_str(),NONWHITE_SEPARATOR, + components); + if(components.size()!=3) + return false; + components.clear(); + + //Now try splitting with whitespace components, dropping empty + // strings. As we have already checked the non-whitespace components + // additional components must be whitespace only, which is fine. + + const char *ALLOWABLE_SEPARATORS=",; \t|_"; + + splitStrsRef(tmpStr.c_str(),ALLOWABLE_SEPARATORS, + components); + for(size_t ui=0;ui::iterator rmIt; + rmIt=std::remove(components.begin(),components.end(),string("")); + components.erase(rmIt,components.end()); + + if(components.size()!=3) + return false; + + float p[3]; + for(size_t ui=0;ui<3;ui++) + { + if(stream_cast(p[ui],components[ui])) + return false; + } + + + setValueArr(p); + + return true; +} + +#ifdef __LITTLE_ENDIAN__ + +void Point3D::switchEndian() +{ + floatSwapBytes(&value[0]); + floatSwapBytes(&value[1]); + floatSwapBytes(&value[2]); +} +#endif + +std::ostream& operator<<(std::ostream &stream, const Point3D &pt) +{ + stream << "(" << pt.value[0] << "," << pt.value[1] << "," << pt.value[2] << ")"; + return stream; +} + + +void Point3D::transform3x3(const float *matrix) +{ + for(unsigned int ui=0;ui<3;ui++) + { + value[ui] = value[ui]*matrix[ui*3] + + value[ui]*matrix[ui*3+1] + value[ui]*matrix[ui*3+2]; + } +} +RandNumGen::RandNumGen() +{ + //Initialisation is NOT performed here, because we need a random seed + //to generate our sequence.... + + //we don't initially have Gaussian + //value to spare + haveGaussian=false; +} + +void RandNumGen::initialise(int seed) +{ + long mj,mk; + + //initialise ma[55] with seed + mj=labs((MBIG-labs(seed))); + mj%=MBIG; + ma[55]=mj; + mk=1; + + + //Initialise the rest of the table + for(unsigned int i=1; i<55; i++) + { + int ii; + ii=(21*i)%55; + + ma[ii]=mk; + mk=mj-mk; + + if(mk<0) + mk+=MBIG; + mj=ma[ii]; + } + + //"warm up" the rng + for(unsigned int j=1;j<=4;j++) + { + for(unsigned int i=1;i<=55;i++) + { + ma[i] -=ma[1+ (i+30)%55]; + if(ma[i] < 0) + ma[i]+=MBIG; + } + } + //the constant 31 is special + inext=0; + inextp=31; +} + + +float RandNumGen::genUniformDev() +{ + long mj; + + if(++inext==56) + inext=1; + if(++inextp == 56) + inextp=1; + + mj=ma[inext]-ma[inextp]; + if(mj<0) + mj+=MBIG; + + ma[inext]=mj; + + return mj*(1.0/MBIG); +} + + +int RandNumGen::genInt() +{ + long mj; + + if(++inext==56) + inext=1; + if(++inextp == 56) + inextp=1; + + mj=ma[inext]-ma[inextp]; + if(mj<0) + mj+=MBIG; + + ma[inext]=mj; + + return mj; +} + + +//This is known as the Box-Muller transform +//You can change it from being a uniform variance +//by simply multiplying by the std deviation of your choice +//this will cause the random number returned to be stretched +//in the x axis from unit variance to your number +float RandNumGen::genGaussDev() +{ + float v1,v2,rsq,fac; + //This algorithm generates + //two Gaussian numbers from two Uniform Devs, + //however we only want one. So to speed things up + //remember the second and spit it out as required + if(haveGaussian) + { + haveGaussian=false; + return gaussSpare; + } + + do + { + //grab two uniform Devs and + //move them into (-1,+1) domain + v1=2.0f*genUniformDev()-1.0f; + v2=2.0f*genUniformDev()-1.0f; + rsq=v1*v1+v2*v2; + //reject them if they don't lie in unit circle + //or if rsq is at the origin of the unit circle + //(as eqn below is undefined at origin) + }while(rsq>=1.0f || rsq==0.0f); + + fac=sqrtf(-2.0f*log(rsq)/rsq); + gaussSpare=v1*fac; + haveGaussian=true; + return v2*fac; + +} + +int RandNumGen::initTimer() +{ + timeval tp; + + gettimeofday(&tp,NULL); + + initialise(tp.tv_sec+ tp.tv_usec); + + return tp.tv_sec + tp.tv_usec; +} + +//quaternion multiplication, assuming q2 has no "a" component +void quat_mult_no_second_a(Quaternion *result, const Quaternion *q1, const Quaternion *q2) +{ + result->a = (-q1->b*q2->b-q1->c*q2->c -q1->d*q2->d); + result->b = (q1->a*q2->b +q1->c*q2->d -q1->d*q2->c); + result->c = (q1->a*q2->c -q1->b*q2->d +q1->d*q2->b); + result->d = (q1->a*q2->d +q1->b*q2->c -q1->c*q2->b ); +} + +//this is a little optimisation that doesn't calculate the "a" component for +//the returned quaternion, and implicitly performs conjugation. +//Note that the result is specific to quaternion rotation +void quat_pointmult(Point3f *result, const Quaternion *q1, const Quaternion *q2) +{ + result->fx = (-q1->a*q2->b +q1->b*q2->a -q1->c*q2->d +q1->d*q2->c); + result->fy = (-q1->a*q2->c +q1->b*q2->d +q1->c*q2->a -q1->d*q2->b); + result->fz = (-q1->a*q2->d -q1->b*q2->c +q1->c*q2->b +q1->d*q2->a); + +} + +//Uses quaternion mathematics to perform a rotation around your favourite axis +//IMPORTANT: Rotvec must be normalised before passing to this function +//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) +{ + ASSERT(rotVec->fx*rotVec->fx + rotVec->fy*rotVec->fy + rotVec->fz*rotVec->fz - 1.0f < + 5.0f*sqrt(std::numeric_limits::epsilon())); + + double sinCoeff; + Quaternion rotQuat; + Quaternion pointQuat; + Quaternion temp; + + //remember this value so we don't recompute it +#ifdef _GNU_SOURCE + double cosCoeff; + //GNU provides sincos which is about twice the speed of sin/cos separately + sincos(angle*0.5f,&sinCoeff,&cosCoeff); + rotQuat.a=cosCoeff; +#else + angle*=0.5f; + sinCoeff=sin(angle); + + rotQuat.a = cos(angle); +#endif + rotQuat.b=sinCoeff*rotVec->fx; + rotQuat.c=sinCoeff*rotVec->fy; + rotQuat.d=sinCoeff*rotVec->fz; + +// pointQuat.a =0.0f; This is implied in the pointQuat multiplcation function + pointQuat.b = point->fx; + pointQuat.c = point->fy; + pointQuat.d = point->fz; + + + //perform rotation + quat_mult_no_second_a(&temp,&rotQuat,&pointQuat); + quat_pointmult(point, &temp,&rotQuat); + +} + + +//Retrieve the quaternion for repeated rotation. pass to the quat_rot_apply_quats +void quat_get_rot_quat(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::epsilon())); + double sinCoeff; +#ifdef _GNU_SOURCE + double cosCoeff; + //GNU provides sincos which is about twice the speed of sin/cos separately + sincos(angle*0.5f,&sinCoeff,&cosCoeff); + rotQuat->a=cosCoeff; +#else + angle*=0.5f; + sinCoeff=sin(angle); + rotQuat->a = cos(angle); +#endif + + rotQuat->b=sinCoeff*rotVec->fx; + rotQuat->c=sinCoeff*rotVec->fy; + rotQuat->d=sinCoeff*rotVec->fz; +} + +//Use previously generated quats from quat_get_rot_quats to rotate a point +void quat_rot_apply_quat(Point3f *point, const Quaternion *rotQuat) +{ + Quaternion pointQuat,temp; +// pointQuat.a =0.0f; No need to set this, as we do not use it in the multiplication function + pointQuat.b = point->fx; + pointQuat.c = point->fy; + pointQuat.d = point->fz; + //perform rotation + quat_mult_no_second_a(&temp,rotQuat,&pointQuat); + quat_pointmult(point, &temp,rotQuat); +} + +//For the table to work, we need the sizeof(size_T) at preprocess time +#ifndef SIZEOF_SIZE_T +#error sizeof(size_t) macro is undefined... At time of writing, this is usually 4 (32 bit) or 8. You can work it out from a simple C++ program which prints out sizeof(size_t). This cant be done automatically due to preprocessor behaviour. +#endif + +//Maximum period linear shift register values (computed by +//other program for Galois polynomial) +//Unless otherwise noted, all these entries have been verified using the +//verifyTable routine. +// +//If you don't trust me, (who doesn't trust some random person on the internet?) +//you can re-run the verification routine. +// +//Note that verification time *doubles* with every entry, so full 64-bit verification +//is computationally intensive. I achieved 40 bits in half a day. 48 bits took over a week. +size_t maximumLinearTable[] = { + 0x03, + 0x06, + 0x0C, + 0x14, + 0x30, + 0x60, + 0xb8, + 0x0110, + 0x0240, + 0x0500, + 0x0e08, + 0x1c80, + 0x3802, + 0x6000, + 0xb400, + 0x12000, + 0x20400, + 0x72000, + 0x90000, + 0x140000, + 0x300000, + 0x420000, + 0xD80000, + 0x1200000, + 0x3880000, + 0x7200000, + 0x9000000, + 0x14000000, + 0x32800000, + 0x48000000, + +#if (SIZEOF_SIZE_T > 4) + 0xA3000000, + 0x100080000, + 0x262000000, + 0x500000000, + 0x801000000, + 0x1940000000, + 0x3180000000, + 0x4400000000, + 0x9C00000000, + 0x12000000000, + 0x29400000000, + 0x63000000000, + 0xA6000000000, + 0x1B0000000000, + 0x20E000000000, + 0x420000000000, + 0x894000000000, + //Maximal linear table entries below line are unverified + //Verifying the full table might take a few months of computing time + //But who needs to count beyond 2^49-1 (~10^14) anyway?? + 0x1008000000000, + + //Really, there are more entries beyond this, but I consider it pretty much not worth the effort. +#endif +}; + + +void LinearFeedbackShiftReg::setMaskPeriod(unsigned int newMask) +{ + //Don't fall off the table + ASSERT((newMask-3) < sizeof(maximumLinearTable)/sizeof(size_t)); + + maskVal=maximumLinearTable[newMask-3]; + + //Set the mask to be all ones + totalMask=0; + for(size_t ui=0;ui> 1) ^ ( (-(lfsr & (ull)(1u))) & maskVal ); + lfsr&=totalMask; + if( lfsr == 0u) + lfsr=1u; + + return lfsr; +} + +double det3by3(const double *ptArray) +{ + return (ptArray[0]*(ptArray[4]*ptArray[8] + - ptArray[7]*ptArray[5]) + - ptArray[1]*(ptArray[3]*ptArray[8] + - ptArray[6]*ptArray[5]) + + ptArray[2]*(ptArray[3]*ptArray[7] + - ptArray[4]*ptArray[6])); +} + +//Determines the volume of a quadrilateral pyramid +//input points "planarpts" must be adjacent (connected) by +//0 <-> 1 <-> 2 <-> 0, all points connected to apex +double pyramidVol(const Point3D *planarPts, const Point3D &apex) +{ + + //Array for 3D simplex volumed determination + // | (a_x - b_x) (b_x - c_x) (c_x - d_x) | + //v_simplex =1/6| (a_y - b_y) (b_y - c_y) (c_y - d_y) | + // | (a_z - b_z) (b_z - c_z) (c_z - d_z) | + double simplexA[9]; + + //simplex A (a,b,c,apex) is as follows + //a=planarPts[0] b=planarPts[1] c=planarPts[2] + + simplexA[0] = (double)( (planarPts[0])[0] - (planarPts[1])[0] ); + simplexA[1] = (double)( (planarPts[1])[0] - (planarPts[2])[0] ); + simplexA[2] = (double)( (planarPts[2])[0] - (apex)[0] ); + + simplexA[3] = (double)( (planarPts[0])[1] - (planarPts[1])[1] ); + simplexA[4] = (double)( (planarPts[1])[1] - (planarPts[2])[1] ); + simplexA[5] = (double)( (planarPts[2])[1] - (apex)[1] ); + + simplexA[6] = (double)( (planarPts[0])[2] - (planarPts[1])[2] ); + simplexA[7] = (double)( (planarPts[1])[2] - (planarPts[2])[2] ); + simplexA[8] = (double)( (planarPts[2])[2] - (apex)[2] ); + + return 1.0/6.0 * (fabs(det3by3(simplexA))); +} + + diff -Nru 3depict-0.0.12/src/common/mathfuncs.h 3depict-0.0.13/src/common/mathfuncs.h --- 3depict-0.0.12/src/common/mathfuncs.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/mathfuncs.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,260 @@ +/* + * mathfuncs.h - General mathematic functions 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 . +*/ +#ifndef MATHFUNCS_H +#define MATHFUNCS_H + +#include +#include +#include + +#include "endianTest.h" + + +//!A 3D point data class storage +/*! A 3D point data class + * contains operator overloads and some basic + * mathematical functions + */ +class Point3D +{ + private: + //!Value data + float value[3]; + public: + //!Constructor + inline Point3D() {}; + //!Constructor with initialising values + inline Point3D(float x,float y,float z) + { value[0] = x, value[1] = y, value[2] = z;} + //!Set by value (ith dim 0, 1 2) + inline void setValue(unsigned int ui, float val){value[ui]=val;}; + //!Set all values + inline void setValue(float fX,float fY, float fZ) + {value[0]=fX; value[1]=fY; value[2]=fZ;} + + //!Set by pointer + inline void setValueArr(const float *val) + { + value[0]=*val; + value[1]=*(val+1); + value[2]=*(val+2); + }; + + //!Get value of ith dim (0, 1, 2) + inline float getValue(unsigned int ui) const {return value[ui];}; + //Retrieve the internal pointer. Only use if you know why. + inline const float *getValueArr() const { return value;}; + + //!get into an array (note array must hold sizeof(float)*3 bytes of valid mem + void copyValueArr(float *value) const; + + //!Add a point to this, without generating a return value + void add(const Point3D &obj); + + //Convert a point string from its "C" language representation to a point value + bool parse(const std::string &str); + + //!Equality operator + bool operator==(const Point3D &pt) const; + //!assignment operator + const Point3D &operator=(const Point3D &pt); + //!+= operator + const Point3D &operator+=(const Point3D &pt); + + const Point3D operator+(float f) const; + //!multiplication operator + const Point3D &operator*=(const float scale); + //!Addition operator + const Point3D operator+(const Point3D &pt) const; + //!elemental multiplication + const Point3D operator*(float scale) const; + //!multiplication + const Point3D operator*(const Point3D &pt) const; + //!Division. + const Point3D operator/(float scale) const; + //!Subtraction + const Point3D operator-(const Point3D &pt) const; + //!returns a negative of the existing value + const Point3D operator-() const; + //!Output streaming operator. Users (x,y,z) as format for output + friend std::ostream &operator<<(std::ostream &stream, const Point3D &); + //!make point unit magnitude, maintaining direction + Point3D normalise(); + //!returns the square of distance another pt + float sqrDist(const Point3D &pt) const; + + //!Calculate the dot product of this and another pint + float dotProd(const Point3D &pt) const; + //!Calculate the cross product of this and another point + Point3D crossProd(const Point3D &pt) const; + + //!Calculate the angle between two position vectors in radiians + float angle(const Point3D &pt) const; + + //Extend the current vector by the specified distance + void extend(float distance); + + //!overload for array indexing returns |pt|^2 + float sqrMag() const; + + //!Retrieve by value + float operator[](unsigned int ui) const; + //!Retrieve element by referene + float &operator[](unsigned int ui) ; + + //!Is a given point stored inside a box bounded by orign and this pt? + /*!returns true if this point is located inside (0,0,0) -> Farpoint + * assuming box shape (non zero edges return false) + * farPoint must be positive in all dim + */ + bool insideBox(const Point3D &farPoint) const; + + + //!Tests if this point lies inside the rectangular prism + /*!Returns true if this point lies inside the box bounded + * by lowPoint and highPoint + */ + bool insideBox(const Point3D &lowPoint, const Point3D &highPoint) const; + + //!Makes each value negative of old value + void negate(); + + //Perform a 3x3 matrix transformation. + void transform3x3(const float *matrix); + + //Perform a cross-product based orthogonalisation + //with the specified vector + bool orthogonalise(const Point3D &p); +#ifdef __LITTLE_ENDIAN__ + //!Flip the endian state for data stored in this point + void switchEndian(); +#endif +}; + + +//IMPORTANT!!! +//=============== +//Do NOT use multiple instances of this in your code +//with the same initialisation technique (e.g. initialising from system clock) +//this would be BAD, correlations might well be introduced into your results +//that are simply a result of using correlated random sequences!!! (think about it) +//use ONE random number generator in the project, initialise it and then "register" +//it with any objects that need a random generator. +//============== +class RandNumGen +{ + private: + int ma[56]; + int inext,inextp; + float gaussSpare; + bool haveGaussian; + + public: + RandNumGen(); + void initialise(int seedVal); + int initTimer(); + + int genInt(); + float genUniformDev(); + + //This generates a number chosen from + //a gaussian distribution range is (-inf, inf) + float genGaussDev(); +}; + +//needed for sincos +#ifdef __LINUX__ +#ifdef __GNUC__ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#endif +#endif + +typedef struct +{ + float a; + float b; + float c; + float d; +} Quaternion; + +typedef struct +{ + float fx; + float fy; + float fz; +} Point3f; + +//Uses quaternion mathematics to perform a rotation around your favourite axis +//IMPORTANT: rotVec must be normalised before passing to this function +//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); + +//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); + +//Use previously generated quats from quat_get_rot_quats to rotate a point +void quat_rot_apply_quat(Point3f *point, const Quaternion *rotQuat); + +//This class implements a Linear Feedback Shift Register (in software) +//This is a mathematical construct based upon polynomials over closed natural numbers (N mod p). +//This will generate a weakly random digit string, but with guaranteed no duplicates, using O(1) +//memory and O(n) calls. The no duplicate guarantee is weak-ish, with no repetition in the +//shift register for 2^n-1 iterations. n can be set by setMaskPeriod. +class LinearFeedbackShiftReg +{ + size_t lfsr; + size_t maskVal; + size_t totalMask; + public: + //Get a value from the shift register, and advance + size_t clock(); + //Set the internal lfsr state. Note 0 is the lock-up state. + void setState(size_t newState) { lfsr=newState;}; + //set the mask to use such that the period is 2^n-1. 3 is minimum 60 is maximum + void setMaskPeriod(unsigned int newMask); + + //!Check the validity of the table + bool verifyTable(size_t maxLen=0); +}; + + +//Determines the volume of a quadrilateral pyramid +//input points "planarpts" must be adjacent (connected) by +//0 <-> 1 <-> 2 <-> 0, all points connected to apex +double pyramidVol(const Point3D *planarPts, const Point3D &apex); + +//!Inline func for calculating a(dot)b +inline float dotProduct(float a1, float a2, float a3, + float b1, float b2, float b3) +{ + return a1*b1 + a2*b2 + a3* b3; +} + +inline unsigned int ilog2(unsigned int value) +{ + unsigned int l = 0; + while( (value >> l) > 1 ) + ++l; + return l; +} +#endif diff -Nru 3depict-0.0.12/src/common/stringFuncs.cpp 3depict-0.0.13/src/common/stringFuncs.cpp --- 3depict-0.0.12/src/common/stringFuncs.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/stringFuncs.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,631 @@ +/* + * stringFuncs.cpp - string manipulation routines + * 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 . +*/ + +#include "common/stringFuncs.h" + +#include "common/basics.h" + +using std::string; +using std::vector; + +std::string getMaxVerStr(const std::vector &verStrings) +{ + std::vector > > verNum; + std::vector thisVer; + + + //break string up into numeric components + for(unsigned int ui=0;ui strVerNum; + strVerNum.clear(); + + // period or hyphen are valid version number separators + splitStrsRef(verStrings[ui].c_str(),".-",strVerNum); + + //Check to see if we can interpret the values + for(unsigned int uj=0;uj 1) + { + unsigned int thisMax; + thisMax=0; + + for(unsigned int ui=0;ui= '0' && s[0] <= '9') || + (s[0] >= 'a' && s[0] <= 'f')); + ASSERT((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'a' && s[1] <= 'f')); + + int high,low; + if(s[0] <= '9' && s[0] >='0') + high = s[0]-(int)'0'; + else + high = s[0] -(int)'a' + 10; + + if(s[1] <= '9' && s[1] >='0') + low = s[1]-(int)'0'; + else + low = s[1] -(int)'a' + 10; + + c = 16*high + low; +} + +std::string digitString(unsigned int thisDigit, unsigned int maxDigit) +{ + std::string s,thisStr; + stream_cast(thisStr,thisDigit); + + stream_cast(s,maxDigit); + for(unsigned int ui=0;ui > comboString, + unsigned int curChoice) +{ + ASSERT(curChoice < comboString.size()) + + string s,sTmp; + stream_cast(sTmp,curChoice); + s=sTmp + string(":"); + for(unsigned int ui=0;ui &sVec) +{ + //Create a truncated vector and reserve mem. + std::vector tVec; + tVec.reserve(sVec.size()); + std::string s; + for(unsigned int ui=0;ui &v ) +{ + const char *thisMark, *lastMark; + string str; + v.clear(); + + //check for null string + if(!*cpStr) + return; + thisMark=cpStr; + lastMark=cpStr; + while(*thisMark) + { + if(*thisMark==delim) + { + str.assign(lastMark,thisMark-lastMark); + v.push_back(str); + + thisMark++; + lastMark=thisMark; + } + else + thisMark++; + } + + if(thisMark!=lastMark) + { + str.assign(lastMark,thisMark-lastMark); + v.push_back(str); + } + +} + +//Split strings around any of a string of delimiters +void splitStrsRef(const char *cpStr, const char *delim,std::vector &v ) +{ + const char *thisMark, *lastMark; + string str; + v.clear(); + + //check for null string + if(!(*cpStr)) + return; + thisMark=cpStr; + lastMark=cpStr; + while(*thisMark) + { + //Loop over possible delimiters to determine if this char is a delimiter + bool isDelim; + const char *tmp; + tmp=delim; + isDelim=false; + while(*tmp) + { + if(*thisMark==*tmp) + { + isDelim=true; + break; + } + tmp++; + } + + if(isDelim) + { + str.assign(lastMark,thisMark-lastMark); + v.push_back(str); + + thisMark++; + lastMark=thisMark; + } + else + thisMark++; + } + + if(thisMark!=lastMark) + { + str.assign(lastMark,thisMark-lastMark); + v.push_back(str); + } + +} + +//!Returns Choice ID from string (see choiceString(...) for string format) +//FIXME: Does not work if the choicestring starts from a number other than zero... +std::string getActiveChoice(const std::string &choiceString) +{ + size_t colonPos; + colonPos = choiceString.find(":"); + ASSERT(colonPos!=string::npos); + + //Extract active selection + string tmpStr; + tmpStr=choiceString.substr(0,colonPos); + unsigned int activeChoice; + stream_cast(activeChoice,tmpStr); + + //Convert ID1|string 1, .... IDN|string n to vectors + std::string s; + s=choiceString.substr(colonPos,choiceString.size()-colonPos); + vector choices; + splitStrsRef(s.c_str(),',',choices); + + ASSERT(activeChoice < choices.size()); + tmpStr = choices[activeChoice]; + + return tmpStr.substr(tmpStr.find("|")+1,tmpStr.size()-1); +} + +void choiceStringToVector(const std::string &choiceString, + std::vector &choices, unsigned int &selected) +{ + ASSERT(isMaybeChoiceString(choiceString)); + + //Convert ID1|string 1, .... IDN|string n to vectors, + // stripping off the ID value + size_t colonPos; + colonPos = choiceString.find(":"); + + std::string s; + s=choiceString.substr(colonPos,choiceString.size()-colonPos); + splitStrsRef(s.c_str(),',',choices); + + for(size_t ui=0;ui verStrs; + + verStrs.push_back("0.0.9"); + verStrs.push_back("0.0.10"); + + TEST(getMaxVerStr(verStrs) == "0.0.10","version string maximum testing"); + + verStrs.clear(); + + verStrs.push_back("0.0.9"); + verStrs.push_back("0.0.9"); + TEST(getMaxVerStr(verStrs) == "0.0.9","version string maximum testing"); + + + verStrs.push_back("0.0.9"); + verStrs.push_back("0.0.blah"); + TEST(getMaxVerStr(verStrs) == "0.0.9","version string maximum testing"); + } + + return true; +} + + +#endif diff -Nru 3depict-0.0.12/src/common/stringFuncs.h 3depict-0.0.13/src/common/stringFuncs.h --- 3depict-0.0.12/src/common/stringFuncs.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/stringFuncs.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,137 @@ +/* + * common/stringFuncs.h - String manipulation 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 . +*/ + +#ifndef STRINGFUNCS_H +#define STRINGFUNCS_H + +#include +#include + +//generate a semi-random string (not strong random), returns true +// if a file that could be opened was found +bool genRandomFilename(std::string &s,bool timerInitRand=true); + +//Convert a boolean to "1" or "0" +std::string boolStrEnc(bool b); + +//!Generate string that can be parsed by wxPropertyGrid for combo control +//String format is CHOICEID:id1|string 1,id2|string 2,id3|string 3,.....,idN|string_N +// where id1->idN are integers +std::string choiceString(std::vector > comboString, + unsigned int curChoice); + +//Convert a choice string, such as generated by "choiceString", into a vector of strings +void choiceStringToVector(const std::string &str, + std::vector &choices, unsigned int &selected); + +#ifdef DEBUG +//!Obtain whether or not the string is a choice string +bool isMaybeChoiceString(const std::string &s); +#endif +//!Generate a string with leading digits up to maxDigit (eg, if maxDigit is 424, and thisDigit is 1 +//leading digit will generate the string 001 +std::string digitString(unsigned int thisDigit, unsigned int maxDigit); + +//!Returns Choice from string (see choiceString(...) for string format) +std::string getActiveChoice(const std::string &choiceString); + +//!Convert a choiceString() into something that a wxGridCellChoiceEditor will accept +std::string wxChoiceParamString(std::string choiceString); + + +//Strip whitespace from a string +std::string stripWhite(const std::string &str); + +//!Return a lowercase version for a given string +std::string lowercase(std::string s); + +//Drop empty entries from a string of vector +void stripZeroEntries(std::vector &s); + + +//Parse a colour string, such as #aabbccdd into its RGBA 8-bit components +bool parseColString(const std::string &str, + unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a); + +//Convert an RGBA 8-bit/channel quadruplet into its hexadecimal colour string +void genColString(unsigned char r, unsigned char g, + unsigned char b, unsigned char a, std::string &s); +//Convert an RGB 8-bit/channel quadruplet into its hexadecimal colour string +void genColString(unsigned char r, unsigned char g, + unsigned char b, std::string &s); + +//Check to see if a given string is a valid version number string, +// consisting of decmials and ints (eg 0.1.2.3.4) +bool isVersionNumberString(const std::string &s); + +//!Retrieve the maximum version string from a list of version strings +// version strings are digit and decimal point (.) only +std::string getMaxVerStr(const std::vector &verStrings); + +//!Strip whitespace, (eg tab,space) from either side of a string +std::string stripWhite(const std::string &str); + +//!Split string references using a single delimiter. +void splitStrsRef(const char *cpStr, const char delim,std::vector &v ); + +//!Split string references using any of a given string of delimiters +void splitStrsRef(const char *cpStr, const char *delim,std::vector &v ); + +//!Return only the filename component +std::string onlyFilename( const std::string& path ); +//!Return only the directory name component of the full path +// - do not use with UNC windows paths +std::string onlyDir( const std::string& path ); + +//!Convert a path format into a native path from unix format +// - do not use with UNC windows paths +std::string convertFileStringToNative(const std::string &s); + +//!Convert a path format into a unix path from native format +std::string convertFileStringToCanonical(const std::string &s); + +//Print N tabs to a string +inline std::string tabs(unsigned int nTabs) +{ + std::string s; + s.resize(nTabs); + std::fill(s.begin(),s.end(),'\t'); + return s; +} + +//Brute force convert a wide STL str to a normal stl str +inline std::string stlWStrToStlStr(const std::wstring& s) +{ + std::string temp(s.length(),' '); + std::copy(s.begin(), s.end(), temp.begin()); + return temp; +} +//Brute force convert an stlStr to an stl wide str +inline std::wstring stlStrToStlWStr(const std::string& s) +{ + std::wstring temp(s.length(),L' '); + std::copy(s.begin(), s.end(), temp.begin()); + return temp; +} + +#ifdef DEBUG +//Run unit tests for string funcs +bool testStringFuncs(); +#endif + +#endif diff -Nru 3depict-0.0.12/src/common/translation.h 3depict-0.0.13/src/common/translation.h --- 3depict-0.0.12/src/common/translation.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/translation.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * common/translation.h - Program gettext translation macros + * 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 . + */ + +#ifndef TRANSLATION_H +#define TRANSLATION_H + +#include + + +#if defined(__APPLE__) || defined(__WIN32__) || defined(__WIN64__) +#include +#endif + +//!Gettext translation macro +#define TRANS(x) (gettext(x)) + +//!Gettext null-translation macro (mark for translation, but do nothing) +#define NTRANS(x) (x) + +//!Wx friendly gettext translation macro +#define wxTRANS(x) (wxString(gettext(x),*wxConvCurrent)) + +#define wxNTRANS(x) wxT(x) + +#endif diff -Nru 3depict-0.0.12/src/common/voxels.cpp 3depict-0.0.13/src/common/voxels.cpp --- 3depict-0.0.12/src/common/voxels.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/voxels.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,177 @@ +/* + * voxels.cpp - Voxelised data manipulation 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 . + */ +#include "voxels.h" + +using std::numeric_limits; +const float FLOAT_SMALL= + sqrt(numeric_limits::epsilon()); + +bool testConvolve() +{ + { + Voxels data,kernel,result; + data.setCallbackMethod(dummyCallback); + kernel.setCallbackMethod(dummyCallback); + + const size_t NUM_SIZES=4; + const size_t TEST_SIZES[]= { 1, 3, 4, 7}; + + for(size_t ui=0;ui data; + data.resize(3,3,3); + data.fill(1); + TEST(fabs(data.trapezIntegral() - 1.0f )< FLOAT_SMALL,"Trapezoid test"); + + data.resize(5,5,5); + data.fill(1); + data.setBounds(Point3D(0,0,0),Point3D(1,1,1)); + TEST(fabs(data.trapezIntegral() - 1.0f) < FLOAT_SMALL,"Trapezoid test"); + data.setBounds(Point3D(0,0,0),Point3D(5,5,5)); + TEST(fabs(data.trapezIntegral() - 125.0f) < FLOAT_SMALL,"Trapezoid test"); + } + + //Test convolution stuff + { + Voxels data,kernel,result; + data.setCallbackMethod(dummyCallback); + kernel.setCallbackMethod(dummyCallback); + //Check that convolving with an impulse with + //a Gaussian gives us a Gaussian + //back, roughly speaking + kernel.setGaussianKernelCube(1.0f,10.0f,10); + + float trapz = kernel.trapezIntegral(); + TEST(trapz < 1.5f && trapz > 0.5f, "Trapezoidal kernel integral test"); + + + data.resize(20,20,20); + data.fill(0.0f); + data.setData(10,10,10,1.0f); + data.convolve(kernel,result,BOUND_CLIP); + + TEST(result.max() > 0 && result.max() < 1.0f,"result should be nonzero, and less than the original input (convolve only squeezes maxima/minima)"); + //Gaussian @ x=0, stdev 1 + TEST(fabs(result.max() - kernel.max()) < FLOAT_SMALL + ,"Gaussian kernel test- maxima of convolved and kernel should be the same"); + } + + return true; +} + +bool simpleMath() +{ + Voxels a,b,c; + a.resize(3,3,3); + a.fill(2.0f); + + float f; + f=a.getSum(); + TEST(fabs(f-3.0*3.0*3.0*2.0 )< FLOAT_SMALL,"getsum test"); + TEST(fabs(a.count(1.0f)- 3.0*3.0*3.0) < FLOAT_SMALL,"Count test"); + + return true; +} + +bool basicTests() +{ + Voxels f; + f.setCallbackMethod(dummyCallback); + f.resize(3,3,3); + + size_t xs,ys,zs; + f.getSize(xs,ys,zs); + TEST(xs == ys && ys == zs && zs == 3,"resize tests"); + + + + f.fill(0); + f.setData(1,1,1,1.0f); + + TEST(fabs(f.max() - 1.0f) < FLOAT_SMALL,"Fill and data set"); + + f.resizeKeepData(2,2,2); + f.getSize(xs,ys,zs); + + TEST(xs == ys && ys == zs && zs == 2, "resizeKeepData"); + TEST(f.max() == 1.0f,"resize keep data"); + + return true; +} + + +bool runVoxelTests() +{ + TEST(basicTests(),"basic voxel tests"); + TEST(testConvolve()," voxel convolve"); + TEST(simpleMath(), "voxel simple maths"); + return true; +} diff -Nru 3depict-0.0.12/src/common/voxels.h 3depict-0.0.13/src/common/voxels.h --- 3depict-0.0.12/src/common/voxels.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/voxels.h 2013-04-10 20:37:11.000000000 +0000 @@ -0,0 +1,2588 @@ + /* + * common/voxels.h - Voxelised data manipulation 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 . + */ + +#ifndef VOXELS_H +#define VOXELS_H + + +const unsigned int MAX_CALLBACK=500; + +#include "common/basics.h" + +#include + +using namespace std; + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifdef _OPENMP + #include +#endif + +//!Boundary clipping mode +/*! These constants defines the behaviour of the routines when presented with a + * boundary value problem, such as in convolution. + */ +enum{ + BOUND_CLIP=1, + BOUND_HOLD, + BOUND_DERIV_HOLD, + BOUND_MIRROR, + BOUND_ZERO, + BOUND_ENUM_END +}; + + +enum{ + ADJ_ALL, + ADJ_PLUS +}; + +//Error codes +enum{ + VOXELS_BAD_FILE_READ=1, + VOXELS_BAD_FILE_OPEN, + VOXELS_BAD_FILE_SIZE, + VOXELS_OUT_OF_MEMORY +}; + +//Must be power of two (buffer size when loading files, in sizeof(T)s) +const unsigned int ITEM_BUFFER_SIZE=65536; + +//!Clipping direction constants +/*! Controls the clipping direction when performing clipping operations + */ +enum { + CLIP_NONE=0, + CLIP_LOWER_SOUTH_WEST, + CLIP_UPPER_NORTH_EAST +}; + + +enum { + VOXEL_ABORT_ERR, + VOXEL_MEMORY_ERR, + VOXEL_BOUNDS_INVALID_ERR +}; + +#ifdef _OPENMP +//Auto-detect the openMP iterator type. +#if ( __GNUC__ > 4 && __GNUC_MINOR__ > 3 ) + #define MP_INT_TYPE size_t +#else + #define MP_INT_TYPE long long +#endif +#else + #define MP_INT_TYPE size_t +#endif + +#ifdef DEBUG + bool runVoxelTests(); +#endif +//!Template class that stores 3D voxel data +/*! To instantiate this class, objects must have + * basic mathematical operators, such as * + - and = + */ +template class Voxels +{ + private: + //!Number of bins in data set (X,Y,Z) + size_t binCount[3]; + + //!Voxel array + std::vector voxels; + + //!Scaling value for furthest bound of the dataset. + //Dataset is assumed to sit in a rectilinear volume from minBound + //to maxBound + Point3D minBound, maxBound; + + bool (*callback)(bool); + + public: + //!Constructor. + Voxels(); + //!Destructor + ~Voxels(); + + //!Swap object contents with other voxel object + void swap(Voxels &v); + + //!Clone this into another object + void clone(Voxels &newClone) const; + + //!Set the value of a point in the dataset + void setPoint(const Point3D &pt, const T &val); + //!Retrieve the value of a datapoint + T getPointData(const Point3D &pt) const; + + + //!Retrieve the XYZ voxel location associated with a given position + void getIndex(size_t &x, size_t &y, + size_t &z, const Point3D &p) const; + + //!Retrieve the XYZ voxel location associated with a given position, + // including upper borders + void getIndexWithUpper(size_t &x, size_t &y, + size_t &z, const Point3D &p) const; + + //!Get the position associated with an XYZ voxel + Point3D getPoint(size_t x, + size_t y, size_t z) const; + //!Retrieve the value of a specific voxel + inline T getData(size_t x, size_t y, size_t z) const; + //!Retrieve value of the nth voxel + inline T getData(size_t i) const { return voxels[i];} + //Return a padded version of the data. Valid pads are BOUND_* + T getPaddedData(long long x, long long y, long long z, + unsigned int padMode) const; + + + void setEntry(size_t n, const T &val) { voxels[n] = val;}; + //!Retrieve a reference to the data ata given position + //const T &getDataRef(size_t x, size_t y, size_t z) const; + //!Set the value of a point in the dataset + 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 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();}; + + //!Resize the data field + /*! This will destroy any data that was already in place + * If the data needs to be preserved use "resizeKeepData" + * Data will *not* be initialised + */ + size_t resize(size_t newX, size_t newY, size_t newZ, const Point3D &newMinBound=Point3D(0.0f,0.0f,0.0f), const Point3D &newMaxBound=Point3D(1.0f,1.0f,1.0f)); + + size_t resize(const Voxels &v); + + //!Resize the data field, maintaining data as best as possible + /*! This will preserve data by resizing as much as possible + * about the origin. If the bounds are extended, the "fill" value is used + * by default iff doFill is set to true. + */ + size_t resizeKeepData(size_t newX, size_t newY, size_t newZ, + unsigned int direction=CLIP_LOWER_SOUTH_WEST, const Point3D &newMinBound=Point3D(0.0f,0.0f,0.0f), const Point3D &newMaxBound=Point3D(1.0f,1.0f,1.0f), const T &fill=T(0),bool doFill=false); + + + + //!Get a unique integer that corresponds to the edge index for the voxel; where edges are shared between voxels + /*! Each voxel has 12 edges. These are shared (except + * voxels that on zero or positive boundary). Return a + * unique index that corresponds to a specified edge (0->11) + */ + size_t getEdgeIndex(size_t x,size_t y, size_t z, unsigned int edge) const; + + + //!Convert the edge index (as generated by getEdgeIndex) into a cenre position + // returns the axis value so you know edge vector too. + // NOte that the value to pass as the edge index is (getEdgeIndex>>2)<<2 to + // make the ownership of the voxel correct + void getEdgeEnds(size_t edgeIndex,Point3D &a, Point3D &b) const; + + + + //TODO: there is duplicate code between this and getEdgeEnds. Refactor. + //!Return the values that are associated with the edge ends, as returned by getEdgeEnds + void getEdgeEndApproxVals(size_t edgeUniqId, float &a, float &b ) const; + + + //!Rebin the data by a given rate + /*! This will perform a quick and dirty rebin operation, where groups of datablocks + * are binned into a single cell. Number of blocks binned is rate^3. Field must be larger than rate + * in all directions. Currently only CLIP_NONE is supported. + */ + void rebin(Voxels &dest, size_t rate, size_t clipMode=CLIP_NONE) const; + + //!Get the total value of the data field. + /*! An "initial value" is provided to provide the definition of a zero value + */ + T getSum(const T &initialVal=T(0.0)) const; + + //!count the number of cells with at least this intensity + size_t count(const T &minIntensity) const; + + //!Fill all voxels with a given value + void fill(const T &val); + //!Get the bounding size + Point3D getMinBounds() const; + Point3D getMaxBounds() const; + ///! Get the spacing for a unit cell + Point3D getPitch() const; + //!Set the bounding size + void setBounds(const Point3D &pMin, const Point3D &pMax); + + //!Initialise the voxel storage + size_t init(size_t nX,size_t nY,size_t nZ, const BoundCube &bound); + //!Initialise the voxel storage + size_t init(size_t nX,size_t nY, size_t nZ); + //!Load the voxels from file + /*! Format is flat size_ts in column major + * return codes: + * 1: File open error + * 2: Data size error + */ + size_t loadFile(const char *cpFilename, size_t nX, + size_t nY, size_t nZ, bool silent=false); + //!Write the voxel objects in column major written out to file + /*! Format is flat objects ("T"s) in column major format. + * Returns nonzero on failure + */ + size_t writeFile(const char *cpFilename) const; + + //!Run convolution over this data, placing the correlation data into "result" + /*! + * Datasets MUST have the same pitch (spacing) for the result to be defined + * template type must have a T(0.0) constructor that intialises it to some "zero" + */ + size_t convolve(const Voxels &templateVec, Voxels &result, + size_t boundMode=BOUND_CLIP) const; + + + //!Similar to convolve, but faster -- only works with separable kernels. + //Destroys original data in process. + /*! + * Datasets MUST have the same pitch (spacing) for the result to be defined + * template type must have a T(0.0) constructor that intialises it to some "zero" + */ + size_t separableConvolve(const Voxels &templateVec, Voxels &result, + size_t boundMode=BOUND_CLIP); + + //!Set this object to a normalised gaussian kernel, centered around the middle of the dataset + void setGaussianKernelCube(float stdDev, float bound, size_t sideLen); + + //!Second derivative by difference approximation + /*! Returns the first order central difference approximation to the + * second derivative. Bound mode can (when implemented) bye used to compute + * appropriate differences. + */ + void secondDifference(Voxels &result, size_t boundMode=BOUND_CLIP) const; + + + //!Find the positions of the voxels that are above or below a given value + /*! Returns the positions of the voxels' centroids for voxels that have, by default, + * a value greater than that of thresh. This behaviour can by reversed to "lesser than" + * by setting lowerEq to false + */ + void thresholdForPosition(std::vector &p, const T &thresh, bool lowerEq=false) const; + + + + //!Construct a spherical kernel + /* The spherical result is located at the centre of the voxel set + * sideLen -The side length is the diameter of the sphere + * bound -the bounding value that the voxels contain themselves within + * val - the value that the voxels take on for a full sphere. + * antialiasingLevel - the number of times to subdivide the voxels into 8 parts + * and test these voxels for internal/external. The resultant fraction of inside/outside voxels is summed. + */ + void makeSphericalKernel(size_t sideLen, float bound, const T &val, unsigned int antialiasLevel=0); + + //!Return the sizeof value for the T type + /*! Maybe there is a better way to do this, I don't know + */ + static size_t sizeofType() { return sizeof(T);}; + + + //!Binarise the data into a result vector + /* On thresholding (val > thresh), set the value to "onThresh". + * Otherwise set to "offthresh" + */ + void binarise(Voxels &result,const T &thresh, const T &onThresh, + const T &offThresh) const; + + + //!Empty the data + /*Remove the data from the voxel set + */ + void clear() { voxels.clear();}; + + //!Find minimum in dataset + T min() const; + + //!Find maximum in dataset + T max() const; + + //!Find both min and max in dataset in the same loop + void minMax(T &min, T &max) const; + + //!Given some coordinates and radii, generate a voxel dataset of solid spheres superimposed + /*! The radius specified is in the bounding units + * clear value optionally wipes the dataset before continuing + */ + void fillSpheresByPosition( const std::vector &spherePos, float rad, const T &value, bool doErase=true); + + + //!Generate a histogram of data values. / operator must be defined for target type + /*! Data bins are evenly spaced between min and max. Formula for binning is (val-min())/(max()-min())*histBinCount + */ + int histogram(std::vector &v, size_t histBinCount) const; + + //!Find the largest or smallest n objects + void findSorted(std::vector &x, std::vector &y, std::vector &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 + * are set by calling ::setBounds() with the + * appropriate parameters for your data. + * Disabling nowrap allows you to "saturate" your + * data field in the case of dense regions, rather + * than let wrap-around errors occur + */ + int countPoints( const std::vector &points, bool noWrap=true, bool doErase=false); + + //!Integrate the datataset via the trapezoidal method + T trapezIntegral() const; + //! Convert voxel intensity into voxel density + // this is done by dividing each voxel by its volume + void calculateDensity(); + + float getBinVolume() const; + //!increment the position specified + inline void increment(size_t x, size_t y, size_t z){ + //Typecast everything to at least 64 bit uints. + voxels[(size_t)z*(size_t)binCount[1]*(size_t)binCount[0] + +(size_t)y*(size_t)binCount[0] + (size_t)x]++;} + + void setCallbackMethod(bool (*cb)(bool)) {callback = cb;} + + //!Element wise division + void operator/=(const Voxels &v); + + void operator/=(const T &v); + + bool operator==(const Voxels &v) const; + +}; + +//!Convert one type of voxel into another by assignment operator +template +void castVoxels(const Voxels &src, Voxels &dest) +{ + size_t x,y,z; + + //Resize the dest + src.getSize(x,y,z); + + dest.resize(x,y,z,src.getBounds()); + + size_t numEntries=x*y*z; +#pragma omp parallel for + for(MP_INT_TYPE ui=0; ui <(MP_INT_TYPE)numEntries; ui++) + { + dest.setEntry(ui,src.getData(ui)); + } + +} + +//!Use one counting type to sum counts in a voxel of given type +template +void sumVoxels(const Voxels &src, U &counter) +{ + size_t nx,ny,nz; + + src.getSize(nx,ny,nz); + + counter=0; + for(size_t ui=0; ui +Voxels::Voxels() : voxels(), minBound(Point3D(0,0,0)), maxBound(Point3D(1,1,1)) +{ +} + +template +Voxels::~Voxels() +{ +} + + +template +void Voxels::clone(Voxels &newVox) const +{ + newVox.binCount[0]=binCount[0]; + newVox.binCount[1]=binCount[1]; + newVox.binCount[2]=binCount[2]; + + newVox.voxels.resize(voxels.size()); + newVox.minBound=minBound; + newVox.maxBound=maxBound; + + std::copy(voxels.begin(),voxels.end(),newVox.voxels.begin()); + +} + +template +void Voxels::setPoint(const Point3D &point,const T &val) +{ + ASSERT(voxels.size()); + size_t pos[3]; + for(size_t ui=0;ui<3;ui++) + pos[ui] = (size_t)round(point[ui]*(float)binCount[ui]); + + + voxels[pos[2]*binCount[1]*binCount[0] + pos[1]*binCount[0] + pos[0]]=val; +} + +template +void Voxels::setData(size_t x, size_t y, + size_t z, const T &val) +{ + ASSERT(voxels.size()); + + ASSERT( x < binCount[0] && y < binCount[1] && z < binCount[2]); + voxels[z*binCount[1]*binCount[0] + y*binCount[0] + x]=val; +} + +template +inline void Voxels::setData(size_t n, const T &val) +{ + ASSERT(voxels.size()); + ASSERT(n +T Voxels::getPointData(const Point3D &point) const +{ + ASSERT(voxels.size()); + size_t pos[3]; + for(size_t ui=0;ui<3;ui++) + pos[ui] = (size_t)round(point[ui]*(float)binCount[ui]); + + return voxels[pos[2]*binCount[1]*binCount[0] + pos[1]*binCount[0] + pos[0]]; +} + +template +Point3D Voxels::getPoint(size_t x, size_t y, size_t z) const +{ + ASSERT(x < binCount[0] && y +Point3D Voxels::getPitch() const +{ + return Point3D((float)1.0/(float)binCount[0]*(maxBound[0]-minBound[0]), + (float)1.0/(float)binCount[1]*(maxBound[1]-minBound[1]), + (float)1.0/(float)binCount[2]*(maxBound[2]-minBound[2])); +} + +template +void Voxels::getSize(size_t &x, size_t &y, size_t &z) const +{ + ASSERT(voxels.size()); + x=binCount[0]; + y=binCount[1]; + z=binCount[2]; +} + + +template +size_t Voxels::getEdgeIndex(size_t x,size_t y, size_t z, unsigned int index) const +{ + //This provides a reversable mapping of x,y,z + //X aligned edges are first + //Y second + //Z third + + + //Consider each parallel set of edges (eg all the X aligned edges) + //to be the dual grid of the actual grid. From this you can visualise the + //cell centres moving -1/2 -/12 units in the direction normal to the edge direction + //to produce the centres of the edge. An additional vertex needs to be created at + //the end of each dimension not equal to the alignement dim. + + + // ->ASCII ART TIME<- + // In each individual cube, the offsets look like this: + // ------------7----------- + // \ |\ . + // |\ | \ . + // | 10 | 11 + // | \ | \ . + // | \ | \ . + // | \ --------6-------------| + // | | | | + // 2 | 3 | | + // | | | | + // | | | | + // | | | | + // | 0 | 1 + // \-----|----5----------- | + // \ | \ | + // 8 | 9 | + // \ | \ | + // \ |---------4------------ + // + // ^x + // z|\ | + // \ | + // \-->y + // + + switch(index) + { + //X axis aligned + //-- + case 0: + break; + case 1: + y++; // one across in Y + break; + case 2: + z++;//One across in Z + break; + case 3: + y++; + z++; + break; + //-- + + //Y Axis aligned + //-- + case 4: + break; + case 5: + z++; + break; + case 6: + x++; + break; + case 7: + z++; + x++; + break; + //-- + + //Z Axis aligned + //-- + case 8: + break; + case 9: + y++; + break; + case 10: + x++; + break; + case 11: + x++; + y++; + break; + //-- + } + + + size_t result = 12*(z + y*(binCount[2]+1) + x*(binCount[2]+1)*(binCount[1]+1)) + + index; + + return result; + +} + +template +void Voxels::getEdgeEnds(size_t edgeUniqId, Point3D &a, Point3D &b ) const +{ + //Invert the mapping generated by the edgeUniqId function + //to retrieve the XYZ and axis values + size_t x,y,z; + + int index; // Per voxel edge number. See ascii art in getEdgeidx + index=edgeUniqId %12; + + //Drop the non-owner part of the voxel + index/=4; + index*=4; + + size_t tmp; + tmp=edgeUniqId; + tmp/=12; // shift out the index multiplier + + x = tmp/((binCount[2]+1)*(binCount[1]+1)); + tmp-=x*((binCount[2]+1)*(binCount[1]+1)); + + y=tmp/(binCount[2]+1); + tmp-=y*(binCount[2]+1); + + z=tmp; + + + + + ASSERT(x< binCount[0]+1 && y::epsilon())); + ASSERT(bc.containsPt(a) && bc.containsPt(b)); +#endif +} + +template +void Voxels::getEdgeEndApproxVals(size_t edgeUniqId, float &a, float &b ) const +{ + //Invert the mapping generated by the edgeUniqId function + //to retrieve the XYZ and axis values + size_t x,y,z; + + int index; // Per voxel edge number. See ascii art in getEdgeidx + index=edgeUniqId %12; + + size_t tmp; + tmp=edgeUniqId; + tmp/=12; // shift out the index multiplier + + x = tmp/((binCount[2]+1)*(binCount[1]+1)); + tmp-=x*((binCount[2]+1)*(binCount[1]+1)); + + y=tmp/(binCount[2]+1); + tmp-=y*(binCount[2]+1); + + z=tmp; + + + ASSERT(x< binCount[0]+1 && y +size_t Voxels::resize(size_t x, size_t y, size_t z, const Point3D &newMinBound, const Point3D &newMaxBound) +{ + voxels.clear(); + + binCount[0] = x; + binCount[1] = y; + binCount[2] = z; + + + minBound=newMinBound; + maxBound=newMaxBound; + + size_t binCountMax = binCount[0]*binCount[1]*binCount[2]; + try + { + voxels.resize(binCountMax); + } + catch(...) + { + return 1; + } + + return 0; +} + +template +size_t Voxels::resize(const Voxels &oth) +{ + return resize(oth.binCount[0],oth.binCount[1],oth.binCount[2],oth.minBound,oth.maxBound); +} + +template +size_t Voxels::resizeKeepData(size_t newX, size_t newY, size_t newZ, + unsigned int direction, const Point3D &newMinBound, const Point3D &newMaxBound, const T &fill,bool doFill) +{ + + ASSERT(direction==CLIP_LOWER_SOUTH_WEST); + ASSERT(callback); + + Voxels v; + + if(v.resize(newX,newY,newZ)) + return 1; + + switch(direction) + { + case CLIP_LOWER_SOUTH_WEST: + { + minBound=newMinBound; + maxBound=newMaxBound; + + if(doFill) + { + size_t itStop[3]; + itStop[0]=std::min(newX,binCount[0]); + itStop[1]=std::min(newY,binCount[1]); + itStop[2]=std::min(newZ,binCount[2]); + + size_t itMax[3]; + itMax[0]=std::max(newX,binCount[0]); + itMax[1]=std::max(newY,binCount[1]); + itMax[2]=std::max(newZ,binCount[2]); + //Duplicate into new value, if currently inside bounding box + //This logic will be a bit slow, owing to repeated "if"ing, but + //it is easy to understand. Other logics would have many more + //corner cases + bool spin=false; +#pragma omp parallel for + for(size_t ui=0;ui +Point3D Voxels::getMinBounds() const +{ + ASSERT(voxels.size()); + return minBound; +} + +template +Point3D Voxels::getMaxBounds() const +{ + ASSERT(voxels.size()); + return maxBound; +} + +template +void Voxels::setBounds(const Point3D &pMin, const Point3D &pMax) +{ + ASSERT(voxels.size()); + minBound=pMin; + maxBound=pMax; +} + +template +size_t Voxels::init(size_t nX, size_t nY, + size_t nZ, const BoundCube &bound) +{ + binCount[0]=nX; + binCount[1]=nY; + binCount[2]=nZ; + + typedef size_t ull; + ull binCountMax; + + ASSERT(bound.isValid()) + bound.getBounds(minBound, maxBound); + binCountMax= (ull)binCount[0]*(ull)binCount[1]*(ull)binCount[2]; + + voxels.resize(binCountMax); + +#pragma omp parallel for + for(size_t ui=0; ui +size_t Voxels::init(size_t nX, size_t nY, size_t nZ) + +{ + Point3D pMin(0,0,0), pMax(nX,nY,nZ); + + return init(nX,nY,nZ,pMin,pMax); +} + +template +size_t Voxels::loadFile(const char *cpFilename, size_t nX, size_t nY, size_t nZ , bool silent) +{ + std::ifstream CFile(cpFilename,std::ios::binary); + + if(!CFile) + return VOXELS_BAD_FILE_OPEN; + + CFile.seekg(0,std::ios::end); + + + size_t fileSize = CFile.tellg(); + if(fileSize !=nX*nY*nZ*sizeof(T)) + return VOXELS_BAD_FILE_SIZE; + + resize(nX,nY,nZ,Point3D(nX,nY,nZ)); + + CFile.seekg(0,std::ios::beg); + + unsigned int curBufferSize=ITEM_BUFFER_SIZE*sizeof(T); + unsigned char *buffer = new unsigned char[curBufferSize]; + + //Shrink the buffer size by factors of 2 + //in the case of small datasets + while(fileSize < curBufferSize) + curBufferSize = curBufferSize >> 1; + + + //Draw a progress bar + if(!silent) + { + cerr << std::endl << "|"; + for(unsigned int ui=0; ui<100; ui++) + cerr << "."; + cerr << "| 100%" << std::endl << "|"; + } + + unsigned int lastFrac=0; + unsigned int ui=0; + unsigned int pts=0; + do + { + + //Still have data? Keep going + while((size_t)CFile.tellg() <= fileSize-curBufferSize) + { + //Update progress bar + if(!silent && ((unsigned int)(((float)CFile.tellg()*100.0f)/(float)fileSize) > lastFrac)) + { + cerr << "."; + pts++; + lastFrac=(unsigned int)(((float)CFile.tellg()*100.0f)/(float)fileSize) ; + } + + //Read a chunk from the file + CFile.read((char *)buffer,curBufferSize); + + if(!CFile.good()) + return VOXELS_BAD_FILE_READ; + + //Place the chunk contents into ram + for(size_t position=0; position> 1 ; + + }while(curBufferSize> sizeof(T)); //This does a few extra loops. Not many + + delete[] buffer; + + //Fill out the progress bar + if(!silent) + { + while(pts++ <100) + cerr << "."; + + cerr << "| done" << std::endl; + } + + return 0; +} + +template +size_t Voxels::writeFile(const char *filename) const +{ + + ASSERT(voxels.size()) + + std::ofstream file(filename, std::ios::binary); + + if(!file) + return 1; + + + for(size_t ui=0; ui +T Voxels::getSum(const T &initialValue) const +{ + ASSERT(voxels.size()); + T returnVal=initialValue; + T val; +#pragma omp parallel for private(val) reduction(+:returnVal) + for(MP_INT_TYPE ui=0; ui +T Voxels::trapezIntegral() const +{ + //Compute volume prefactor - volume of cube of each voxel + //-- + float prefactor=1.0; + for(size_t ui=0;ui<3;ui++) + { + prefactor*=(maxBound[ui]- + minBound[ui])/ + (float)binCount[ui]; + } + + //-- + + + double accumulation(0.0); + //Loop across dataset integrating along z direction +#pragma omp parallel for reduction(+:accumulation) + for(size_t ui=0;ui +size_t Voxels::count(const T &minIntensity) const +{ + size_t bins; + bins=binCount[0]*binCount[1]*binCount[2]; + + size_t sum=0; +#pragma omp parallel for reduction(+:sum) + for(size_t ui=0;ui=minIntensity) + sum++; + } + + return sum; +} + +template +void Voxels::swap(Voxels &kernel) +{ + std::swap(binCount[0],kernel.binCount[0]); + std::swap(binCount[1],kernel.binCount[1]); + std::swap(binCount[2],kernel.binCount[2]); + + std::swap(voxels,kernel.voxels); + + std::swap(maxBound,kernel.maxBound); + std::swap(minBound,kernel.minBound); +} + +template +size_t Voxels::convolve(const Voxels &kernel, Voxels &result, size_t boundMode) const +{ + ASSERT(voxels.size()); + ASSERT(callback); + + //Check the kernel can fit within this datasest + size_t x,y,z; + kernel.getSize(x,y,z); + if(binCount[0] +size_t Voxels::separableConvolve(const Voxels &kernel, Voxels &result, size_t boundMode) +{ + ASSERT(voxels.size()); + + //Loop through all of the voxel elements, setting the + //result voxels to the convolution of the template + //with the data + + + Point3D resultMinBound, resultMaxBound; + size_t x,y,z; + unsigned long long half; + kernel.getSize(x,y,z); + half=x/2; + //Kernel needs to be cubic + ASSERT(x==y && y == z && (z%2)); + + if(boundMode!=BOUND_CLIP) + { + + resultMinBound=minBound; + resultMaxBound=maxBound; + + ASSERT(result.binCount[0] == binCount[0] && + result.binCount[1] == binCount[1] && + result.binCount[2] == binCount[2]); + + T tally; + + //Separable kernels can be repeatably convolved + //ie, f*g can be expressed as (f*g(x) + + // + + + if(x < binCount[0]/2) + { + //Convolve in X direction only + for(size_t uj=0;uj +T Voxels::getData(size_t x, size_t y, size_t z) const +{ + typedef size_t ull; + ASSERT(x < binCount[0] && y < binCount[1] && z < binCount[2]); + ull off; //byte offset + + //Typecast everything to at least 64 bit uints. + off=(ull)z*(ull)binCount[1]*(ull)binCount[0]; + off+=(ull)y*(ull)binCount[0] + (ull)x; + + ASSERT(off < voxels.size()); + return voxels[off]; +} + +template +T Voxels::getPaddedData(long long x, long long y, long long z, unsigned int padMode) const +{ + if(x >=0 && x<(long long)binCount[0] && y>=0 && y<(long long)binCount[1] && z>=0 && z <(long long)binCount[2]) + { + return getData(x,y,z); + } + + //OK, so we are not inside the dataset -- we have to guess + + switch(padMode) + { + case BOUND_ZERO: + return T(0); + case BOUND_MIRROR: + { + + if(x<0) + x=-x; + + if(y<0) + y=-y; + + if(z<0) + z=-z; + + if(x >=binCount[0]) + x=binCount[0]-(x-binCount[0]+1); + if(y >=binCount[1]) + y=binCount[1]-(y-binCount[1]+1); + if(z >=binCount[2]) + z=binCount[2]-(z-binCount[2]+1); + + + return getData(x,y,z); + } + default: + //Should only get here if we have not implemented the bound mode + ASSERT(false); + } + + ASSERT(false); +} + +template +void Voxels::setGaussianKernelCube(float stdDev, float bound, size_t sideLen) +{ + T obj; + + //Equi-variance multivariate normal distribution. + //https://en.wikipedia.org/wiki/Multivariate_normal_distribution#Density_function + // with identity covariance. (non-degenerate case) + // det|sigma| == (stddev^3) + const float product = 1.0/(pow(2.0*M_PI*stdDev,3.0/2.0)); + + float scale; + const float halfLen = sideLen/2; + + resize(sideLen,sideLen,sideLen); + + setBounds(Point3D(-bound/2.0f,-bound/2.0f,-bound/2.0f), + Point3D(bound/2.0f,bound/2.0f,bound/2.0f)); + + + //2*det(covariance matrix) + const float twoDetCov=2.0*stdDev*stdDev*stdDev; + + scale=bound/sideLen; + scale*=scale; + //Loop through the data, setting + // using probability density function + for(size_t ui=0;ui +void Voxels::secondDifference(Voxels &result, size_t boundMode) const +{ + //Only clipping mode is supported at this time + ASSERT(boundMode=BOUND_CLIP); + //Note: Central difference loses two values from each edge + ASSERT(binCount[0] > 2 && binCount[1] > 2 && binCount[2] > 2); + float xSqr,ySqr,zSqr; + + xSqr = (maxBound[0]-minBound[0])/binCount[0]; + + ySqr = (maxBound[1]-minBound[1])/binCount[1]; + + zSqr = (maxBound[2]-minBound[2])/binCount[2]; + + + + //Allocate the second difference result, with a bin wdith + //Note: We are bastardising the definition of xSqr for convenience here + //xSqr at this time is simply the grid pitch (same for ySqr,zSqr) + + result.resize(binCount[0]-2,binCount[1]-2,binCount[2]-2, + Point3D((binCount[0]-2)*xSqr, + (binCount[1]-2)*ySqr, + (binCount[2]-2)*zSqr)); + + + xSqr*=xSqr; + ySqr*=ySqr; + zSqr*=zSqr; + + + //Calculate del^2 + T d; +#pragma omp parallel for private(d) + for(MP_INT_TYPE ui=1; ui +void Voxels::thresholdForPosition(std::vector &p, const T &thresh, bool lowerEq) const +{ + p.clear(); + + if(lowerEq) + { +#pragma omp parallel for + for(MP_INT_TYPE ui=0;ui thresh) + { +#pragma omp critical + p.push_back(getPoint(ui,uj,uk)); + } + + } + } + } + } +} + +template +void Voxels::binarise(Voxels &result, const T &thresh, + const T &onThresh, const T &offThresh) const +{ + + result.resize(binCount[0],binCount[1], + binCount[2],minBound,maxBound); +#pragma omp parallel for + for(MP_INT_TYPE ui=0;ui<(MP_INT_TYPE)binCount[0]; ui++) + { + for(size_t uj=0;uj +void Voxels::rebin(Voxels &result, size_t rate, size_t clipDir) const +{ + //Check that the binsize can be reduced by this factor + //or clipping allowed + ASSERT(clipDir || ( !(binCount[0] % rate) && !(binCount[1] % rate) + && !(binCount[2] % rate))); + + //Datasets must be bigger than their clipping direction + ASSERT(binCount[0] > rate && binCount[1] && rate && binCount[2] > rate); + + + size_t newBin[3]; + newBin[0]=binCount[0]/rate; + newBin[1]=binCount[1]/rate; + newBin[2]=binCount[2]/rate; + + + //Clipping not implmented! + ASSERT(clipDir == CLIP_NONE); + + result.resize(newBin[0],newBin[1],newBin[2],getMinBounds(), getMaxBounds()); + //Draw a progress bar + cerr << std::endl << "|"; + for(unsigned int ui=0; ui<100; ui++) + cerr << "."; + cerr << "| 100%" << std::endl << "|"; + + size_t its=0; + unsigned int progress =0; + float itsToDo = binCount[0]/rate; +#pragma omp parallel for shared(progress,its) + for(MP_INT_TYPE ui=0; ui +void Voxels::makeSphericalKernel(size_t sideLen, float bound, const T &val, unsigned int antialiasLevel) +{ + + const size_t halfLen = sideLen/2; + float sqrSideLen=(float)halfLen*(float)halfLen; + resize(sideLen,sideLen,sideLen,Point3D(bound,bound,bound)); + + if(!antialiasLevel) + { + //Loop through the data + //This could be sped up using decrementing whiles, + //at the cost of losing the openMP bit +#pragma omp parallel for shared(sqrSideLen) + for(MP_INT_TYPE ui=0;ui (float)sqrSideLen && insideSphere)) + { + //We have to do a full volume fraction + //calculation to compute the value of this voxel + fullCalc=true; + break; + } + } + + + if(fullCalc) + { + //Compute volume fraction + + //The method we use is a recursive divide & measure approach + //We chop the voxel into eight half size voxels, then check + //to see which lie in the sphere, and which dont. + std::stack > positionStack; + float value,x,y,z; + value=0; + //Push this voxel's 8 sub-voxel's centres onto the stack + //to kick things off + for(int off=0;off<8; off++) //CRITICAL that off is an int for bitmask + { + //the right hand part of the addition should + //flip between -0.5 and +0.5 alternately + x= ui + 0.5*(2*(off &1)-1); + y= uj + 0.5*((off &2)-1); + z= uk + 0.5*(0.5*(off &4)-1); + + positionStack.push(std::make_pair(Point3D(x,y,z),0)); + } + + //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)) + while(!positionStack.empty()) + { + unsigned int thisLevel; + float thisLen; + Point3D thisCentre; + + thisCentre = positionStack.top().first; + thisLevel = positionStack.top().second; + positionStack.pop(); + + + //Side length for this voxel + thisLen = pow(2.0,-((int)thisLevel+1))*halfLen; + //Calculate r^2 from sphere centre for each corner + for(int off=0;off<8; off++) //critical that off is int for bitmasking + { + x= thisCentre[0] + (2*(off &1)-1)*thisLen; + y= thisCentre[1] + ((off &2)-1)*thisLen; + z= thisCentre[2] + (0.5*(off &4)-1)*thisLen; + + offset[off] = (x - halfLen)*(x-halfLen) + (y-halfLen)*(y-halfLen) + + (z-halfLen)*(z-halfLen); + } + + insideSphere= offset[0] < (float)sqrSideLen; + fullCalc=false; + + //Spin through each to check if this is a border-straddling voxel + for(int off=1;off<8; off++) + { + if( (offset[off] < (float)sqrSideLen && !insideSphere) || + (offset[off] > (float)sqrSideLen && insideSphere)) + { + //We have to do a full volume fraction + //calculation to compute the value of this voxel + fullCalc=true; + break; + } + } + + //OK, the action to take now depends on whether we need to subdivide or not + if(thisLevel < antialiasLevel && fullCalc) + { + for(int off=0;off<8; off++) //Critical that off is signed for bitmask + { + x= thisCentre[0] + (2*(off &1)-1)*thisLen; + y= thisCentre[1] + ((off &2)-1)*thisLen; + z= thisCentre[2] + (0.5*(off &4)-1)*thisLen; + + positionStack.push(std::make_pair(Point3D(x,y,z),thisLevel+1)); + } + } + else + { + if(fullCalc) + { + //Lets just call it a half shall we + value+=pow(2.0,-(((int)thisLevel+1)*3+1)); + + } + else + { + //Voxel is either wholly within, or without + //If inside sphere, add to internal volume + //otherwise we "add zero" - ie do nothing + if(insideSphere) + value+=pow(2.0,-((int)thisLevel+1)*3); + } + } + + } + + + setData(ui,uj,uk,value*val); + } + else + setData(ui,uj,uk,((int)insideSphere)*val); + } + } + } + } + +} + +template +T Voxels::min() const +{ + ASSERT(voxels.size()); + size_t numPts = binCount[0]*binCount[1]*binCount[2]; + T minVal; + minVal = voxels[0]; +#ifdef _OPENMP + //Unfortunately openMP doesn't lend itself well here + //But we can code around it. + size_t maxThr = omp_get_max_threads(); + T minArr[maxThr]; + //Init all mins + for(size_t ui=0; ui +T Voxels::max() const +{ + ASSERT(voxels.size()); + size_t numPts = binCount[0]*binCount[1]*binCount[2]; + T maxVal; + maxVal = voxels[0]; +#ifdef _OPENMP + //Unfortunately openMP doesn't lend itself well here + //But we can code around it. + size_t maxThr = omp_get_max_threads(); + T maxArr[maxThr]; + //Init all maxs + for(size_t ui=0; ui +void Voxels::minMax(T &minVal,T &maxVal) const +{ + ASSERT(voxels.size()); + size_t numPts = binCount[0]*binCount[1]*binCount[2]; + maxVal=voxels[0]; + minVal=voxels[0]; +#ifdef _OPENMP + //Unfortunately openMP doesn't lend itself well here + //But we can code around it. + size_t maxThr = omp_get_max_threads(); + T minArr[maxThr],maxArr[maxThr]; + //Init all maxs + for(size_t ui=0; ui +void Voxels::fillSpheresByPosition( const std::vector &spherePos, float rad, const T &value, bool doErase) +{ + + //I haven't though this through for non cubic datasets + ASSERT((maxBound[0]-minBound[0]) == (maxBound[1]-minBound[1])); + ASSERT((maxBound[1]-minBound[1]) == (maxBound[2]-minBound[2])); + ASSERT(binCount[0] == binCount[1]); + ASSERT(binCount[1] == binCount[2]); + + //Size of rectangular box that contains the sphere + size_t numBlocks[3]; + numBlocks[0] = (size_t)(2.0*rad*binCount[0]/(maxBound[0]-minBound[0])); + numBlocks[1] = (size_t)(2.0*rad*binCount[1]/(maxBound[1]-minBound[1])); + numBlocks[2] = (size_t)(2.0*rad*binCount[2]/(maxBound[2]-minBound[2])); + + //Construct the sphere kernel + std::vector vX,vY,vZ; + float sqrRad=(float)numBlocks[0]*(float)numBlocks[0]/4.0f; +#pragma omp parallel for + for(MP_INT_TYPE ui=0;ui 0 && + p[1] < binCount[1] && p[1] > 0 && + p[2] < binCount[2] && p[2] > 0) + { +#pragma omp critical + setData(p[0],p[1],p[2],value); + } + + } + + } +} + + +template +int Voxels::countPoints( const std::vector &points, bool noWrap, bool doErase) +{ + ASSERT(callback); + if(doErase) + { + fill(0); + } + + size_t x,y,z; + + unsigned int downSample=MAX_CALLBACK; + for(size_t ui=0; ui getData(x,y,z)) + setData(x,y,z,value); + } else { + setData(x,y,z,value); + } + } + } + } + + return 0; +} + +template +void Voxels::calculateDensity() +{ + Point3D size = maxBound - minBound; + // calculate the volume of a voxel + double volume = 1.0; + for (int i = 0; i < 3; i++) + volume *= size[i] / binCount[i]; + + // normalise the voxel value based on volume +#pragma omp parallel for + for(size_t ui=0; ui +float Voxels::getBinVolume() const +{ + Point3D size = maxBound - minBound; + double volume = 1.0; + for (int i = 0; i < 3; i++) + volume *= size[i] / binCount[i]; + + return volume; +} + +template +void Voxels::getIndex(size_t &x, size_t &y, + size_t &z, const Point3D &p) const +{ + + ASSERT(p[0] >=minBound[0] && p[1] >=minBound[1] && p[2] >=minBound[2] && + p[0] <=maxBound[0] && p[1] <=maxBound[1] && p[2] <=maxBound[2]); + x=(size_t)((p[0]-minBound[0])/(maxBound[0]-minBound[0])*(float)binCount[0]); + y=(size_t)((p[1]-minBound[1])/(maxBound[1]-minBound[1])*(float)binCount[1]); + z=(size_t)((p[2]-minBound[2])/(maxBound[2]-minBound[2])*(float)binCount[2]); +} + +template +void Voxels::getIndexWithUpper(size_t &x, size_t &y, + size_t &z, const Point3D &p) const +{ + //Get the data index as per normal + getIndex(x,y,z,p); + + //but, as a special case, if the index is the same as our bincount, check + //to see if it is positioned on an edge + if(x==binCount[0] && + fabs(p[0] -maxBound[0]) < sqrt(std::numeric_limits::epsilon())) + x--; + if(y==binCount[1] && + fabs(p[1] -maxBound[1]) < sqrt(std::numeric_limits::epsilon())) + y--; + if(z==binCount[2] && + fabs(p[2] -maxBound[2]) < sqrt(std::numeric_limits::epsilon())) + z--; + +} + +template +void Voxels::fill(const T &v) +{ + size_t nBins = binCount[0]*binCount[1]*binCount[2]; + +#pragma omp parallel for + for(MP_INT_TYPE ui=0;ui<(MP_INT_TYPE)nBins; ui++) + voxels[ui]=v; +} + + +template +int Voxels::histogram(std::vector &v, size_t histBinCount) const +{ + ASSERT(callback); + + T maxVal=max(); + T minVal=min(); + +#ifdef _OPENMP + //We need an array for each thread to store results + size_t *vals; + + vals = new size_t[omp_get_max_threads()*histBinCount]; + + //Zero out the array + for(size_t ui=0;ui +void Voxels::findSorted(std::vector &x, std::vector &y, + std::vector &z, size_t n, bool largest) const +{ + //Could be better if we didn't use indexed data aquisition (record opsition) + std::deque bSx,bSy,bSz; + + if(voxels.empty()) + return; + + T curBest; + curBest=getData(0); + + //It is theoretically possible to rewrite this without locking (critical sections). + if(largest) + { + + for(size_t ui=0;ui curBest) + { +#pragma omp critical + { + bSx.push_front(ui); + bSy.push_front(uj); + bSz.push_front(uk); + curBest=getData(ui,uj,uk); + } + } + + } + } + } + + } + else + { + for(size_t ui=0;ui +void Voxels::operator/=(const Voxels &v) +{ + ASSERT(v.voxels.size() == voxels.size()); +#pragma omp parallel for + for (size_t i = 0; i < voxels.size(); i++) + { + if(v.voxels[i]) + voxels[i]/=(v.voxels[i]); + else + voxels[i] =0; + } +} + + +template +void Voxels::operator/=(const T &v) +{ + ASSERT(v); +#pragma omp parallel for + for (size_t i = 0; i < voxels.size(); i++) + voxels[i]/=v; +} + +template +bool Voxels::operator==(const Voxels &v) const +{ + for(size_t ui=0;ui<3;ui++) + { + + if(v.binCount[ui] != binCount[ui]) + return false; + } + + for(size_t ui=0;ui. + */ +#include "xmlHelper.h" + +#include + +//Convert a normal string sequence into an XML escaped sequence +std::string escapeXML(const std::string &input) +{ + size_t strLen= input.size(); + std::string output; + for (size_t ui = 0; ui < strLen; ui++) + { + char c; + c= input[ui]; + if (c == '&') + output+=("&"); + else if (c == '<') + output+=("<"); + else if (c == '>') + output+=(">"); + else if (c == '"') + output+=("""); + else if (c == '\'') + output+=("'"); + else + output+=c; + } + return output; +} + + +//Convert an xml escaped sequence into a normal string sequence +//Re-used under GPL v3+ From: +//http://svn.lsdcas.engineering.uiowa.edu/repos/lsdcas/trunk/cas2/libcas/xml.cc +//accessed 3 Mar 2012 +std::string unescapeXML(const std::string &input) +{ + const char* chars = "<>'\"&" ; + const char* refs[] = + { + "<", + ">", + "'", + """, + "&", + 0 + } ; + + std::string data=input; + for( size_t i = 0 ; refs[i] != NULL ; i++ ) + { + std::string::size_type pos = data.find( refs[i] ) ; + + while( pos != std::string::npos ) + { + std::stringstream unescaped ; + unescaped << data.substr( 0, pos ) + << chars[i] + << data.substr( pos + strlen( refs[i] ) ) ; + + data = unescaped.str() ; + pos = data.find( refs[i], pos + strlen( refs[i] ) ) ; + } + } + + return data ; +} + + + +unsigned int XMLHelpNextType(xmlNodePtr &node, int nodeType) +{ + do + { + node= node->next; + if(!node) + return 1; + } + while(node->type != nodeType); + return 0; +} + +//returns zero on success, nonzero on fail +unsigned int XMLHelpFwdToElem(xmlNodePtr &node, const char *nodeName) +{ + do + { + node=node->next; + }while(node != NULL && + xmlStrcmp(node->name,(const xmlChar *) nodeName)); + return (!node); +} + + diff -Nru 3depict-0.0.12/src/common/xmlHelper.h 3depict-0.0.13/src/common/xmlHelper.h --- 3depict-0.0.12/src/common/xmlHelper.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/common/xmlHelper.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * XMLHelper.h - libXML2 wrapper functions + * 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 . + */ + +#ifndef XMLHELPER_H +#define XMLHELPER_H + +//Undefs are because wxwidgets and libxml both define this +#ifdef ATTRIBUTE_PRINTF + #pragma push_macro("ATTRIBUTE_PRINTF") + #include + #pragma pop_macro(" ATTRIBUTE_PRINTF") +#else + #include + #undef ATTRIBUTE_PRINTF +#endif +#include +using std::string; + +#include "common/basics.h" + +//These functions return nonzero on failure, +//zero on success +//be warned that the node WILL be modified. + +//Jump to next element that is of a given type (eg text, node, comment etc) +//see EOF for more details. Returns nonzero on error +unsigned int XMLHelpNextType(xmlNodePtr &node,int); +//Scroll forwards until we reach an element of a given node. return nonzero on error +unsigned int XMLHelpFwdToElem(xmlNodePtr &node, const char *nodeName); + +//Convert a normal string sequence into an XML escaped sequence +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 +//returns false on failure +//NOTE: Do not use if your value may validly contain whitespace. stream_cast skips these cases +template +bool XMLGetNextElemAttrib(xmlNodePtr &nodePtr, T &v, const char *nodeName, const char *attrib) +{ + std::string tmpStr; + xmlChar *xmlString; + //==== + if(XMLHelpFwdToElem(nodePtr,nodeName)) + return false; + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)attrib); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(v,tmpStr)) + { + xmlFree(xmlString); + return false; + } + + xmlFree(xmlString); + + return true; +} + + +//Returns false on failure +//Do not use on validly whitespace containing XML +template +bool XMLGetAttrib(xmlNodePtr &nodePtr, T&v, const char *attrib) +{ + std::string tmpStr; + xmlChar *xmlString; + //==== + + xmlString=xmlGetProp(nodePtr,(const xmlChar *)attrib); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + + if(stream_cast(v,tmpStr)) + { + xmlFree(xmlString); + return false; + } + + xmlFree(xmlString); + + return true; +} + +/* Defined in the bowels of the xmlLib2 library + * Enum xmlElementType { + * XML_ELEMENT_NODE = 1 + * XML_ATTRIBUTE_NODE = 2 + * XML_TEXT_NODE = 3 + * XML_CDATA_SECTION_NODE = 4 + * XML_ENTITY_REF_NODE = 5 + * XML_ENTITY_NODE = 6 + * XML_PI_NODE = 7 + * XML_COMMENT_NODE = 8 + * XML_DOCUMENT_NODE = 9 + * XML_DOCUMENT_TYPE_NODE = 10 + * XML_DOCUMENT_FRAG_NODE = 11 + * XML_NOTATION_NODE = 12 + * XML_HTML_DOCUMENT_NODE = 13 + * XML_DTD_NODE = 14 + * XML_ELEMENT_DECL = 15 + * XML_ATTRIBUTE_DECL = 16 + * XML_ENTITY_DECL = 17 + * XML_NAMESPACE_DECL = 18 + * XML_XINCLUDE_START = 19 + * XML_XINCLUDE_END = 20 + * XML_DOCB_DOCUMENT_NODE = 21 + * } + */ +#endif + diff -Nru 3depict-0.0.12/src/commonConstants.h 3depict-0.0.13/src/commonConstants.h --- 3depict-0.0.12/src/commonConstants.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/commonConstants.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * commonConstants.h - Common constants used across program - * 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 - * 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 . - */ -#ifndef COMMONCONSTANTS_H -#define COMMONCONSTANTS_H -//Plot styles -enum -{ - PLOT_TRACE_LINES=0, - PLOT_TRACE_BARS, - PLOT_TRACE_STEPS, - PLOT_TRACE_STEM, - PLOT_TRACE_POINTS, - PLOT_TRACE_ENDOFENUM -}; - -//Plot types -enum -{ - PLOT_MODE_1D, - PLOT_MODE_2D, - PLOT_MODE_ENUM_END -}; - - -//Plot error types -enum -{ - PLOT_ERROR_NONE, - PLOT_ERROR_MOVING_AVERAGE, - PLOT_ERROR_ENDOFENUM -}; - -//!State file output formats -enum -{ - STATE_FORMAT_XML=1 -}; - -//!Property types for wxPropertyGrid -enum -{ - PROPERTY_TYPE_BOOL=1, - PROPERTY_TYPE_INTEGER, - PROPERTY_TYPE_REAL, - PROPERTY_TYPE_COLOUR, - PROPERTY_TYPE_STRING, - PROPERTY_TYPE_POINT3D, - PROPERTY_TYPE_CHOICE, - PROPERTY_TYPE_ENUM_END //Not a prop, just end of enum -}; - - -//!Movement types for plot -enum -{ - REGION_MOVE_EXTEND_XMINUS, - REGION_MOVE_TRANSLATE_X, - REGION_MOVE_EXTEND_XPLUS -}; - -//!Data holder for colour as float -typedef struct RGBf -{ - float red; - float green; - float blue; -} RGBf; - -//!Structure to handle error bar drawing in plot -struct PLOT_ERROR -{ - //!Plot data estimator mode - unsigned int mode; - //!Number of data points for moving average - unsigned int movingAverageNum; - //!Edge mode - unsigned int edgeMode; -}; - -#endif diff -Nru 3depict-0.0.12/src/configFile.cpp 3depict-0.0.13/src/configFile.cpp --- 3depict-0.0.12/src/configFile.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/configFile.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,709 +0,0 @@ -/* - * configFile.cpp - User configuration loading/saving - * Copyright (C) 2012, 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 . -*/ - -#include "configFile.h" -#include "wxcommon.h" - -#include "xmlHelper.h" - -#include "filters/allFilter.h" - -#include "translation.h" - - -const char *CONFIG_FILENAME="config.xml"; - -const unsigned int MAX_RECENT=9; - -const unsigned int MAX_MOUSE_PERCENT= 400; - - - -#include - -#include -#include -#include -#include -#include - -using std::endl; -using std::string; - - -ConfigFile::ConfigFile() : configLoadOK(false), panelMode(CONFIG_PANELMODE_REMEMBER), - haveIntialAppSize(false), mouseZoomRatePercent(100),mouseMoveRatePercent(100), - allowOnline(true), allowOnlineVerCheck(true), leftRightSashPos(0), - topBottomSashPos(0),filterSashPos(0),plotListSashPos(0) - -{ -} - - -ConfigFile::~ConfigFile() -{ - for(unsigned int ui=0;ui MAX_RECENT) - recentFiles.pop_front(); -} - -void ConfigFile::getRecentFiles(std::vector &files) const -{ - files.resize(recentFiles.size()); - std::copy(recentFiles.begin(),recentFiles.end(),files.begin()); -} - -void ConfigFile::removeRecentFile(const std::string &str) -{ - std::deque::iterator it; - it=std::find(recentFiles.begin(),recentFiles.end(),str); - - if(it!=recentFiles.end()) - recentFiles.erase(it); -} - -void ConfigFile::getFilterDefaults(vector &defs) -{ - defs.resize(filterDefaults.size()); - std::copy(filterDefaults.begin(),filterDefaults.end(),defs.begin()); -} -void ConfigFile::setFilterDefaults(const vector &defs) -{ - for(unsigned int ui=0;uicanBeHazardous())); - } -} - - - -bool ConfigFile::getInitialAppSize(unsigned int &x, unsigned int &y) const -{ - if(haveIntialAppSize) - { - x=initialSizeX; - y=initialSizeY; - } - - return haveIntialAppSize; -} - -void ConfigFile::setInitialAppSize(unsigned int x, unsigned int y) -{ - haveIntialAppSize=true; - initialSizeX=x; - initialSizeY=y; -} - -Filter *ConfigFile::getDefaultFilter(unsigned int type) const -{ - for(unsigned int ui=0;uigetType()) - { - ASSERT(!filterDefaults[ui]->canBeHazardous()); - return filterDefaults[ui]->cloneUncached(); - } - } - - return makeFilter(type); -} - -unsigned int ConfigFile::read() -{ - string filename; - filename = getConfigDir() + std::string("/") + std::string(CONFIG_FILENAME); - - //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) - { - return CONFIG_ERR_NOPARSER; - } - - //Open the XML file again, but without DTD validation - doc = xmlCtxtReadFile(context, filename.c_str(), NULL, 0); - - if(!doc) - return CONFIG_ERR_NOFILE; - - //release the context - xmlFreeParserCtxt(context); - - //retrieve root node - xmlNodePtr nodePtr = xmlDocGetRootElement(doc); - - - try - { - std::stack nodeStack; - - //Umm where is our root node guys? - if(!nodePtr) - throw 1; - - //push root tag - nodeStack.push(nodePtr); - - //This *should* be an threeDepict state file - if(xmlStrcmp(nodePtr->name, (const xmlChar *)"threeDepictconfig")) - { - errMessage=TRANS("Config file present, but is not valid (root node test)"); - throw 1; - } - - //push root node - nodeStack.push(nodePtr); - nodePtr=nodePtr->xmlChildrenNode; - - //push not quite root tag - nodeStack.push(nodePtr); - if(!XMLHelpFwdToElem(nodePtr,"initialwinsize")) - { - if(XMLGetAttrib(nodePtr, initialSizeX, "width") && - XMLGetAttrib(nodePtr,initialSizeY,"height")) - { - if( initialSizeX >0 && initialSizeY > 0) - haveIntialAppSize=true; - } - } - nodePtr=nodeStack.top(); - nodeStack.pop(); - - - //Clean up current configuration - recentFiles.clear(); - - if(!XMLHelpFwdToElem(nodePtr,"recent")) - { - nodeStack.push(nodePtr); - nodePtr=nodePtr->xmlChildrenNode; - - - std::string thisName; - while(!XMLHelpFwdToElem(nodePtr,"file") && recentFiles.size() < MAX_RECENT) - { - xmlChar *xmlString; - - //read name of file - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); - if(!xmlString) - { - errMessage=TRANS("Unable to interpret recent file entry"); - throw 1; - } - thisName=(char *)xmlString; - - recentFiles.push_back(thisName); - - xmlFree(xmlString); - } - } - - //restore old node - nodePtr=nodeStack.top(); - nodeStack.pop(); - - //Advance and push - if(!nodePtr->next) - goto nodeptrEndJump; - - nodePtr=nodePtr->next; - nodeStack.push(nodePtr); - - if(!XMLHelpFwdToElem(nodePtr,"filterdefaults")) - { - nodePtr=nodePtr->xmlChildrenNode; - - if(nodePtr) - { - - - while(!XMLHelpNextType(nodePtr,XML_ELEMENT_NODE)) - { - string s; - - s=(char *)(nodePtr->name); - Filter *f; - f=makeFilter(s); - - if(!f) - { - errMessage=TRANS("Unable to determine filter type in defaults listing."); - throw 1; - } - - - //potentially hazardous filters cannot have their - //default properties altered. Quietly drop them - if(!f->canBeHazardous()) - { - nodeStack.push(nodePtr); - nodePtr=nodePtr->xmlChildrenNode; - if(f->readState(nodePtr)) - filterDefaults.push_back(f); - - nodePtr=nodeStack.top(); - nodeStack.pop(); - } - } - - } - } - - //restore old node - nodePtr=nodeStack.top(); - nodeStack.pop(); - - //Advance and push - if(!nodePtr->next) - goto nodeptrEndJump; - - nodePtr=nodePtr->next; - nodeStack.push(nodePtr); - if(!XMLHelpFwdToElem(nodePtr,"startuppanels")) - { - startupPanelView.resize(CONFIG_STARTUPPANEL_END_ENUM); - - std::string tmpStr; - xmlChar *xmlString; - xmlString=xmlGetProp(nodePtr,(xmlChar*)"mode"); - - if(xmlString) - { - tmpStr=(char*)xmlString; - stream_cast(panelMode,tmpStr); - - if(panelMode >=CONFIG_PANELMODE_END_ENUM) - panelMode=CONFIG_PANELMODE_NONE; - - xmlFree(xmlString); - } - - if(panelMode) - { - xmlString=xmlGetProp(nodePtr,(xmlChar*)"rawdata"); - if(xmlString) - { - - tmpStr=(char *)xmlString; - if(tmpStr == "1") - startupPanelView[CONFIG_STARTUPPANEL_RAWDATA]=true; - else - startupPanelView[CONFIG_STARTUPPANEL_RAWDATA]=false; - - xmlFree(xmlString); - } - - xmlString=xmlGetProp(nodePtr,(xmlChar*)"control"); - if(xmlString) - { - - tmpStr=(char *)xmlString; - if(tmpStr == "1") - startupPanelView[CONFIG_STARTUPPANEL_CONTROL]=true; - else - startupPanelView[CONFIG_STARTUPPANEL_CONTROL]=false; - xmlFree(xmlString); - } - - xmlString=xmlGetProp(nodePtr,(xmlChar*)"plotlist"); - if(xmlString) - { - - tmpStr=(char *)xmlString; - if(tmpStr == "1") - startupPanelView[CONFIG_STARTUPPANEL_PLOTLIST]=true; - else - startupPanelView[CONFIG_STARTUPPANEL_PLOTLIST]=false; - xmlFree(xmlString); - } - - } - } - - //restore old node - nodePtr=nodeStack.top(); - nodeStack.pop(); - - //Advance and push, as needed - if(!nodePtr->next) - goto nodeptrEndJump; - - nodePtr=nodePtr->next; - nodeStack.push(nodePtr); - if(!XMLHelpFwdToElem(nodePtr,"mousedefaults")) - { - xmlNodePtr mouseDataNodePtr=nodePtr->xmlChildrenNode; - if(mouseDataNodePtr) - { - nodeStack.push(mouseDataNodePtr); - if(!XMLHelpFwdToElem(mouseDataNodePtr,"speed")) - { - unsigned int percentage; - if(XMLGetAttrib(mouseDataNodePtr,percentage,"zoom") && percentage next; - nodeStack.push(nodePtr); - if(!XMLHelpFwdToElem(nodePtr,"netaccess")) - { - std::string tmpStr; - xmlChar *xmlString; - - xmlString=xmlGetProp(nodePtr,(xmlChar*)"enabled"); - if(xmlString) - { - tmpStr=(char *)xmlString; - - if(!(tmpStr == "1" || tmpStr == "0")) - throw 1; - - allowOnline = (tmpStr == "1"); - xmlFree(xmlString); - } - - if(nodePtr->xmlChildrenNode) - { - nodePtr=nodePtr->xmlChildrenNode; - - if(!XMLHelpFwdToElem(nodePtr,"versioncheck")) - { - xmlChar *xmlString; - - xmlString=xmlGetProp(nodePtr,(xmlChar*)"enabled"); - if(xmlString) - { - tmpStr=(char *)xmlString; - if(!(tmpStr == "1" || tmpStr == "0")) - throw 1; - - allowOnlineVerCheck = (tmpStr == "1"); - xmlFree(xmlString); - } - - } - } - } - nodePtr=nodeStack.top(); - nodeStack.pop(); - - - nodeStack.push(nodePtr); - if(!XMLHelpFwdToElem(nodePtr,"sashposition")) - { - if(nodePtr->xmlChildrenNode) - { - nodePtr=nodePtr->xmlChildrenNode; - - while(!XMLHelpFwdToElem(nodePtr,"pos")) - { - - string name; - if(XMLGetAttrib(nodePtr, name,"name")) - { - if(name == "topbottom") - XMLGetAttrib(nodePtr,topBottomSashPos,"value"); - if(name == "leftright") - XMLGetAttrib(nodePtr,leftRightSashPos,"value"); - if(name == "filter") - XMLGetAttrib(nodePtr,filterSashPos,"value"); - if(name == "plotlist") - XMLGetAttrib(nodePtr,plotListSashPos,"value"); - } - - nodePtr=nodePtr->next; - } - } - } - nodePtr=nodeStack.top(); - nodeStack.pop(); -nodeptrEndJump: - ; - - } - catch (int) - { - //Code threw an error, just say "bad parse" and be done with it - xmlFreeDoc(doc); - return CONFIG_ERR_BADFILE; - } - - - xmlFreeDoc(doc); - - configLoadOK=true; - return 0; - -} - -bool ConfigFile::createConfigDir() -{ - wxString filePath = wxStr(getConfigDir()); - - //Create the folder if it does not exist - if(!wxDirExists(filePath)) - { - if(!wxMkdir(filePath)) - return false; - - //Make it a hidden folder -#if defined(__WIN32) || defined(__WIN64) - SetFileAttributes(filePath.wc_str(),FILE_ATTRIBUTE_HIDDEN); -#endif - } - - return true; -} - -std::string ConfigFile::getConfigDir() -{ - wxStandardPaths *paths = new wxStandardPaths; - wxString filePath = paths->GetDocumentsDir()+wxCStr("/.")+wxCStr(PROGRAM_NAME); - - delete paths; - - return stlStr(filePath); -} - - -bool ConfigFile::write() -{ - string filename; - - if(!createConfigDir()) - return false; - - filename = getConfigDir() + std::string("/") + std::string(CONFIG_FILENAME); - - //Open file for output - std::ofstream f(filename.c_str()); - - if(!f) - return false; - - //Write state open tag - f<< "" << endl; - f<" << endl; - - if(haveIntialAppSize) - { - f<" << endl; - } - - f<" << endl; - - for(unsigned int ui=0;ui" << endl; - - f<< tabs(1) << "" << endl; - - f<< tabs(1) << "" << endl; - - for(unsigned int ui=0;uiwriteState(f,STATE_FORMAT_XML,2); - f<< tabs(1) << "" << endl; - - if(startupPanelView.size()) - { - ASSERT(startupPanelView.size() == CONFIG_STARTUPPANEL_END_ENUM); - - f << tabs(1) << "" << endl; - } - - f << tabs(1) << " " << endl; - f << tabs(2) << "" << endl; - f << tabs(1) << " " << endl; - - //Online access settings -#if (!defined(__APPLE__) && !defined(WIN32)) - f << tabs(1) <<"" << endl; -#endif - f << tabs(1) << " " << endl; - - f << tabs(2) << " " << endl; - - f << tabs(1) << "" << endl; - - - //Online access settings - f << tabs(1) << "" << endl; - if(topBottomSashPos) - f << tabs(2) << "" << endl; - if(leftRightSashPos) - f << tabs(2) << "" << endl; - if(filterSashPos) - f << tabs(2) << "" << endl; - if(plotListSashPos) - f << tabs(2) << "" << endl; - f << tabs(1) << "" << endl; - - f << "" << endl; - - ASSERT(isValidXML(filename.c_str())); - - return true; -} - -bool ConfigFile::getPanelEnabled(unsigned int panelID) const -{ - ASSERT(panelID < CONFIG_STARTUPPANEL_END_ENUM); - - switch(panelMode) - { - case CONFIG_PANELMODE_NONE: - return true; - case CONFIG_PANELMODE_REMEMBER: - case CONFIG_PANELMODE_SPECIFY: - if(startupPanelView.size()) - { - ASSERT(startupPanelView.size() == CONFIG_STARTUPPANEL_END_ENUM); - return startupPanelView[panelID]; - } - else - return true; - default: - ASSERT(false); - } -} - -void ConfigFile::setPanelEnabled(unsigned int panelID, bool enabled, bool permanent) -{ - ASSERT(panelID < CONFIG_STARTUPPANEL_END_ENUM); - - //Create the vector as neeeded, filling with default of "enbaled" - if(startupPanelView.empty()) - startupPanelView.resize(CONFIG_STARTUPPANEL_END_ENUM,true); - - ASSERT(startupPanelView.size() == CONFIG_STARTUPPANEL_END_ENUM); - - if(panelMode != CONFIG_PANELMODE_SPECIFY || permanent) - startupPanelView[panelID] = enabled; -} - -void ConfigFile::setStartupPanelMode(unsigned int panelM) -{ - ASSERT(panelM < CONFIG_PANELMODE_END_ENUM); - panelMode=panelM; -} - -unsigned int ConfigFile::getStartupPanelMode() const -{ - return panelMode; -} - - -bool ConfigFile::getAllowOnlineVersionCheck() const -{ - #if defined(WIN32) - //apple crashes wx, and windows don't have good package - //management systems as yet, so we check, - //iff the user opts in - return allowOnlineVerCheck; - #else - //Linux and friends should NEVER look online. - //as they have package management systems to do this. - return false; - #endif -} - -void ConfigFile::setAllowOnline(bool v) -{ - //Do not allow this setting to - //be modified from the default for non-apple-non windows - //platforms - #if defined( __APPLE__) || defined(WIN32) - allowOnline=v; - #endif -} -void ConfigFile::setAllowOnlineVersionCheck(bool v) -{ - //Do not allow this setting to - //be modified from the default for non windows and apple crashes wx - //platforms - #if defined(WIN32) - allowOnlineVerCheck=v; - #endif -} - - -void ConfigFile::setLeftRightSashPos(float fraction) -{ - ASSERT(fraction <= 1.0f && fraction >=0.0f); - leftRightSashPos=fraction; -} - -void ConfigFile::setTopBottomSashPos(float fraction) -{ - ASSERT(fraction <= 1.0f && fraction >=0.0f); - topBottomSashPos=fraction; -} - - -void ConfigFile::setFilterSashPos(float fraction) -{ - ASSERT(fraction <= 1.0f && fraction >=0.0f); - filterSashPos=fraction; -} - - -void ConfigFile::setPlotListSashPos(float fraction) -{ - ASSERT(fraction <= 1.0f && fraction >=0.0f); - plotListSashPos=fraction; -} - - diff -Nru 3depict-0.0.12/src/configFile.h 3depict-0.0.13/src/configFile.h --- 3depict-0.0.12/src/configFile.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/configFile.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -/* - * configFile.h - Configuration file management header - * 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 - * 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 . - */ - -#ifndef CONFIGFILE_H -#define CONFIGFILE_H - - -#include "filter.h" - -#include -#include -#include - -//!Startup panel identifiers. -enum { - CONFIG_STARTUPPANEL_RAWDATA, - CONFIG_STARTUPPANEL_CONTROL, - CONFIG_STARTUPPANEL_PLOTLIST, - CONFIG_STARTUPPANEL_END_ENUM -}; - -enum -{ - CONFIG_PANELMODE_NONE, - CONFIG_PANELMODE_REMEMBER, - CONFIG_PANELMODE_SPECIFY, - CONFIG_PANELMODE_END_ENUM -}; - -enum -{ - CONFIG_ERR_NOFILE=1, - CONFIG_ERR_BADFILE, - CONFIG_ERR_NOPARSER -}; - - -class ConfigFile -{ - private: - std::deque recentFiles; - vector filterDefaults; - - //!Did the configuration load from file OK? - bool configLoadOK; - - //!Panel - vector startupPanelView; - - //!Any errors that occur during file IO. Set by class members during read()/write() - std::string errMessage; - - //!Method for showing/hiding panel at startup - unsigned int panelMode; - - //!Initial application window size in pixels - unsigned int initialSizeX,initialSizeY; - //!Do we have a valid initial app size? - bool haveIntialAppSize; - - //!Percentile speeds for mouse zoom and move - unsigned int mouseZoomRatePercent,mouseMoveRatePercent; - - //!Master allow the program to do stuff online check. This is AND-ed, so cannot override disabled items - bool allowOnline; - - //!Should the program perform online version number checking? - bool allowOnlineVerCheck; - - //!fractional initial positions of sashes in main UI - float leftRightSashPos,topBottomSashPos, - filterSashPos,plotListSashPos; - - - public: - ConfigFile(); - ~ConfigFile(); - void addRecentFile(const std::string &str); - void getRecentFiles(std::vector &filenames) const; - void removeRecentFile(const std::string &str); - - unsigned int read(); - bool write(); - - bool configLoadedOK() const { return configLoadOK;} - - //Create the configuration folder, if needed. - static bool createConfigDir() ; - //Get the configuration dir path - static std::string getConfigDir(); - - std::string getErrMessage() const { return errMessage;}; - - static unsigned int getMaxHistory(); - - //Get a vector of the default filter pointers - void getFilterDefaults(vector &defs); - //Set the default filter pointers (note this will take ownership of the pointer) - void setFilterDefaults(const vector &defs); - - //Get a clone of the default filter for a given type, - //even if it is not in the array (use hardcoded) - Filter *getDefaultFilter(unsigned int type) const; - - //!Return startup status of UI panels - bool getPanelEnabled(unsigned int panelID) const; - - //!Return startup status of UI panels - void setPanelEnabled(unsigned int panelID,bool enabled, bool permanent=false); - - //!Get the mouse movement rate (for all but zoom) - unsigned int getMouseMoveRate() const { return mouseMoveRatePercent; } - //!Get the mouse movement rate for zoom - unsigned int getMouseZoomRate() const { return mouseZoomRatePercent; } - - //Set the mouse zoom rate(percent) - void setMouseZoomRate(unsigned int rate) { mouseZoomRatePercent=rate;}; - //Set the mouse move rate (percent) - void setMouseMoveRate(unsigned int rate) { mouseMoveRatePercent=rate;}; - - //!Return the current panelmode - unsigned int getStartupPanelMode() const; - //!Set the mode to use for recalling the startup panel layout - void setStartupPanelMode(unsigned int panelM); - - //!Returns true if we have a suggested initial window size; with x & y being the suggestion - bool getInitialAppSize(unsigned int &x, unsigned int &y) const; - //!Set the initial window suggested size - void setInitialAppSize(unsigned int x, unsigned int y); - - bool getAllowOnlineVersionCheck() const; - - //!Set if the program is allowed to access network resources - void setAllowOnline(bool v); - //!Set if the program is allowed to phone home to get latest version #s - void setAllowOnlineVersionCheck(bool v); - - //!Set the position for the main window left/right sash - void setLeftRightSashPos(float fraction); - //!Set the position for the top/bottom sash - void setTopBottomSashPos(float fraction); - //!Set the position for the filter property/tree sash - void setFilterSashPos(float fraction); - //!Set the position for the plot list panel - void setPlotListSashPos(float fraction); - - //!Set the position for the main window left/right sash - float getLeftRightSashPos() const { return leftRightSashPos;}; - //!Set the position for the top/bottom sash - float getTopBottomSashPos() const{ return topBottomSashPos;} - //!Set the position for the filter property/tree sash - float getFilterSashPos() const { return filterSashPos;}; - //!Set the position for the plot list panel - float getPlotListSashPos()const { return plotListSashPos;}; - - -}; - -#endif diff -Nru 3depict-0.0.12/src/cropPanel.cpp 3depict-0.0.13/src/cropPanel.cpp --- 3depict-0.0.12/src/cropPanel.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/cropPanel.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,710 +0,0 @@ -/* - * wxCropPanel.cpp - cropping window for user interaction - * Copyright (C) 2012, 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 . -*/ - - -#include "cropPanel.h" - -#include - -//DEBUG ONLY -//--- -#include -using std::cerr; -using std::endl; -//--- - -//Crop array indices -enum -{ - CROP_LEFT, - CROP_TOP, - CROP_RIGHT, - CROP_BOTTOM, - CROP_ENUM_END -}; - - -BEGIN_EVENT_TABLE(CropPanel, wxPanel) - EVT_PAINT(CropPanel::onPaint) - EVT_MOTION(CropPanel::mouseMove) - EVT_LEFT_DOWN(CropPanel::mouseDown) - EVT_LEFT_UP(CropPanel::mouseReleased) - EVT_LEAVE_WINDOW(CropPanel::mouseLeftWindow) - EVT_LEFT_DCLICK(CropPanel::mouseDoubleLeftClick) - EVT_ERASE_BACKGROUND(CropPanel::OnEraseBackground) - EVT_SIZE(CropPanel::onResize) -END_EVENT_TABLE() - - - -CropPanel::CropPanel(wxWindow * parent, wxWindowID id, - const wxPoint & pos,const wxSize & size,long style) - : wxPanel(parent, id, pos, size, style) -{ - SetBackgroundStyle(wxBG_STYLE_CUSTOM); - programmaticEvent=false; - crop[0]=crop[1]=crop[2]=crop[3]=0.2; - selMode=SELECT_MODE_NONE; - dragging=false; - linkedPanel=0; - linkMode=CROP_LINK_NONE; - hasUpdates=false; -} - -void CropPanel::OnEraseBackground(wxEraseEvent &event) -{ - //Intentionally do nothing, to suppress background erase -} - -void CropPanel::mouseMove(wxMouseEvent &event) -{ - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - - if(!w || !h) - return; - - //Do our calculations in reduced coordinates (0->1); - float xMouse,yMouse; - wxPoint mousePos =event.GetPosition(); - //Add a 1px border around control - xMouse=(float)(mousePos.x+1)/(float)(w-2); - yMouse=(float)(mousePos.y+1)/(float)(h-2); - - if(!dragging) - { - unsigned int index; - selMode=getBestCropWidget(xMouse,yMouse,index); - - //Update the currently selected index as needed - if(selMode == SELECT_MODE_SIDE || selMode == SELECT_MODE_CORNER) - selIndex=index; - } - else - { - float origCrop[4]; - for(unsigned int ui=0;ui<4;ui++) - origCrop[ui]=crop[ui]; - switch(selMode) - { - case SELECT_MODE_NONE: - ASSERT(false); // Can't be dragging nothing, can we. - break; - case SELECT_MODE_SIDE: - { - // we are dragging one of the side crop walls - switch(selIndex) - { - case 0: - crop[selIndex ] =xMouse; - break; - case 1: - crop[selIndex ] = yMouse; - break; - case 2: - crop[selIndex]=1.0-xMouse; - break; - case 3: - crop[selIndex]=1.0-yMouse; - break; - } - - break; - } - case SELECT_MODE_CORNER: - { - //we are dragging one of the corners - switch(selIndex) - { - case 0: - crop[0] =xMouse; - crop[1]=yMouse; - break; - case 1: - crop[1]=yMouse; - crop[2] =1.0-xMouse; - break; - case 2: - crop[2] =1.0-xMouse; - crop[3]=1.0-yMouse; - break; - case 3: - crop[3] =1.0-yMouse; - crop[0]=xMouse; - break; - } - break; - } - case SELECT_MODE_CENTRE: - { - //OK, we have to move them based upon the original drag - //coordinates - float delta[2]; - delta[0]=xMouse-mouseAtDragStart[0]; - delta[1]=yMouse-mouseAtDragStart[1]; - for(unsigned int ui=0;ui<4;ui++) - { - float flip; - - if(ui<2) - flip=1.0; - else - flip=-1; - crop[ui]=cropAtDragStart[ui]+delta[ui&1]*flip; - } - - break; - - } - } - - - //Check the result is still valid - if(!validCoords()) - { - //Try to only adjust the invalid coordinates, - //to make the motion a little "smoother" - for(unsigned int ui=0;ui<4;ui++) - { - if(crop[ui] > 1.0 || crop[ui] < 0.0) - crop[ui]=origCrop[ui]; - } - - //See if our quick fix solved the coord validity - if(!validCoords()) - { - //restore the original coords - for(unsigned int ui=0;ui<4;ui++) - crop[ui]=origCrop[ui]; - } - } - - if(linkedPanel) - updateLinked(); - - hasUpdates=true; - } - - - Refresh(); -} - -unsigned int CropPanel::getBestCropWidget(float xMouse, float yMouse,unsigned int &index) const -{ - unsigned int bestSelMode=SELECT_MODE_NONE; - - int w,h; - w=0;h=0; - GetClientSize(&w,&h); - - if(!w || !h) - return bestSelMode; - - float meanPx = 1.0/(1.0/(w-2) + 1.0/(h-2)); - unsigned int minIndex; - float minDist,tmpDist,x,y; - //work our way clockwise around the corners - //finding the minimum distance - for(unsigned int ui=0;ui<4;ui++) - { - //Check this corner - switch(ui) - { - case 0: - //Top left corner - x=crop[CROP_LEFT]; - y=crop[CROP_TOP]; - break; - case 1: - //Top right corner - x=1.0-crop[CROP_RIGHT]; - y=crop[CROP_TOP]; - break; - - case 2: - //Bottom right corner - x=1.0-crop[CROP_RIGHT]; - y=1.0-crop[CROP_BOTTOM]; - break; - case 3: - //Bottom left corner - x=crop[CROP_LEFT]; - y=1.0-crop[CROP_BOTTOM]; - break; - default: - ASSERT(false); - } - - tmpDist=(xMouse-x)*(xMouse-x) + (yMouse-y)*(yMouse-y); - if(!ui || tmpDist < minDist) //first pass - no data - { - minIndex=ui; - minDist=tmpDist; - } - } - - minDist=sqrtf(minDist); - bool haveCorner; - - const float MIN_CUTOFF_DISTANCE= 3; - - //Do we have a corner minimum? - haveCorner= ((int)(minDist*meanPx) < MIN_CUTOFF_DISTANCE); - - bool haveCentre; - float meanX = (float)(crop[0] + (1.0-crop[2]))*0.5; - float meanY = (float)(crop[1] + (1.0-crop[3]))*0.5; - - float centreDist; - centreDist=sqrtf((xMouse-meanX)*(xMouse-meanX) - + (yMouse-meanY)*(yMouse-meanY)); - //Check the centre, which is allowed to trump the corners - if(haveCorner) - haveCentre=(centreDist< minDist); - else - haveCentre=(meanPx*centreDist) < MIN_CUTOFF_DISTANCE; - unsigned int sideIndex; - - bool haveSide=false; - //OK, well, we are allowed to have a side match, check that. - if(fabs(crop[CROP_LEFT] - xMouse)*meanPx < MIN_CUTOFF_DISTANCE) - { - haveSide=true; - sideIndex=CROP_LEFT; - } - //OK, well, we are allowed to have a side match, check that. - else if(fabs((1.0-crop[CROP_RIGHT]) - xMouse)*meanPx < MIN_CUTOFF_DISTANCE) - { - haveSide=true; - sideIndex=CROP_RIGHT; - } - else if(fabs(crop[CROP_TOP] - yMouse)*meanPx < MIN_CUTOFF_DISTANCE) - { - haveSide=true; - sideIndex=CROP_TOP; - } - else if(fabs((1.0- crop[CROP_BOTTOM]) - yMouse)*meanPx < MIN_CUTOFF_DISTANCE) - { - haveSide=true; - sideIndex=CROP_BOTTOM; - } - - - //!Prioritise selection mode - if(haveCentre) - { - bestSelMode=SELECT_MODE_CENTRE; - } - else if(haveCorner) - { - bestSelMode=SELECT_MODE_CORNER; - index=minIndex; - } - else if(haveSide) - { - bestSelMode=SELECT_MODE_SIDE; - index=sideIndex; - } - else - { - bestSelMode=SELECT_MODE_NONE; - } - - return bestSelMode; -} - -void CropPanel::mouseDoubleLeftClick(wxMouseEvent& event) -{ - //set the snap position using a bitmask - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - - if(!w || !h) - return; - - - unsigned int index; - - float xMouse,yMouse; - wxPoint mousePos =event.GetPosition(); - //Add a 1px border around control - xMouse=(float)(mousePos.x+1)/(float)(w-2); - yMouse=(float)(mousePos.y+1)/(float)(h-2); - - - switch(getBestCropWidget(xMouse,yMouse,index)) - { - //Just reset the crop values - //if we are at the centre or side - case SELECT_MODE_NONE: - case SELECT_MODE_CENTRE: - { - for(unsigned int ui=0;ui<4;ui++) - crop[ui]=0; - break; - } - case SELECT_MODE_SIDE: - { - //Ok, lets reset just this side - crop[index]=0; - break; - } - case SELECT_MODE_CORNER: - { - crop[index]=0; - crop[(index+1)%4]=0; - break; - } - default: - ASSERT(false); - } - - - Refresh(); - if(linkedPanel) - updateLinked(); - - hasUpdates=true; - event.Skip(); -} - - -void CropPanel::mouseLeftWindow(wxMouseEvent& event) -{ - if(!dragging) - selMode=SELECT_MODE_NONE; -} - -void CropPanel::mouseDown(wxMouseEvent &event) -{ - //set the snap position using a bitmask - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - - if(!w || !h) - return; - - - //Do our calculations in reduced coordinates (0->1); - wxPoint mousePos =event.GetPosition(); - mouseAtDragStart[0]=(float)(mousePos.x+1)/(float)(w-2); - mouseAtDragStart[1]=(float)(mousePos.y+1)/(float)(h-2); - - ASSERT(validCoords()); - if(selMode != SELECT_MODE_NONE) - dragging=true; - - for(unsigned int ui=0;ui<4;ui++) - cropAtDragStart[ui] = crop[ui]; - -} - - -void CropPanel::mouseReleased(wxMouseEvent &event) -{ - dragging=false; - selMode=SELECT_MODE_NONE; - selIndex=0; - - Refresh(); -} - -bool CropPanel::validCoords() const -{ - float sum; - sum=(crop[CROP_LEFT] + crop[CROP_RIGHT]); - //Draw the four crop markers - if(sum > 1.00f) - return false; - - - sum=(crop[CROP_TOP] + crop[CROP_BOTTOM]); - if( sum> 1.00f) - return false; - - - for(unsigned int ui=0;ui<4;ui++) - { - if(crop[ui] < 0.0) - return false; - } - - return true; -} - -void CropPanel::onPaint(wxPaintEvent &event) -{ - draw(); -} - -void CropPanel::draw() -{ - ASSERT(validCoords()); - - wxAutoBufferedPaintDC *dc=new wxAutoBufferedPaintDC(this); - - wxBrush *b = new wxBrush; - b->SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND)); - dc->Clear(); - - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - if(!w || !h) - { - delete dc; - return; - } - - - //Drawing coords - int lineX[8],lineY[8]; - - //Draw lines - lineX[0]=lineX[1]=(int)(crop[CROP_LEFT]*(float)w); - lineX[2]=0; - lineX[3]=w; - lineX[4]=lineX[5]=(int)((1.0-crop[CROP_RIGHT])*(float)w); - lineX[6]=w; - lineX[7]=0; - - lineY[0]=0; - lineY[1]=h; - lineY[2]=lineY[3]=(int)(crop[CROP_TOP]*(float)h); - lineY[4]=0; - lineY[5]=h; - lineY[6]=lineY[7]=(int)((1.0-crop[CROP_BOTTOM])*(float)h); - - - - //Draw greyed out section - //-- - wxPen *noPen; - noPen = new wxPen(*wxBLACK,1,wxTRANSPARENT); - b->SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND)); - dc->SetBrush(*b); - dc->SetPen(*noPen); - - dc->DrawRectangle(0,0,lineX[0],h); - dc->DrawRectangle(0,0,w,lineY[2]); - dc->DrawRectangle(0,lineY[6],w,h-lineY[6]); - dc->DrawRectangle(lineX[4],0,w-lineX[4],h); - delete noPen; - delete b; - //-- - - - wxPen *highPen,*normalPen; - highPen= new wxPen(*wxBLUE,2,wxSOLID); - normalPen= new wxPen(*wxBLACK,2,wxSOLID); - - dc->SetPen(*normalPen); - if(selMode!=SELECT_MODE_SIDE) - { - - dc->SetPen(*normalPen); - for(unsigned int ui=0;ui<8;ui+=2) - dc->DrawLine(lineX[ui],lineY[ui],lineX[ui+1],lineY[ui+1]); - - } - else - { - for(unsigned int ui=0;ui<8;ui+=2) - { - if(selIndex== ui/2) - dc->SetPen(*highPen); - else - dc->SetPen(*normalPen); - - dc->DrawLine(lineX[ui],lineY[ui],lineX[ui+1],lineY[ui+1]); - } - - dc->SetPen(*normalPen); - } - - - if(selMode == SELECT_MODE_CORNER) - { - //Draw the corner markers - float xC,yC; - float sizeX,sizeY; - - sizeX=sizeY=8; - switch(selIndex) - { - case 0: - xC=crop[CROP_LEFT]; - yC=crop[CROP_TOP]; - sizeX=-sizeX; - sizeY=-sizeY; - break; - case 1: - xC=1.0-crop[CROP_RIGHT]; - yC=crop[CROP_TOP]; - sizeY=-sizeY; - break; - case 2: - xC=1.0-crop[CROP_RIGHT]; - yC=1.0-crop[CROP_BOTTOM]; - break; - case 3: - sizeX=-sizeX; - xC=crop[CROP_LEFT]; - yC=1.0-crop[CROP_BOTTOM]; - break; - default: - ASSERT(false); - } - - xC=xC*(float)w; - yC=yC*(float)h; - - - //Draw the corner - dc->SetPen(*highPen); - dc->DrawLine(wxCoord(xC + 2.0f*sizeX), wxCoord(yC+sizeY), - wxCoord(xC+sizeX),wxCoord(yC+sizeY)); - dc->DrawLine(wxCoord(xC+sizeX), wxCoord(yC+sizeY), - wxCoord(xC+sizeX),wxCoord(yC+2.0f*sizeY)); - dc->SetPen(*normalPen); - } - - - - float meanX = (float)w*(crop[0] + (1.0-crop[2]))*0.5; - float meanY = (float)h*(crop[1] + (1.0-crop[3]))*0.5; - - dc->DrawCircle((int)meanX,(int)meanY,1); - if(selMode==SELECT_MODE_CENTRE) - { - dc->SetPen(*highPen); - dc->DrawCircle((int)meanX,(int)meanY,4); - } - - delete dc; - - delete highPen; - delete normalPen; - -} - - -void CropPanel::updateLinked() -{ - ASSERT(linkedPanel); - switch(linkMode) - { - case CROP_LINK_NONE: - return; - case CROP_LINK_LR: - linkedPanel->crop[CROP_LEFT]=crop[CROP_LEFT]; - linkedPanel->crop[CROP_RIGHT]=crop[CROP_RIGHT]; - break; - case CROP_LINK_LR_FLIP: - linkedPanel->crop[CROP_BOTTOM]=crop[CROP_LEFT]; - linkedPanel->crop[CROP_TOP]=crop[CROP_RIGHT]; - break; - case CROP_LINK_TB: - linkedPanel->crop[CROP_BOTTOM]=crop[CROP_BOTTOM]; - linkedPanel->crop[CROP_TOP]=crop[CROP_TOP]; - break; - case CROP_LINK_TB_FLIP: - linkedPanel->crop[CROP_LEFT]=crop[CROP_BOTTOM]; - linkedPanel->crop[CROP_RIGHT]=crop[CROP_TOP]; - break; - case CROP_LINK_BOTH: - linkedPanel->crop[CROP_LEFT]=crop[CROP_LEFT]; - linkedPanel->crop[CROP_RIGHT]=crop[CROP_RIGHT]; - linkedPanel->crop[CROP_BOTTOM]=crop[CROP_BOTTOM]; - linkedPanel->crop[CROP_TOP]=crop[CROP_TOP]; - break; - case CROP_LINK_BOTH_FLIP: - linkedPanel->crop[CROP_BOTTOM]=crop[CROP_LEFT]; - linkedPanel->crop[CROP_TOP]=crop[CROP_RIGHT]; - linkedPanel->crop[CROP_LEFT]=crop[CROP_BOTTOM]; - linkedPanel->crop[CROP_RIGHT]=crop[CROP_TOP]; - break; - default: - ASSERT(false); - - } - - linkedPanel->Refresh(); - -} - - -void CropPanel::link(CropPanel *panel,unsigned int mode) -{ - linkMode=mode; - if(linkMode== CROP_LINK_NONE) - linkedPanel=0; - else - { - linkedPanel=panel; - - for(unsigned int ui=0;uicrop[ui]=crop[ui]; - } -} - -void CropPanel::getCropValues(float *array) const -{ - array[0]=crop[CROP_LEFT]; - array[1]=crop[CROP_RIGHT]; - array[2]=crop[CROP_TOP]; - array[3]=crop[CROP_BOTTOM]; - -} - -void CropPanel::setCropValue(unsigned int index, float v) - -{ - ASSERT(index<=CROP_BOTTOM); - crop[index]=v; -} - -void CropPanel::makeCropValuesValid() -{ - for(size_t ui=0;ui<4;ui++) - { - crop[ui]=std::max(crop[ui],0.0f); - crop[ui]=std::min(crop[ui],1.0f); - } - - if(crop[CROP_LEFT] + crop[CROP_RIGHT] >1) - crop[CROP_LEFT]=crop[CROP_RIGHT]=0.2f; - - if(crop[CROP_TOP] + crop[CROP_BOTTOM] >1) - crop[CROP_TOP]=crop[CROP_BOTTOM]=0.2f; -} - -void CropPanel::onResize(wxSizeEvent &evt) -{ -#ifndef __WXMAC__ - wxPaintEvent paintEvt; - wxPostEvent(this,paintEvt); -#endif -} diff -Nru 3depict-0.0.12/src/cropPanel.h 3depict-0.0.13/src/cropPanel.h --- 3depict-0.0.12/src/cropPanel.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/cropPanel.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* - * wxCropPanel.cpp - cropping window for user interaction - * Copyright (C) 2012, 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 . -*/ - -#ifndef WXCROPPANEL_H -#define WXCROPPANEL_H - -#include -#include "assertion.h" - -//Selection method -enum -{ - SELECT_MODE_NONE, - SELECT_MODE_SIDE, - SELECT_MODE_CENTRE, - SELECT_MODE_CORNER, - SELECT_MODE_END_ENUM -}; - - -enum -{ - CROP_LINK_NONE, - CROP_LINK_LR, - CROP_LINK_LR_FLIP, - CROP_LINK_TB, - CROP_LINK_TB_FLIP, - CROP_LINK_BOTH, - CROP_LINK_BOTH_FLIP, -}; - -class CropPanel : public wxPanel -{ - private: - //!A panel to force the linkage to (link crop border positions) - CropPanel *linkedPanel; - - //!The link mode for the other panel - unsigned int linkMode; - - //!True if event generated programmatically (blocker bool) - bool programmaticEvent; - //!Cropping %ages for window - float crop[4]; - - //Mouse coords and crop coords at drag start (0->1) - float mouseAtDragStart[2]; - float cropAtDragStart[4]; - - //!Selection mode and index for different crop edges/corners/centre - unsigned int selMode,selIndex; - - //!Is the control currently being dragged by the user with the mouse? - bool dragging; - - //!True if the crop array has been modified. - bool hasUpdates; - - bool validCoords() const; - - - void draw() ; - - //!Get the "best" crop widget as defined by coordinates (in 0->1 space) - //returns the index of the selected item as parameter - unsigned int getBestCropWidget(float xMouse,float yMouse, unsigned int &idx) const; - - - DECLARE_EVENT_TABLE(); - public: - CropPanel(wxWindow * parent, wxWindowID id = wxID_ANY, - const wxPoint & pos = wxDefaultPosition, - const wxSize & size = wxDefaultSize, - long style = wxTAB_TRAVERSAL) ; - - - bool hasUpdate(){return hasUpdates;}; - void clearUpdate(){hasUpdates=false;}; - - void getCropValues(float *array) const; - //!Directly set the crop value, (0->1), index can be 0->3 - void setCropValue(unsigned int index, float v); - - void makeCropValuesValid(); - - //!Link this panel's updates to another. Use CROP_LINK_NONE to disable - void link(CropPanel *otherPanel,unsigned int mode); - - void OnEraseBackground(wxEraseEvent& event); - - void mouseMove(wxMouseEvent& event); - void mouseDown(wxMouseEvent& event); - void mouseReleased(wxMouseEvent& event); - void mouseLeftWindow(wxMouseEvent& event); - void mouseDoubleLeftClick(wxMouseEvent& event); - void onPaint(wxPaintEvent& evt); - void onResize(wxSizeEvent& evt); - - void updateLinked(); - ~CropPanel() {}; -}; -#endif diff -Nru 3depict-0.0.12/src/dialogs/ExportPos.cpp 3depict-0.0.13/src/dialogs/ExportPos.cpp --- 3depict-0.0.12/src/dialogs/ExportPos.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/ExportPos.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,524 +0,0 @@ -/* - * ExportPos.cpp - POS file export dialog implementation - * Copyright (C) 2012, 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 . -*/ - - -#include "ExportPos.h" -#include "../wxcommon.h" - -#include "../translation.h" -// begin wxGlade: ::extracode - -// end wxGlade - -wxWindow *exportPosYieldWindow=0; -bool abortOp; -wxStopWatch *exportPosDelayTime=0; - -bool yieldCallback(bool) -{ - const unsigned int YIELD_MS=75; - - ASSERT(exportPosDelayTime); - //Rate limit the updates - if(exportPosDelayTime->Time() > YIELD_MS) - { - wxSafeYield(exportPosYieldWindow); - exportPosDelayTime->Start(); - } - - return !abortOp; -} - - -using std::list; -using std::pair; - -enum -{ - ID_BTN_ADDDATA=wxID_ANY+1, - ID_BTN_ADDNODE, - ID_BTN_ADDALL, - ID_TREE_FILTERS, - ID_LIST_SELECTED, - ID_LIST_AVAILABLE, - ID_RADIO_VISIBLE, - ID_RADIO_SELECTION, -}; - - -ExportPosDialog::ExportPosDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) - -{ - haveRefreshed=false; - exportVisible=true; - // begin wxGlade: ExportPosDialog::ExportPosDialog - lblExport = new wxStaticText(this, wxID_ANY, wxTRANS("Export:")); - radioVisible = new wxRadioButton(this,ID_RADIO_VISIBLE , wxTRANS("Visible")); - radioSelection = new wxRadioButton(this,ID_RADIO_SELECTION , wxTRANS("Selected Data")); - treeData = new wxTreeCtrl(this, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER); - lblAvailableData = new wxStaticText(this, wxID_ANY, wxTRANS("Available Data")); - listAvailable = new wxListCtrl(this, ID_LIST_AVAILABLE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER|wxLC_VRULES); - btnAddData = new wxButton(this, ID_BTN_ADDDATA, wxT(">")); - btnAddNode = new wxButton(this,ID_BTN_ADDNODE, wxT(">>")); - btnAddAll = new wxButton(this, ID_BTN_ADDALL, wxT(">>>")); - panel_2 = new wxPanel(this, wxID_ANY); - label_4 = new wxStaticText(this, wxID_ANY, wxTRANS("Selection")); - listSelected = new wxListCtrl(this, ID_LIST_SELECTED, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); - btnSave = new wxButton(this, wxID_SAVE, wxEmptyString); - btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - - btnSave->SetFocus(); - - set_properties(); - do_layout(); - // end wxGlade - - //Disable most everything. - enableSelectionControls(false); - - //Assign global variables their init value - //-- - ASSERT(!exportPosYieldWindow); - exportPosYieldWindow=this; - - ASSERT(!exportPosDelayTime); //Should not have been inited yet. - - exportPosDelayTime = new wxStopWatch(); - //-- - - //Add columns to report listviews - listSelected->InsertColumn(0,wxTRANS("Index")); - listSelected->InsertColumn(1,wxTRANS("Count")); - - listAvailable->InsertColumn(0,wxTRANS("Index")); - listAvailable->InsertColumn(1,wxTRANS("Count")); -} - -ExportPosDialog::~ExportPosDialog() -{ - delete exportPosDelayTime; - exportPosDelayTime=0; - exportPosYieldWindow=0; - //Should have called cleanup before exiting. - ASSERT(!haveRefreshed); -} - -BEGIN_EVENT_TABLE(ExportPosDialog, wxDialog) - // begin wxGlade: ExportPosDialog::event_table - EVT_BUTTON(ID_BTN_ADDDATA, ExportPosDialog::OnBtnAddData) - EVT_BUTTON(ID_BTN_ADDNODE, ExportPosDialog::OnBtnAddNode) - EVT_BUTTON(ID_BTN_ADDALL, ExportPosDialog::OnBtnAddAll) - EVT_RADIOBUTTON(ID_RADIO_VISIBLE, ExportPosDialog::OnVisibleRadio) - EVT_RADIOBUTTON(ID_RADIO_SELECTION, ExportPosDialog::OnSelectedRadio) - EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, ExportPosDialog::OnTreeFiltersSelChanged) - EVT_LIST_ITEM_ACTIVATED(ID_LIST_AVAILABLE, ExportPosDialog::OnListAvailableItemActivate) - EVT_LIST_ITEM_ACTIVATED(ID_LIST_SELECTED, ExportPosDialog::OnListSelectedItemActivate) - EVT_LIST_KEY_DOWN(ID_LIST_SELECTED, ExportPosDialog::OnListSelectedItemKeyDown) - EVT_BUTTON(wxID_SAVE, ExportPosDialog::OnSave) - EVT_BUTTON(wxID_CANCEL, ExportPosDialog::OnCancel) - - // end wxGlade -END_EVENT_TABLE() - -void ExportPosDialog::initialiseData(FilterTree &f) -{ - ASSERT(!haveRefreshed) - - //Steal the filter tree contents - f.swap(filterTree); - vector dummyPersist; - upWxTreeCtrl(filterTree,treeData,filterMap,dummyPersist,0); - - ProgressData p; - //TODO: Is trashing the devices a problem? do we have to restore them?? - std::vector *> dummyDevices; - std::vector > consoleStrings; - filterTree.refreshFilterTree(outputData,dummyDevices,consoleStrings,p,yieldCallback); - - //Delete all filter items that came out of refresh, other than ion streams - filterTree.safeDeleteFilterList(outputData,STREAM_TYPE_IONS,true); - - haveRefreshed=true; -} - -void ExportPosDialog::OnVisibleRadio(wxCommandEvent &event) -{ - ASSERT(haveRefreshed); - exportVisible=true; - listAvailable->DeleteAllItems(); - enableSelectionControls(false); -} - - -void ExportPosDialog::OnSelectedRadio(wxCommandEvent &event) -{ - ASSERT(haveRefreshed); - exportVisible=false; - enableSelectionControls(true); -} - - -void ExportPosDialog::OnTreeFiltersSelChanged(wxTreeEvent &event) -{ - wxTreeItemId id; - id=treeData->GetSelection(); - - if(!id.IsOk() || id== treeData->GetRootItem()) - { - event.Skip(); - return; - } - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeData->GetItemData(id); - - //Clear the available list - listAvailable->DeleteAllItems(); - availableFilterData.clear(); - - const Filter *targetFilter=filterMap[((wxTreeUint *)tData)->value]; - - typedef std::pair > filterOutputData; - //Spin through the output list, looking for this filter's contribution - for(list::iterator it=outputData.begin();it!=outputData.end();++it) - { - //Is this the filter we are looking for? - if(it->first == targetFilter) - { - //huzzah. - std::string label; - - for(unsigned int ui=0;uisecond.size();ui++) - { - const IonStreamData *ionData; - ionData=(const IonStreamData *)((it->second)[ui]); - - wxColour c; - c.Set((unsigned char)(ionData->r*255), - (unsigned char)(ionData->g*255),(unsigned char)(ionData->b*255)); - //Add the item using the index as a str - stream_cast(label,ui); - listAvailable->InsertItem(ui,wxStr(label)); - - size_t basicCount; - basicCount=ionData->getNumBasicObjects(); - stream_cast(label,basicCount); - - listAvailable->SetItem(ui,1,wxStr(label)); - - listAvailable->SetItemBackgroundColour(ui,c); - - availableFilterData.push_back((it->second)[ui]); - } - } - - } -} - - -void ExportPosDialog::OnListAvailableItemActivate(wxListEvent &event) -{ - unsigned int item=event.GetIndex(); - - //If the selected item is not already in the "selected filter" list, add it - if(find(selectedFilterData.begin(),selectedFilterData.end(), - availableFilterData[item]) == selectedFilterData.end()) - selectedFilterData.push_back(availableFilterData[item]); - - //Update the selection list - updateSelectedList(); -} - -void ExportPosDialog::OnListSelectedItemActivate(wxListEvent &event) -{ - unsigned int item=event.GetIndex(); - - unsigned int thisIdx=0; - for(list::iterator it=selectedFilterData.begin(); - it!=selectedFilterData.end(); ++it) - { - if(thisIdx == item) - { - selectedFilterData.erase(it); - break; - } - - thisIdx++; - } - - //Update the selection list - updateSelectedList(); - - -} - -void ExportPosDialog::OnListSelectedItemKeyDown(wxListEvent &event) -{ - switch(event.GetKeyCode()) - { - case WXK_DELETE: - { - //Spin through the selected items - int item=-1; - for ( ;; ) - { - item = listSelected->GetNextItem(item, - wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - if ( item == -1 ) - break; - - list::iterator it; - - it=find(selectedFilterData.begin(),selectedFilterData.end(), - availableFilterData[item]); - //If the selected item is not already in the "selected filter" list, add it - if(it != selectedFilterData.end()) - selectedFilterData.erase(it); - } - - //Update the selection list - updateSelectedList(); - } - - } -} - -void ExportPosDialog::OnBtnAddAll(wxCommandEvent &event) -{ - selectedFilterData.clear(); - typedef std::pair > filterOutputData; - - for(list::iterator it=outputData.begin();it!=outputData.end();++it) - { - for(unsigned int uj=0;ujsecond.size();uj++) - selectedFilterData.push_back(it->second[uj]); - } - - - updateSelectedList(); -} - - -void ExportPosDialog::OnBtnAddData(wxCommandEvent &event) -{ - - int item=-1; - for ( ;; ) - { - item = listAvailable->GetNextItem(item, - wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - if ( item == -1 ) - break; - - //Disallow addition of duplicate entries - if(find(selectedFilterData.begin(),selectedFilterData.end(), - availableFilterData[item]) == selectedFilterData.end()) - selectedFilterData.push_back(availableFilterData[item]); - } - updateSelectedList(); - -} - -void ExportPosDialog::updateSelectedList() -{ - //Clear the available list - listSelected->DeleteAllItems(); - - unsigned int idx=0; - std::string label; - for(list::iterator it=selectedFilterData.begin(); - it!=selectedFilterData.end(); ++it) - { - const IonStreamData *ionData; - ionData=(const IonStreamData *)(*it); - - wxColour c; - c.Set((unsigned char)(ionData->r*255), - (unsigned char)(ionData->g*255), - (unsigned char)(ionData->b*255)); - //Add the item using the index as a str - stream_cast(label,idx); - listSelected->InsertItem(idx,wxStr(label)); - - size_t basicCount; - basicCount=ionData->getNumBasicObjects(); - stream_cast(label,basicCount); - - listSelected->SetItem(idx,1,wxStr(label)); - - listSelected->SetItemBackgroundColour(idx,c); - - idx++; - } - - - - if(listSelected->GetItemCount()) - { - btnSave->Enable(); - } - else - btnSave->Disable(); -} - -void ExportPosDialog::OnBtnAddNode(wxCommandEvent &event) -{ - - //Spin through the selected items - for (int item=0;itemGetItemCount(); item++) - { - //If the selected item is not already in the "selected filter" list, add it - if(find(selectedFilterData.begin(),selectedFilterData.end(), - availableFilterData[item]) == selectedFilterData.end()) - selectedFilterData.push_back(availableFilterData[item]); - } - - updateSelectedList(); -} - - - -void ExportPosDialog::OnSave(wxCommandEvent &event) -{ - exportVisible=(radioVisible->GetValue()); - EndModal(wxID_OK); -} - -void ExportPosDialog::OnCancel(wxCommandEvent &event) -{ - EndModal(wxID_CANCEL); -} - -void ExportPosDialog::getExportVec(std::vector &v) const -{ - typedef std::pair > filterOutputData; - - //If the user has selected "visible", then all outputs are to be exported - if(exportVisible) - { - v.reserve(outputData.size()); - - for(list::const_iterator it=outputData.begin(); - it!=outputData.end();++it) - { - for(unsigned int ui=0;uisecond.size();ui++) - v.push_back(it->second[ui]); - - } - } - else - { - //If the user wants to perform custom picking, then only "selected" to be - //exported - v.reserve(selectedFilterData.size()); - for(list::const_iterator it=selectedFilterData.begin(); - it!=selectedFilterData.end(); ++it) - { - v.push_back(*it); - } - - } -} - -// wxGlade: add ExportPosDialog event handlers - - -void ExportPosDialog::set_properties() -{ - // begin wxGlade: ExportPosDialog::set_properties - SetTitle(wxTRANS("Export Pos Data")); - // end wxGlade - - treeData->SetToolTip(wxTRANS("Tree of filters, select leaves to show ion data.")); - - btnAddAll->SetToolTip(wxTRANS("Add all data from all filters")); - btnAddNode->SetToolTip(wxTRANS("Add all data from currently selected filter")); - btnAddData->SetToolTip(wxTRANS("Add selected data from currently selected filter")); - radioVisible->SetValue(TRUE); -} - -void ExportPosDialog::enableSelectionControls(bool enabled) - -{ - //Enable/disable controls that are used for sleection - treeData->Enable(enabled); - listAvailable->Enable(enabled); - btnAddData->Enable(enabled); - btnAddNode->Enable(enabled); - btnAddAll->Enable(enabled); - listSelected->Enable(enabled); - - //If the selection control is enabled, - //bring the tree back to life - //otherwise, grey it out. - if(enabled) - { - treeData->ExpandAll(); - treeData->SetForegroundColour(wxNullColour); - btnSave->Enable(listSelected->GetItemCount()); - } - else - { - treeData->CollapseAll(); - treeData->SetForegroundColour(*wxLIGHT_GREY); - treeData->Unselect(); - btnSave->Enable(); - } -} - -void ExportPosDialog::do_layout() -{ - // begin wxGlade: ExportPosDialog::do_layout - wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_12 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_13 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_11 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_9 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_10 = new wxBoxSizer(wxVERTICAL); - sizer_4->Add(10, 20, 0, 0, 0); - sizer_9->Add(lblExport, 0, wxTOP|wxBOTTOM, 5); - sizer_9->Add(radioVisible, 0, 0, 0); - sizer_9->Add(radioSelection, 0, 0, 0); - sizer_10->Add(treeData, 1, wxTOP|wxBOTTOM|wxEXPAND, 6); - sizer_10->Add(lblAvailableData, 0, 0, 0); - sizer_10->Add(listAvailable, 1, wxBOTTOM|wxEXPAND, 5); - sizer_9->Add(sizer_10, 1, wxEXPAND, 0); - sizer_4->Add(sizer_9, 1, wxALL|wxEXPAND, 5); - sizer_11->Add(20, 200, 0, 0, 0); - sizer_11->Add(btnAddData, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 10); - sizer_11->Add(btnAddNode, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 10); - sizer_11->Add(btnAddAll, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 10); - sizer_11->Add(panel_2, 1, wxEXPAND, 0); - sizer_4->Add(sizer_11, 0, wxEXPAND, 0); - sizer_12->Add(20, 40, 0, 0, 0); - sizer_12->Add(label_4, 0, wxTOP|wxBOTTOM, 6); - sizer_12->Add(listSelected, 1, wxEXPAND, 0); - sizer_12->Add(20, 20, 0, 0, 0); - sizer_13->Add(20, 20, 1, 0, 0); - sizer_13->Add(btnSave, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_RIGHT|wxALIGN_BOTTOM, 6); - sizer_13->Add(btnCancel, 0, wxBOTTOM|wxALIGN_RIGHT|wxALIGN_BOTTOM, 6); - sizer_12->Add(sizer_13, 0, wxEXPAND, 0); - sizer_4->Add(sizer_12, 1, wxALL|wxEXPAND, 5); - SetSizer(sizer_4); - sizer_4->Fit(this); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/ExportPos.h 3depict-0.0.13/src/dialogs/ExportPos.h --- 3depict-0.0.12/src/dialogs/ExportPos.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/ExportPos.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* - * ExportPos.h - Point data export dialog - * Copyright (C) 2012, 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 . -*/ - -#include -#include - -#ifndef EXPORTPOS_H -#define EXPORTPOS_H - -// begin wxGlade: ::dependencies -#include -#include -// end wxGlade - -// begin wxGlade: ::extracode - -// end wxGlade - -#include "../viscontrol.h" - - -class ExportPosDialog: public wxDialog { -public: - // begin wxGlade: ExportPosDialog::ids - // end wxGlade - - ExportPosDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - ~ExportPosDialog(); -private: - - - FilterTree filterTree; - - std::map filterMap; - - //!Have we refreshed the filterstream data list? - bool haveRefreshed; - //!Should we be exporting selected ions (false) or visible ions (true) - bool exportVisible; - //!List containing filter and ion streams to export - std::list > > outputData; - //!vector containing currently available filter streams - std::vector availableFilterData; - - //List containing currently selected filter streams - std::list selectedFilterData; - - - //!Use selectedFilterData to draw wx widget - void updateSelectedList(); - // begin wxGlade: ExportPosDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - -protected: - // begin wxGlade: ExportPosDialog::attributes - wxStaticText* lblExport; - wxRadioButton* radioVisible; - wxRadioButton* radioSelection; - wxTreeCtrl* treeData; - wxStaticText* lblAvailableData; - wxListCtrl* listAvailable; - wxButton* btnAddData; - wxButton* btnAddNode; - wxButton* btnAddAll; - wxPanel* panel_2; - wxStaticText* label_4; - wxListCtrl* listSelected; - wxButton* btnSave; - wxButton* btnCancel; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnVisibleRadio(wxCommandEvent &event); // wxGlade: - virtual void OnSelectedRadio(wxCommandEvent &event); // wxGlade: - virtual void OnTreeFiltersSelChanged(wxTreeEvent &event); // wxGlade: - virtual void OnBtnAddAll(wxCommandEvent &event); // wxGlade: - virtual void OnBtnAddData(wxCommandEvent &event); // wxGlade: - virtual void OnBtnAddNode(wxCommandEvent &event); // wxGlade: - virtual void OnSave(wxCommandEvent &event); // wxGlade: - virtual void OnCancel(wxCommandEvent &event); // wxGlade: - virtual void OnListAvailableItemActivate(wxListEvent &event); // wxGlade: - virtual void OnListSelectedItemActivate(wxListEvent &event); // wxGlade: - virtual void OnListSelectedItemKeyDown(wxListEvent &event); // wxGlade: - - void initialiseData(FilterTree &f); - void enableSelectionControls(bool enabled); - void getExportVec(std::vector &v) const; - void swapFilterTree(FilterTree &f) { f.swap(filterTree);haveRefreshed=false;} - -}; // wxGlade: end class - - -#endif // EXPORTPOS_H diff -Nru 3depict-0.0.12/src/dialogs/ExportRngDialog.cpp 3depict-0.0.13/src/dialogs/ExportRngDialog.cpp --- 3depict-0.0.12/src/dialogs/ExportRngDialog.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/ExportRngDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,273 +0,0 @@ -/* - * ExportRngDialog.cpp - "Range" data export dialog - * Copyright (C) 2012, 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 . -*/ - -#include "ExportRngDialog.h" -#include "../wxcommon.h" -#include "../translation.h" - - -#include "../filters/rangeFile.h" - -#include -// begin wxGlade: ::extracode - -// end wxGlade - -enum -{ - ID_LIST_ACTIVATE=wxID_ANY+1, -}; - -ExportRngDialog::ExportRngDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) -{ - // begin wxGlade: ExportRngDialog::ExportRngDialog - lblRanges = new wxStaticText(this, wxID_ANY, wxTRANS("Range Sources")); - listRanges = new wxListCtrl(this, ID_LIST_ACTIVATE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); - label_3 = new wxStaticText(this, wxID_ANY, wxTRANS("Details")); - gridDetails = new wxGrid(this, wxID_ANY); - btnOK = new wxButton(this, wxID_SAVE, wxEmptyString); - btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - btnOK->SetFocus(); - - set_properties(); - do_layout(); - // end wxGlade - - //Add columns to report listviews - listRanges->InsertColumn(0,wxTRANS("Source Filter")); - listRanges->InsertColumn(1,wxTRANS("Ions")); - listRanges->InsertColumn(2,wxTRANS("Ranges")); - -} - - -BEGIN_EVENT_TABLE(ExportRngDialog, wxDialog) - // begin wxGlade: ExportRngDialog::event_table - EVT_LIST_ITEM_ACTIVATED(ID_LIST_ACTIVATE, ExportRngDialog::OnListRangeItemActivate) - EVT_BUTTON(wxID_SAVE, ExportRngDialog::OnSave) - EVT_BUTTON(wxID_CANCEL, ExportRngDialog::OnCancel) - // end wxGlade -END_EVENT_TABLE(); - - -void ExportRngDialog::OnListRangeItemActivate(wxListEvent &event) -{ - updateGrid(event.GetIndex()); - - selectedRange=event.GetIndex(); -} - -void ExportRngDialog::updateGrid(unsigned int index) -{ - const RangeFileFilter *rangeData; - rangeData=(RangeFileFilter *)rngFilters[index]; - - gridDetails->BeginBatch(); - if (gridDetails->GetNumberCols()) - gridDetails->DeleteCols(0,gridDetails->GetNumberCols()); - if (gridDetails->GetNumberRows()) - gridDetails->DeleteRows(0,gridDetails->GetNumberRows()); - - gridDetails->AppendCols(3); - gridDetails->SetColLabelValue(0,wxTRANS("Param")); - gridDetails->SetColLabelValue(1,wxTRANS("Value")); - gridDetails->SetColLabelValue(2,wxTRANS("Value2")); - - unsigned int nRows; - nRows=rangeData->getRange().getNumIons()+rangeData->getRange().getNumRanges() + 4; - gridDetails->AppendRows(nRows); - - - gridDetails->SetCellValue(0,0,wxTRANS("Ion Name")); - gridDetails->SetCellValue(0,1,wxTRANS("Num Ranges")); - unsigned int row=1; - std::string tmpStr; - - unsigned int maxNum; - maxNum=rangeData->getRange().getNumIons(); - //Add ion data, then range data - for(unsigned int ui=0;uiSetCellValue(row,0,wxStr(rangeData->getRange().getName(ui))); - stream_cast(tmpStr,rangeData->getRange().getNumRanges(ui)); - gridDetails->SetCellValue(row,1,wxStr(tmpStr)); - row++; - } - - row++; - gridDetails->SetCellValue(row,0,wxTRANS("Ion")); - gridDetails->SetCellValue(row,1,wxTRANS("Range Start")); - gridDetails->SetCellValue(row,2,wxTRANS("Range end")); - row++; - - maxNum=rangeData->getRange().getNumRanges(); - for(unsigned int ui=0;ui rngPair; - unsigned int ionID; - - rngPair=rangeData->getRange().getRange(ui); - ionID=rangeData->getRange().getIonID(ui); - gridDetails->SetCellValue(row,0, - wxStr(rangeData->getRange().getName(ionID))); - - stream_cast(tmpStr,rngPair.first); - gridDetails->SetCellValue(row,1,wxStr(tmpStr)); - - stream_cast(tmpStr,rngPair.second); - gridDetails->SetCellValue(row,2,wxStr(tmpStr)); - - row++; - } - - gridDetails->EndBatch(); -} - -void ExportRngDialog::OnSave(wxCommandEvent &event) -{ - - if(rngFilters.empty()) - EndModal(wxID_CANCEL); - - //create a file chooser for later. - wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save pos..."), wxT(""), - wxT(""),wxTRANS("ORNL format RNG (*.rng)|*.rng|All Files (*)|*"),wxFD_SAVE); - //Show, then check for user cancelling export dialog - if(wxF->ShowModal() == wxID_CANCEL) - { - wxF->Destroy(); - return; - } - - std::string dataFile = stlStr(wxF->GetPath()); - - - if(((RangeFileFilter *)(rngFilters[selectedRange]))-> - getRange().write(dataFile.c_str())) - { - std::string errString; - errString=TRANS("Unable to save. Check output destination can be written to."); - - wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) - ,wxTRANS("Save error"),wxOK|wxICON_ERROR); - wxD->ShowModal(); - wxD->Destroy(); - return; - } - - EndModal(wxID_OK); -} - -void ExportRngDialog::OnCancel(wxCommandEvent &event) -{ - EndModal(wxID_CANCEL); -} -// wxGlade: add ExportRngDialog event handlers - - -void ExportRngDialog::addRangeData(std::vector rangeData) -{ -#ifdef DEBUG - //This function should only recieve rangefile filters - for(unsigned int ui=0;uigetType() == FILTER_TYPE_RANGEFILE); -#endif - - rngFilters.resize(rangeData.size()); - std::copy(rangeData.begin(),rangeData.end(),rngFilters.begin()); - - updateRangeList(); - - if(rangeData.size()) - { - //Use the first item to populate the grid - updateGrid(0); - //select the first item - listRanges->SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - - selectedRange=0; - } -} - - -void ExportRngDialog::updateRangeList() -{ - listRanges->DeleteAllItems(); - for(unsigned int ui=0;uiInsertItem(0, wxStr(rangeData->getUserString())); - unsigned int nIons,nRngs; - nIons = rangeData->getRange().getNumIons(); - nRngs = rangeData->getRange().getNumIons(); - - stream_cast(tmpStr,nIons); - listRanges->SetItem(itemIndex, 1, wxStr(tmpStr)); - stream_cast(tmpStr,nRngs); - listRanges->SetItem(itemIndex, 2, wxStr(tmpStr)); - - } -} - -void ExportRngDialog::set_properties() -{ - // begin wxGlade: ExportRngDialog::set_properties - SetTitle(wxTRANS("Export Range")); - gridDetails->CreateGrid(0, 0); - gridDetails->SetRowLabelSize(0); - gridDetails->SetColLabelSize(0); - - listRanges->SetToolTip(wxTRANS("List of rangefiles in filter tree")); - gridDetails->EnableEditing(false); - gridDetails->SetToolTip(wxTRANS("Detailed view of selected range")); - // end wxGlade -} - - -void ExportRngDialog::do_layout() -{ - // begin wxGlade: ExportRngDialog::do_layout - wxBoxSizer* sizer_2 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_14 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_15 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_16 = new wxBoxSizer(wxVERTICAL); - sizer_16->Add(lblRanges, 0, wxLEFT|wxTOP, 5); - sizer_16->Add(listRanges, 1, wxALL|wxEXPAND, 5); - sizer_14->Add(sizer_16, 1, wxEXPAND, 0); - sizer_14->Add(10, 20, 0, 0, 0); - sizer_15->Add(label_3, 0, wxLEFT|wxTOP, 5); - sizer_15->Add(gridDetails, 1, wxALL|wxEXPAND, 5); - sizer_14->Add(sizer_15, 1, wxEXPAND, 0); - sizer_2->Add(sizer_14, 1, wxEXPAND, 0); - sizer_3->Add(20, 20, 1, 0, 0); - sizer_3->Add(btnOK, 0, wxALL, 5); - sizer_3->Add(btnCancel, 0, wxALL, 5); - sizer_2->Add(sizer_3, 0, wxEXPAND, 0); - SetSizer(sizer_2); - sizer_2->Fit(this); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/ExportRngDialog.h 3depict-0.0.13/src/dialogs/ExportRngDialog.h --- 3depict-0.0.12/src/dialogs/ExportRngDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/ExportRngDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - * ExportRngDialog.h - Range data export dialog - * Copyright (C) 2012, 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 . -*/ - -#include -#include - -#ifndef EXPORTRNGDIALOG_H -#define EXPORTRNGDIALOG_H - -// begin wxGlade: ::dependencies -#include -// end wxGlade - -#include "../viscontrol.h" -class ExportRngDialog: public wxDialog { -public: - // begin wxGlade: ExportRngDialog::ids - // end wxGlade - - ExportRngDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - -private: - //!Vis controller pointer FIXME: Can we downgrade this to const? - VisController *visControl; - //!vector containing currently available filter streams - std::vector rngFilters; - - // begin wxGlade: ExportRngDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //!Use filter data to draw wx widget - void updateRangeList(); - //!Draw details of selected range into grid - void updateGrid(unsigned int index); - - unsigned int selectedRange; -protected: - // begin wxGlade: ExportRngDialog::attributes - wxStaticText* lblRanges; - wxListCtrl* listRanges; - wxStaticText* label_3; - wxGrid* gridDetails; - wxButton* btnOK; - wxButton* btnCancel; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnListRangeItemActivate(wxListEvent &event); // wxGlade: - virtual void OnSave(wxCommandEvent &event); // wxGlade: - virtual void OnCancel(wxCommandEvent &event); // wxGlade: - - void addRangeData(std::vector rangeData); - -}; // wxGlade: end class - - -#endif // EXPORTRNGDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/StashDialog.cpp 3depict-0.0.13/src/dialogs/StashDialog.cpp --- 3depict-0.0.12/src/dialogs/StashDialog.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/StashDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,397 +0,0 @@ -/* - * StashDialog.cpp - filter "Stash" tree editing and viewing dialog - * Copyright (C) 2012, 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 . -*/ - -#include "StashDialog.h" - -#include "../wxcommon.h" -#include "../translation.h" - -#include -#include -#include - -using std::pair; -using std::string; -using std::stack; -// begin wxGlade: ::extracode - -// end wxGlade - -enum -{ - ID_TREE_FILTERS=wxID_ANY+1, - ID_GRID_FILTER, - ID_LIST_STASH, -}; - -StashDialog::StashDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, style) -{ - // begin wxGlade: StashDialog::StashDialog - label_5 = new wxStaticText(this, wxID_ANY, wxTRANS("Stashes")); - listStashes = new wxListCtrl(this, ID_LIST_STASH, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); - btnRemove = new wxButton(this, wxID_REMOVE, wxEmptyString); - label_6 = new wxStaticText(this, wxID_ANY, wxTRANS("Stashed Tree")); - treeFilters = new wxTreeCtrl(this, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_HIDE_ROOT); - label_7 = new wxStaticText(this, wxID_ANY, wxTRANS("Properties")); - gridProperties = new wxPropertyGrid(this, ID_GRID_FILTER); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - - set_properties(); - do_layout(); - // end wxGlade - gridProperties->CreateGrid(0, 2); - -} - -void StashDialog::ready() -{ - updateList(); - updateGrid(); - updateTree(); -} - -BEGIN_EVENT_TABLE(StashDialog, wxDialog) - // begin wxGlade: StashDialog::event_table - EVT_LIST_KEY_DOWN(ID_LIST_STASH, StashDialog::OnListKeyDown) - EVT_BUTTON(wxID_REMOVE, StashDialog::OnBtnRemove) - EVT_LIST_ITEM_SELECTED(ID_LIST_STASH, StashDialog::OnListSelected) - EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, StashDialog::OnTreeSelChange) - EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_FILTER,StashDialog::OnGridEditor) - // end wxGlade -END_EVENT_TABLE(); - -void StashDialog::setVisController(VisController *s) -{ - visControl=s; -} - -void StashDialog::set_properties() -{ - // begin wxGlade: StashDialog::set_properties - SetTitle(wxTRANS("Stashed Trees")); - SetSize(wxSize(600, 430)); - - btnRemove->SetToolTip(wxTRANS("Erase stashed item")); - treeFilters->SetToolTip(wxTRANS("Filter view for current stash")); - gridProperties->SetToolTip(wxTRANS("Settings for selected filter in current stash")); - listStashes->SetToolTip(wxTRANS("Available stashes")); - // end wxGlade -} - -void StashDialog::OnGridEditor(wxGridEvent &evt) -{ - evt.Veto(); -} - -void StashDialog::OnListKeyDown(wxListEvent &event) -{ - switch(event.GetKeyCode()) - { - case WXK_DELETE: - { - //Spin through the selected items - int item=-1; - for ( ;; ) - { - item = listStashes->GetNextItem(item, - wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - if ( item == -1 ) - break; - - visControl->deleteStash(listStashes->GetItemData(item)); - } - - //Update the filter list - updateList(); - updateTree(); - updateGrid(); - } - - } -} - -void StashDialog::OnListSelected(wxListEvent &event) -{ - updateTree(); - updateGrid(); -} - -void StashDialog::OnTreeSelChange(wxTreeEvent &event) -{ - updateGrid(); -} - -void StashDialog::updateList() -{ - //Generate the stash selection list - // - vector > stashes; - - visControl->getStashes(stashes); - - //Clear the existing list - listStashes->ClearAll(); - - //Fill it with "stash" entries - long itemIdx; - string strTmp; - FilterTree t; - //Add columns to report listviews - listStashes->InsertColumn(0,wxTRANS("Stash Name"),3); - listStashes->InsertColumn(1,wxTRANS("Filter Count"),1); - for (unsigned int ui=0; uiInsertItem(ui,wxStr(stashes[ui].first)); - - //Second column is num filters - - visControl->getStashTree(stashes[ui].second,t); - stream_cast(strTmp,t.size()); - listStashes->SetItem(ui,1,wxStr(strTmp)); - - //Set the stash ID as the list data item - //this is the key to the stash val - listStashes->SetItemData(itemIdx,stashes[ui].second); - } - -} - -void StashDialog::updateGrid() -{ - gridProperties->clear(); - if(!treeFilters->GetCount()) - return; - //Get the selection from the current tree - wxTreeItemId id; - id=treeFilters->GetSelection(); - - if(!id.IsOk() || id == treeFilters->GetRootItem()) - return; - - unsigned int stashId; - - //Retreive the stash ID - if(!getStashIdFromList(stashId)) - return; - - //Tree data contains unique identifier for vis control to do matching - wxTreeItemData *tData=treeFilters->GetItemData(id); - - unsigned int filterIdx = ((wxTreeUint *)tData)->value; - - FilterTree t; - visControl->getStashTree(stashId,t); - - Filter *targetFilter=0; - unsigned int pos=0; - //Spin through the tree iterators until we hit the target index - for(tree::iterator it=t.depthBegin();it!=t.depthEnd(); ++it) - { - if(pos == filterIdx) - { - targetFilter=*it; - break; - } - pos++; - } - - ASSERT(targetFilter); - - FilterPropGroup p; - targetFilter->getProperties(p); - - gridProperties->clearKeys(); - gridProperties->setNumGroups(p.numGroups()); - //Create the keys for the property grid to do its thing - for(unsigned int ui=0;ui propGrouping; - p.getGroup(ui,propGrouping); - - for(size_t uj=0;ujaddKey(propGrouping[uj].name,ui, - propGrouping[uj].key, - propGrouping[uj].type, - propGrouping[uj].data, - propGrouping[uj].helpText); - } - } - - //Let the property grid layout what it needs to - gridProperties->propertyLayout(); - -} - -bool StashDialog::getStashIdFromList(unsigned int &stashId) -{ - //Get the currently selected item - //Spin through the selected items - int item=-1; - unsigned int numItems=0; - for ( ;; ) - { - item = listStashes->GetNextItem(item, - wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - if ( item == -1 ) - break; - numItems++; - } - - //error if not only a single selected - if(numItems !=1) - return false; - - item=-1; - item = listStashes->GetNextItem(item, - wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - - stashId = listStashes->GetItemData(item); - - - return true; -} - -void StashDialog::updateTree() -{ - treeFilters->DeleteAllItems(); - - unsigned int stashId; - - //Get the selected stash and build the tree control - if(!getStashIdFromList(stashId)) - return; - - visControl->getStashTree(stashId,curTree); - - - uniqueIds.clear(); - //REBUILD TREE - //===== - stack treeIDs; - wxTreeItemId visibleTreeId; - //Warning: this generates an event, - //most of the time (some windows versions do not according to documentation) - treeFilters->DeleteAllItems(); - filterTreeMapping.clear(); - - int lastDepth=0; - //Add dummy root node. This will be invisible to wxTR_HIDE_ROOT controls - wxTreeItemId tid; - tid=treeFilters->AddRoot(wxT("TreeBase")); - unsigned int curTreePos=0; - - // Push on stack to prevent underflow, but don't keep a copy, - // as we will never insert or delete this from the UI - treeIDs.push(tid); - - //Depth first add - unsigned int pos=0; - for(tree::pre_order_iterator filtIt=curTree.depthBegin(); - filtIt!=curTree.depthEnd(); ++filtIt) - { - //Push or pop the stack to make it match the iterator position - if( lastDepth > curTree.depth(filtIt)) - { - while(curTree.depth(filtIt) +1 < (int)treeIDs.size()) - treeIDs.pop(); - } - else if( lastDepth < curTree.depth(filtIt)) - { - treeIDs.push(tid); - } - - - lastDepth=curTree.depth(filtIt); - - //This will use the user label or the type string. - tid=treeFilters->AppendItem(treeIDs.top(), - wxStr((*filtIt)->getUserString())); - - treeFilters->SetItemData(tid,new wxTreeUint(pos)); - pos++; - - //Record mapping to filter for later reference - filterTreeMapping.push_back(std::make_pair(curTreePos,*filtIt)); - - curTreePos++; - } - //===== - - - -} - -void StashDialog::OnBtnRemove(wxCommandEvent &event) -{ - //Spin through the list, to find the selected items - int item=-1; - for ( ;; ) - { - item = listStashes->GetNextItem(item, - wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - if ( item == -1 ) - break; - - visControl->deleteStash(listStashes->GetItemData(item)); - updateList(); - updateTree(); - updateGrid(); - - } - - -} - -void StashDialog::do_layout() -{ - // begin wxGlade: StashDialog::do_layout - wxBoxSizer* sizer_17 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_19 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_18 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_21 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_20 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_22 = new wxBoxSizer(wxHORIZONTAL); - sizer_17->Add(9, 8, 0, 0, 0); - sizer_20->Add(label_5, 0, wxLEFT, 5); - sizer_20->Add(listStashes, 1, wxLEFT|wxRIGHT|wxEXPAND, 5); - sizer_22->Add(btnRemove, 0, wxLEFT|wxALIGN_RIGHT, 6); - sizer_20->Add(sizer_22, 0, wxTOP|wxEXPAND, 8); - sizer_18->Add(sizer_20, 1, wxLEFT|wxEXPAND, 5); - sizer_18->Add(15, 20, 0, 0, 0); - sizer_21->Add(label_6, 0, 0, 4); - sizer_21->Add(treeFilters, 1, wxRIGHT|wxEXPAND, 5); - sizer_21->Add(label_7, 0, wxTOP, 10); - sizer_21->Add(gridProperties, 1, wxRIGHT|wxBOTTOM|wxEXPAND, 5); - sizer_18->Add(sizer_21, 1, wxRIGHT|wxEXPAND, 5); - sizer_17->Add(sizer_18, 1, wxEXPAND, 0); - sizer_17->Add(20, 20, 0, 0, 0); - sizer_19->Add(20, 20, 1, 0, 0); - sizer_19->Add(btnOK, 0, wxALL, 5); - sizer_17->Add(sizer_19, 0, wxEXPAND, 0); - SetSizer(sizer_17); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/StashDialog.h 3depict-0.0.13/src/dialogs/StashDialog.h --- 3depict-0.0.12/src/dialogs/StashDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/StashDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* - * stashdialog.h - "Stash" filter storage edit dialog header - * Copyright (C) 2012, 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 . -*/ - -#include - -#ifndef STASHDIALOG_H -#define STASHDIALOG_H - - -#include "../viscontrol.h" -#include -// end wxGlade - -// begin wxGlade: ::extracode -// end wxGlade - - -class StashDialog: public wxDialog { -public: - // begin wxGlade: StashDialog::ids - // end wxGlade - - - StashDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - - void setVisController(VisController *s); - -private: - - FilterTree curTree; - std::vector > filterTreeMapping; - UniqueIDHandler uniqueIds; - // begin wxGlade: StashDialog::methods - void set_properties(); - void do_layout(); - void updateList(); - void updateGrid(); - void updateTree(); - - bool getStashIdFromList(unsigned int &stashId); - // end wxGlade - - VisController *visControl; -protected: - // begin wxGlade: StashDialog::attributes - wxStaticText* label_5; - wxListCtrl* listStashes; - wxButton* btnRemove; - wxStaticText* label_6; - wxTreeCtrl* treeFilters; - wxStaticText* label_7; - wxPropertyGrid* gridProperties; - wxButton* btnOK; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnListKeyDown(wxListEvent &event); // wxGlade: - virtual void OnListSelected(wxListEvent &event); // wxGlade: - virtual void OnTreeSelChange(wxTreeEvent &event); // wxGlade: - virtual void OnGridEditor(wxGridEvent &event); - - virtual void OnBtnRemove(wxCommandEvent &event); - void ready(); -}; // wxGlade: end class - - - -#endif // STASHDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/animateFilterDialog.cpp 3depict-0.0.13/src/dialogs/animateFilterDialog.cpp --- 3depict-0.0.12/src/dialogs/animateFilterDialog.cpp 2012-11-24 11:31:32.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateFilterDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1195 +0,0 @@ -// -*- C++ -*- generated by wxGlade b48da20df8f4++ on Mon May 7 22:48:14 2012 - -#include "animateFilterDialog.h" -#include "resolutionDialog.h" -#include "./animateSubDialogs/realKeyFrameDialog.h" -#include "./animateSubDialogs/colourKeyFrameDialog.h" -#include "./animateSubDialogs/stringKeyFrameDialog.h" -#include "./animateSubDialogs/choiceKeyFrameDialog.h" -// begin wxGlade: ::extracode - -// end wxGlade - -#include -#include -#include -#include -#include "basics.h" -#include "translation.h" -#include "wxcommon.h" -#include "commonConstants.h" - -#include "filter.h" -#include "filtertree.h" -#include "viscontrol.h" //For tree update routine -enum -{ - ID_FILTER_TREE_CTRL, - ID_PROPERTY_GRID, - ID_ANIMATION_GRID_CTRL, - ID_BUTTON_FRAME_REMOVE, - ID_TEXTBOX_WORKDIR, - ID_BUTTON_WORKDIR, - ID_CHECK_IMAGE_OUT, - ID_TEXTBOX_IMAGEPREFIX, - ID_TEXTBOX_IMAGESIZE, - ID_BUTTON_IMAGE_RES, - ID_CHECK_ONLYDATACHANGE, - ID_CHECK_POINT_OUT, - ID_CHECK_PLOT_OUT, - ID_CHECK_VOXEL_OUT, - ID_CHECK_RANGE_OUT, - ID_COMBO_RANGE_TYPE, - ID_SPLIT_FILTERVIEW, - ID_FRAME_SLIDER, - ID_FRAME_TEXTBOX, - ID_BTN_OK, - ID_BTN_CANCEL, - ID_FILTER_PROPERTY_VALUE_GRID -}; -enum -{ - CELL_FILTERNAME, - CELL_PROPERTYNAME, - CELL_KEYINTERPMODE, - CELL_STARTFRAME, - CELL_ENDFRAME -}; - -enum -{ - FRAME_CELL_FILTERNAME, - FRAME_CELL_PROPNAME, - FRAME_CELL_VALUE -}; - -const size_t RANGE_FORMAT_NUM_OPTIONS=3; - - -//TODO: This should be merged into aptclasses? -const char *extension[RANGE_FORMAT_NUM_OPTIONS] = -{ - "rng", - "rrng", - "env" -}; - -const char * comboRange_choices[RANGE_FORMAT_NUM_OPTIONS] = -{ - NTRANS("Oak-Ridge RNG"), - NTRANS("Cameca/Ametek RRNG"), - NTRANS("Cameca/Ametek ENV") -}; - -using std::string; -using std::cout; -using std::endl; - - -template -bool getRealKeyFrame(FrameProperties &frameProp, - FilterProperty &filterProp, RealKeyFrameDialog *r) -{ - if( r->ShowModal() != wxID_OK) - { - r->Destroy(); - return false; - } - - //Copy out the data obtained from the dialog - size_t transitionMode; - T value; - transitionMode=r->getTransitionMode(); - frameProp.setInterpMode(transitionMode); - - value=r->getStartValue(); - stream_cast(filterProp.data,value); - - frameProp.addKeyFrame(r->getStartFrame(),filterProp); - - //Add end value as needed - switch(transitionMode) - { - case TRANSITION_STEP: - break; - case TRANSITION_INTERP: - value=r->getEndValue(); - stream_cast(filterProp.data,value); - frameProp.addKeyFrame(r->getEndFrame(),filterProp); - break; - default: - ASSERT(false); - } - - r->Destroy(); - - return true; -} - -ExportAnimationDialog::ExportAnimationDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX) -{ - // begin wxGlade: ExportAnimationDialog::ExportAnimationDialog - viewNotebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); - frameViewPane = new wxPanel(viewNotebook, wxID_ANY); - filterViewPane = new wxPanel(viewNotebook, wxID_ANY); - splitPaneFilter = new wxSplitterWindow(filterViewPane, ID_SPLIT_FILTERVIEW, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); - filterRightPane = new wxPanel(splitPaneFilter, wxID_ANY); - filterLeftPane = new wxPanel(splitPaneFilter, wxID_ANY); - keyFramesSizer_staticbox = new wxStaticBox(filterRightPane, -1, wxTRANS("Key frames")); - outputDataSizer_staticbox = new wxStaticBox(frameViewPane, -1, wxTRANS("Output Data")); - filterPropertySizer_staticbox = new wxStaticBox(filterLeftPane, -1, wxTRANS("Filters and properties")); - filterTreeCtrl =new wxTreeCtrl(filterLeftPane,ID_FILTER_TREE_CTRL , wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_EDIT_LABELS); - - propertyGrid = new wxPropertyGrid(filterLeftPane, ID_PROPERTY_GRID); - animationGrid = new wxGrid(filterRightPane, ID_ANIMATION_GRID_CTRL); - keyFrameRemoveButton = new wxButton(filterRightPane, wxID_REMOVE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - labelWorkDir = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Dir : ")); - textWorkDir = new wxTextCtrl(frameViewPane, ID_TEXTBOX_WORKDIR, wxEmptyString); - buttonWorkDir = new wxButton(frameViewPane, wxID_OPEN, wxEmptyString); - checkOutOnlyChanged = new wxCheckBox(frameViewPane, ID_CHECK_ONLYDATACHANGE, wxTRANS("Output only when refresh required")); - outputDataSepLine = new wxStaticLine(frameViewPane, wxID_ANY); - labelDataType = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Data Types:")); - checkImageOutput = new wxCheckBox(frameViewPane, ID_CHECK_IMAGE_OUT, wxTRANS("3D Images")); - lblImageName = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("File Prefix: ")); - textImageName = new wxTextCtrl(frameViewPane, ID_TEXTBOX_IMAGEPREFIX, wxEmptyString); - labelImageSize = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Size : ")); - textImageSize = new wxTextCtrl(frameViewPane, ID_TEXTBOX_IMAGESIZE, wxEmptyString); - buttonImageSize = new wxButton(frameViewPane, ID_BUTTON_IMAGE_RES, wxTRANS("...")); - checkPoints = new wxCheckBox(frameViewPane, ID_CHECK_POINT_OUT, wxTRANS("Point data")); - checkPlotData = new wxCheckBox(frameViewPane, ID_CHECK_PLOT_OUT, wxTRANS("Plots")); - checkVoxelData = new wxCheckBox(frameViewPane, ID_CHECK_VOXEL_OUT, wxTRANS("Voxel data")); - checkRangeData = new wxCheckBox(frameViewPane, ID_CHECK_RANGE_OUT, wxTRANS("Range files")); - labelRangeFormat = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Format")); - - //Workaround for wx bug http://trac.wxwidgets.org/ticket/4398 - wxSortedArrayString rangeNames; - for(unsigned int ui=0;uicomboRange_choices offset. - rangeMap[TRANS(str)] = ui; - //Add to filter name wxArray - wxString wxStrTrans = wxTRANS(str); - rangeNames.Add(wxStrTrans); - } - comboRangeFormat = new wxComboBox(frameViewPane, ID_COMBO_RANGE_TYPE, wxT(""), wxDefaultPosition, wxDefaultSize, rangeNames, wxCB_DROPDOWN|wxCB_READONLY|SAFE_CB_SORT); - static_line_1 = new wxStaticLine(frameViewPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); - labelFrame = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Frame")); - frameSlider = new wxSlider(frameViewPane, ID_FRAME_SLIDER, 1, 1, 1); - textFrame = new wxTextCtrl(frameViewPane, ID_FRAME_TEXTBOX, wxEmptyString); - framePropGrid = new wxGrid(frameViewPane, ID_FILTER_PROPERTY_VALUE_GRID); - cancelButton = new wxButton(this, wxID_CANCEL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - okButton = new wxButton(this, wxID_OK, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - - - set_properties(); - do_layout(); - // end wxGlade - - -#if wxCHECK_VERSION(2,9,0) - //Manually tuned splitter parameters - splitPaneFilter->SetMinimumPaneSize(220); - int w, h; - GetClientSize(&w,&h); - - float sashFrac=0.4; - - splitPaneFilter->SetSashPosition((int)(sashFrac*w)); -#endif - - programmaticEvent=true; - - //-- set up the default properties for dialog back-end data - imageWidth=640; - imageHeight=480; - imageSizeOK=true; - - //Plot check status - wantPlotOutput=checkPlotData->IsChecked(); - wantImageOutput=checkImageOutput->IsChecked(); - wantIonOutput=checkPoints->IsChecked(); - wantPlotOutput=checkPlotData->IsChecked(); - wantVoxelOutput=checkVoxelData->IsChecked(); - wantRangeOutput=checkRangeData->IsChecked(); - wantOnlyChanges=checkOutOnlyChanged->IsChecked(); - - string sFirst,sSecond; - stream_cast(sFirst,imageWidth); - stream_cast(sSecond,imageHeight); - textImageSize->SetValue(wxStr(string(sFirst+string("x")+sSecond))); - textImageSize->SetBackgroundColour(wxNullColour); - - currentFrame=0; - existsConflicts=false; - //--- - - programmaticEvent=false; -} - -ExportAnimationDialog::~ExportAnimationDialog() -{ - filterTree=0; -} - -BEGIN_EVENT_TABLE(ExportAnimationDialog, wxDialog) - // begin wxGlade: ExportAnimationDialog::event_table - EVT_TREE_SEL_CHANGED(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnFilterTreeCtrlSelChanged) - EVT_GRID_CMD_EDITOR_SHOWN(ID_PROPERTY_GRID, ExportAnimationDialog::OnFilterGridCellEditorShow) - EVT_GRID_CMD_EDITOR_SHOWN(ID_ANIMATION_GRID_CTRL, ExportAnimationDialog::OnFrameGridCellEditorShow) - EVT_GRID_CMD_EDITOR_SHOWN(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnAnimateGridCellEditorShow) - EVT_SPLITTER_UNSPLIT(ID_SPLIT_FILTERVIEW, ExportAnimationDialog::OnFilterViewUnsplit) - EVT_BUTTON(wxID_REMOVE, ExportAnimationDialog::OnButtonKeyFrameRemove) - EVT_TEXT(ID_TEXTBOX_WORKDIR, ExportAnimationDialog::OnOutputDirText) - EVT_BUTTON(wxID_OPEN, ExportAnimationDialog::OnButtonWorkDir) - EVT_CHECKBOX(ID_CHECK_ONLYDATACHANGE, ExportAnimationDialog::OnCheckOutDataChange) - EVT_CHECKBOX(ID_CHECK_IMAGE_OUT, ExportAnimationDialog::OnCheckImageOutput) - EVT_TEXT(ID_TEXTBOX_IMAGEPREFIX, ExportAnimationDialog::OnImageFilePrefix) - EVT_TEXT(ID_TEXTBOX_IMAGESIZE, ExportAnimationDialog::OnTextImageSize) - EVT_BUTTON(ID_BUTTON_IMAGE_RES, ExportAnimationDialog::OnBtnResolution) - EVT_CHECKBOX(ID_CHECK_POINT_OUT, ExportAnimationDialog::OnCheckPointOutput) - EVT_CHECKBOX(ID_CHECK_PLOT_OUT, ExportAnimationDialog::OnCheckPlotOutput) - EVT_CHECKBOX(ID_CHECK_VOXEL_OUT, ExportAnimationDialog::OnCheckVoxelOutput) - EVT_CHECKBOX(ID_CHECK_RANGE_OUT, ExportAnimationDialog::OnCheckRangeOutput) - EVT_COMBOBOX(ID_COMBO_RANGE_TYPE, ExportAnimationDialog::OnRangeTypeCombo) - EVT_COMMAND_SCROLL(ID_FRAME_SLIDER, ExportAnimationDialog::OnFrameViewSlider) - EVT_TEXT(ID_FRAME_TEXTBOX, ExportAnimationDialog::OnTextFrame) - EVT_BUTTON(ID_BTN_CANCEL, ExportAnimationDialog::OnButtonCancel) - EVT_BUTTON(ID_BTN_OK, ExportAnimationDialog::OnButtonOK) - // end wxGlade -END_EVENT_TABLE(); - - -bool ExportAnimationDialog::getModifiedTree(size_t frame, FilterTree &t,bool &needsUp) const -{ - vector propsAtFrame; - vector propIds; - - propertyAnimator.getPropertiesAtFrame(frame,propIds,propsAtFrame); - - needsUp=false; - for(size_t ui=0;ui dummyVec; - upWxTreeCtrl(*filterTree,filterTreeCtrl,filterMap, - dummyVec,NULL); - - update(); -} - -void ExportAnimationDialog::updateFilterViewGrid() -{ - //Empty the grid - animationGrid->BeginBatch(); - if(animationGrid->GetNumberRows()) - animationGrid->DeleteRows(0,animationGrid->GetNumberRows()); - animationGrid->EndBatch(); - - - animationGrid->AppendRows(propertyAnimator.getNumProps()); - for(size_t ui=0;uigetProperties(filtPropGroup); - FilterProperty filtProp; - filtProp=filtPropGroup.getPropValue(frameProps.getPropertyKey()); - - animationGrid->SetCellValue(ui,CELL_FILTERNAME, - wxStr(filterPtr->getUserString())); - animationGrid->SetCellValue(ui,CELL_PROPERTYNAME, - wxStr(filtProp.name)); - animationGrid->SetCellValue(ui,CELL_KEYINTERPMODE, - wxCStr(INTERP_NAME[frameProps.getInterpMode()])); - - string str; - stream_cast(str,frameProps.getMinFrame()); - animationGrid->SetCellValue(ui,CELL_STARTFRAME, wxStr(str)); - stream_cast(str,frameProps.getMaxFrame()); - animationGrid->SetCellValue(ui,CELL_ENDFRAME, wxStr(str)); - } - - //CHeck for conflicting rows in the animation dialog, - // and highlight them in colour - set conflictRows; - if(!propertyAnimator.checkSelfConsistent(conflictRows)) - { - existsConflicts=true; - for(std::set::const_iterator it=conflictRows.begin(); - it!=conflictRows.end();++it) - { - wxGridCellAttr *colourRowAttr=new wxGridCellAttr; - colourRowAttr->SetBackgroundColour(wxColour(*wxCYAN)); - animationGrid->SetRowAttr(*it,colourRowAttr); - } - } -} - -void ExportAnimationDialog::updateFrameViewGrid() -{ - ASSERT(currentFrame <= frameSlider->GetMax()); - - //Empty the grid - framePropGrid->BeginBatch(); - if(framePropGrid->GetNumberRows()) - framePropGrid->DeleteRows(0,animationGrid->GetNumberRows()); - framePropGrid->EndBatch(); - - std::set conflictProps; - if(!propertyAnimator.checkSelfConsistent(conflictProps)) - return; - - vector alteredProperties; - vector propertyIds; - //Grab the properties that have been modified from their initial value - // and then refill the grid with this data - propertyAnimator.getPropertiesAtFrame(currentFrame, - propertyIds,alteredProperties); - - framePropGrid->AppendRows(alteredProperties.size()); - - for(size_t ui=0; uigetUserString(); - - - FilterPropGroup p; - FilterProperty prop; - //obtain filter properties - filterMap.at(idFilter)->getProperties(p); - prop=p.getPropValue(alteredProperties[ui].getPropertyKey()); - propertyName=prop.name; - - - std::string animatedValue; - animatedValue=propertyAnimator.getInterpolatedFilterData( - alteredProperties[ui].getFilterId(),prop.key,currentFrame); - //-- - - //Moidify the grid properties with the appropriate data - framePropGrid->SetCellValue(ui,FRAME_CELL_FILTERNAME, - wxStr(filterName)); - framePropGrid->SetCellValue(ui,FRAME_CELL_PROPNAME, - wxStr(propertyName)); - framePropGrid->SetCellValue(ui,FRAME_CELL_VALUE, - wxStr(animatedValue)); - } - -} - -void ExportAnimationDialog::updateFrameViewSlider() -{ - - programmaticEvent=true; - - //reset the range on the frame slider - size_t maxFrameVal; - maxFrameVal=propertyAnimator.getMaxFrame(); - frameSlider->SetMin(0); - frameSlider->SetMax(maxFrameVal); - - //Update the textbox - std::string textCurrent,textMax; - stream_cast(textCurrent,frameSlider->GetValue()); - stream_cast(textMax,propertyAnimator.getMaxFrame()); - - textCurrent= (textCurrent + std::string("/") + textMax); - textFrame->SetValue( wxStr(textCurrent)); - - programmaticEvent=false; - -} - -void ExportAnimationDialog::OnTextFrame(wxCommandEvent &event) -{ - if(programmaticEvent) - return; - - string s; - s=stlStr(textImageSize->GetValue()); - - bool parseOK=true; - size_t pos; - size_t frameCur,frameEnd; - pos = s.find('/'); - if(pos==string::npos) - parseOK=false; - else - { - string first,last; - first = s.substr(0,pos); - last=s.substr(pos+1); - - - if(stream_cast(frameCur,first)) - parseOK=false; - - - if(stream_cast(frameEnd,last)) - parseOK=false; - } - - if(!parseOK) - textImageSize->SetBackgroundColour(*wxCYAN); - else - { - textImageSize->SetBackgroundColour(wxNullColour); - - currentFrame=frameCur; - - updateFrameViewGrid(); - } - imageSizeOK=parseOK; - - update(); -} - -void ExportAnimationDialog::OnFrameViewSlider(wxScrollEvent &event) -{ - programmaticEvent=true; - size_t sliderVal=frameSlider->GetValue(); - - - std::string frameText,tmp; - stream_cast(frameText,sliderVal); - frameText+= "/"; - stream_cast(tmp,frameSlider->GetMax()); - frameText+=tmp; - - textFrame->SetValue( wxStr(frameText)); - - currentFrame=sliderVal; - updateFrameViewGrid(); - programmaticEvent=false; -} - -void ExportAnimationDialog::OnButtonCancel(wxCommandEvent &event) -{ - event.Skip(); -} - -void ExportAnimationDialog::update() -{ - programmaticEvent=true; - updateFilterViewGrid(); - updateFrameViewGrid(); - updateFrameViewSlider(); - updateOKButton(); - programmaticEvent=false; -} - -void ExportAnimationDialog::OnFilterTreeCtrlSelChanged(wxTreeEvent &event) -{ - //Get the parent filter pointer - wxTreeItemId id=filterTreeCtrl->GetSelection();; - - if(id !=filterTreeCtrl->GetRootItem() && id.IsOk()) - { - wxTreeItemData *parentData=filterTreeCtrl->GetItemData(id); - updateFilterPropertyGrid(propertyGrid, - filterMap[((wxTreeUint *)parentData)->value]); - } - - event.Skip(); -} - - -void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event) -{ - event.Veto(); - wxTreeItemId id=filterTreeCtrl->GetSelection();; - - if(id ==filterTreeCtrl->GetRootItem() || !id.IsOk()) - return; - - - unsigned int key; - key=propertyGrid->getKeyFromRow(event.GetRow()); - - //Get the filter ID value - size_t filterId; - wxTreeItemId tId = filterTreeCtrl->GetSelection(); - if(!tId.IsOk()) - return; - - wxTreeItemData *tData=filterTreeCtrl->GetItemData(tId); - filterId = ((wxTreeUint *)tData)->value; - - const Filter *f; - f=filterMap.at(filterId); - - //Obtain the filter property that was selected by the user - //-- - FilterPropGroup propGroup; - f->getProperties(propGroup); - - FilterProperty filterProp; - filterProp=propGroup.getPropValue(key); - //-- - - //Create a property entry for this, and get values from user - FrameProperties frameProp(filterId,key); - switch(filterProp.type) - { - case PROPERTY_TYPE_BOOL: - { - wxTextEntryDialog *teD = new wxTextEntryDialog(this,wxTRANS("transition frame"),wxTRANS("Frame count"), - wxT("0"),(long int)wxOK|wxCANCEL); - - std::string s; - size_t frameValue; - do - { - if(teD->ShowModal() == wxID_CANCEL) - { - teD->Destroy(); - return; - } - - s=stlStr(teD->GetValue()); - } - while(stream_cast(frameValue,s)); - ASSERT(filterProp.data == "1" || filterProp.data == "0"); - - - //Find the last property for the fitler from the animator - // if available - std::string sData; - sData=propertyAnimator.getInterpolatedFilterData(filterId, - key,std::min(frameValue, - propertyAnimator.getMaxFrame())); - - if(!sData.empty()) - { - ASSERT(sData == "0" || sData == "1"); - filterProp.data=sData; - } - - //Flip the data - if(filterProp.data == "1") - filterProp.data="0"; - else - filterProp.data="1"; - - frameProp.setInterpMode(INTERP_STEP); - frameProp.addKeyFrame(frameValue,filterProp); - - teD->Destroy(); - break; - } - case PROPERTY_TYPE_CHOICE: - { - vector choiceVec; - unsigned int activeChoice; - choiceStringToVector(filterProp.data,choiceVec,activeChoice); - - ChoiceKeyFrameDialog *cD = new ChoiceKeyFrameDialog(this, - wxID_ANY,wxT("")); - cD->setChoices(choiceVec); - - if( cD->ShowModal() != wxID_OK) - { - cD->Destroy(); - return; - } - - filterProp.data=cD->getChoice(); - frameProp.setInterpMode(INTERP_STEP); - frameProp.addKeyFrame(cD->getStartFrame(),filterProp); - - cD->Destroy(); - - - break; - } - case PROPERTY_TYPE_COLOUR: - { - ColourKeyFrameDialog *colDlg = new ColourKeyFrameDialog(this, - wxID_ANY,wxTRANS("Key frame : Colour")) ; - if( colDlg->ShowModal() != wxID_OK) - { - colDlg->Destroy(); - return; - } - - //Copy out the data obtained from the dialog - size_t transitionMode; - transitionMode=colDlg->getTransitionMode(); - - frameProp.setInterpMode(transitionMode); - filterProp.data=colDlg->getStartValue(); - - frameProp.addKeyFrame(colDlg->getStartFrame(),filterProp); - //Add end value as needed - switch(transitionMode) - { - case TRANSITION_STEP: - break; - case TRANSITION_INTERP: - filterProp.data=colDlg->getEndValue(); - frameProp.setInterpMode(INTERP_LINEAR_COLOUR); - frameProp.addKeyFrame(colDlg->getEndFrame(),filterProp); - break; - default: - ASSERT(false); - } - colDlg->Destroy(); - - break; - } - case PROPERTY_TYPE_STRING: - { - //Create and show the string keyframe input dialog - StringKeyFrameDialog *sd = new StringKeyFrameDialog(this, - wxID_ANY,_("")); - - if(sd->ShowModal() != wxID_OK) - { - sd->Destroy(); - return; - } - - //set the interpolator to step-by-step interp - frameProp.setInterpMode(INTERP_LIST); - - //Grab the data vector we need to insert the keyframes - vector dataVec; - if(!sd->getStrings(dataVec)) - { - sd->Destroy(); - wxMessageDialog *wxD =new wxMessageDialog(this, - wxTRANS("File existed, but was unable to read or interpret file contents."), - wxTRANS("String load failed"),wxICON_ERROR|wxOK); - - wxD->ShowModal(); - wxD->Destroy(); - return; - } - - for(size_t ui=0;uigetStartFrame()+ui,filterProp); - } - - sd->Destroy(); - - - break; - } - case PROPERTY_TYPE_REAL: - { - RealKeyFrameDialog *r = new RealKeyFrameDialog(this, - wxID_ANY,wxTRANS("Keyframe : decimal")); - if(!getRealKeyFrame(frameProp,filterProp,r)) - return; - frameProp.setInterpMode(r->getTransitionMode()); - break; - } - case PROPERTY_TYPE_INTEGER: - { - RealKeyFrameDialog *r = new RealKeyFrameDialog(this, - wxID_ANY,wxTRANS("Keyframe : integer")); - if(!getRealKeyFrame(frameProp,filterProp,r)) - return; - frameProp.setInterpMode(r->getTransitionMode()); - break; - } - case PROPERTY_TYPE_POINT3D: - { - RealKeyFrameDialog *r = new RealKeyFrameDialog(this, - wxID_ANY,wxTRANS("Keyframe : 3D Point")); - if(!getRealKeyFrame(frameProp,filterProp,r)) - return; - //Animator needs special Linear ramping code, so select that - // if user chooses a linear ramp - if(frameProp.getInterpMode()==INTERP_LINEAR_FLOAT) - frameProp.setInterpMode(INTERP_LINEAR_POINT3D); - else - frameProp.setInterpMode(r->getTransitionMode()); - - break; - } - default: - ASSERT(false); // that should cover all data types... - } - - //Add property to animator - propertyAnimator.addProp(frameProp); - - //update the user interface controls - update(); - -} - -void ExportAnimationDialog::OnFrameGridCellEditorShow(wxGridEvent &event) -{ - event.Veto(); -} - -void ExportAnimationDialog::OnFilterViewUnsplit(wxSplitterEvent &evt) -{ - evt.Veto(); -} - -void ExportAnimationDialog::OnAnimateGridCellEditorShow(wxGridEvent &event) -{ - event.Veto(); -} - -void ExportAnimationDialog::OnButtonKeyFrameRemove(wxCommandEvent &event) -{ - if(!animationGrid->GetNumberRows()) - return; - //Obtain the IDs of the selected rows, or partially selected rows - ;wxGridCellCoordsArray selectedRows = animationGrid->GetSelectedCells(); - - wxGridCellCoordsArray arrayTL(animationGrid->GetSelectionBlockTopLeft()); - wxGridCellCoordsArray arrayBR(animationGrid->GetSelectionBlockBottomRight()); - - //This is an undocumented class AFAIK. :( - if(arrayTL.Count() && arrayBR.Count()) - { - wxGridCellCoords coordTL = arrayTL.Item(0); - wxGridCellCoords coordBR = arrayBR.Item(0); - - size_t rows = coordBR.GetRow() - coordTL.GetRow() +1; - - vector rowsToKill; - rowsToKill.resize(rows); - - for(size_t r=0; rGetGridCursorRow(); - propertyAnimator.removeNthKeyFrame(rowToKill); - } - - - //update user interface - update(); - -} - -void ExportAnimationDialog::updateOKButton() -{ - bool badStatus=false; - - badStatus|=workDir.empty(); - badStatus|=filterMap.empty(); - badStatus|=(imagePrefix.empty() && wantImageOutput); - badStatus|=(propertyAnimator.getNumProps() == 0); - - //Ensure that there were no inconsisted properties in - // the animation - std::set inconsistentProps; - badStatus|=!propertyAnimator.checkSelfConsistent(inconsistentProps); - okButton->Enable(!badStatus); -} - -void ExportAnimationDialog::OnOutputDirText(wxCommandEvent &event) -{ - if(programmaticEvent) - return; - - if(!wxDirExists(textWorkDir->GetValue())) - { - textWorkDir->SetBackgroundColour(*wxCYAN); - workDir.clear(); - } - else - { - textWorkDir->SetBackgroundColour(wxNullColour); - workDir=stlStr(textWorkDir->GetValue()); - } - - //update the user interface controls - update(); -} - - -void ExportAnimationDialog::OnButtonWorkDir(wxCommandEvent &event) -{ - //Pop up a directory dialog, to choose the base path for the new folder - wxDirDialog *wxD = new wxDirDialog(this, wxTRANS("Select or create new folder"), - wxFileSelectorDefaultWildcardStr, wxFD_SAVE); - - unsigned int res; - res = wxD->ShowModal(); - - while(res != wxID_CANCEL) - { - //If dir exists, exit - if(wxDirExists(wxD->GetPath())) - break; - - res=wxD->ShowModal(); - } - - //User aborted directory choice. - if(res==wxID_CANCEL) - { - wxD->Destroy(); - return; - } - - textWorkDir->SetValue(wxD->GetPath()); - workDir=stlStr(textWorkDir->GetValue()); - wxD->Destroy(); - - //update the user interface controls - update(); -} - -void ExportAnimationDialog::OnCheckOutDataChange(wxCommandEvent &event) -{ - if(programmaticEvent) - return; - - wantOnlyChanges=checkOutOnlyChanged->IsChecked(); -} - -void ExportAnimationDialog::OnCheckImageOutput(wxCommandEvent &event) -{ - if(programmaticEvent) - return; - - wantImageOutput=checkImageOutput->IsChecked(); - //update UI (eg OK button) - update(); -} - - -void ExportAnimationDialog::OnImageFilePrefix(wxCommandEvent &event) -{ - if(programmaticEvent) - return; - - imagePrefix=stlStr(textImageName->GetValue()); - - //update UI (eg OK button) - update(); -} - - -void ExportAnimationDialog::OnTextImageSize(wxCommandEvent &event) -{ - - if(programmaticEvent) - return; - - string s; - s=stlStr(textImageSize->GetValue()); - - bool parseOK=true; - size_t pos; - pos = s.find('x'); - if(pos==string::npos) - parseOK=false; - else - { - string first,last; - first = s.substr(0,pos); - last=s.substr(pos+1); - - - size_t w,h; - if(stream_cast(w,first)) - parseOK&=false; - - - if(stream_cast(h,last)) - parseOK&=false; - } - - if(!parseOK) - textImageSize->SetBackgroundColour(*wxCYAN); - else - textImageSize->SetBackgroundColour(wxNullColour); - - //update UI (eg OK button) - update(); -} - - -void ExportAnimationDialog::OnBtnResolution(wxCommandEvent &event) -{ - ResolutionDialog *r = new ResolutionDialog(this,wxID_ANY,wxT("Choose Resolution")); - - r->setRes(imageWidth,imageHeight); - - if(r->ShowModal() != wxID_OK) - { - r->Destroy(); - return; - } - - imageWidth=r->getWidth(); - imageHeight=r->getHeight(); - - string sWidth,sHeight; - stream_cast(sWidth,imageWidth); - stream_cast(sHeight,imageHeight); - - string s; - s=sWidth+"x" + sHeight; - textImageSize->SetValue(wxStr(s)); - - r->Destroy(); -} - - -void ExportAnimationDialog::OnCheckPointOutput(wxCommandEvent &event) -{ - wantIonOutput=checkPoints->IsChecked(); -} - - -void ExportAnimationDialog::OnCheckPlotOutput(wxCommandEvent &event) -{ - wantPlotOutput=checkPlotData->IsChecked(); -} - - -void ExportAnimationDialog::OnCheckVoxelOutput(wxCommandEvent &event) -{ - wantVoxelOutput=checkVoxelData->IsChecked(); -} - - -void ExportAnimationDialog::OnCheckRangeOutput(wxCommandEvent &event) -{ - wantRangeOutput=checkRangeData->IsChecked(); -} - -void ExportAnimationDialog::OnRangeTypeCombo(wxCommandEvent &event) -{ - rangeExportMode=event.GetSelection(); -} - - -void ExportAnimationDialog::OnButtonOK(wxCommandEvent &event) -{ - event.Skip(); -} - -size_t ExportAnimationDialog::getRangeFormat() const -{ - return rangeExportMode; - -} - -// wxGlade: add ExportAnimationDialog event handlers - - -void ExportAnimationDialog::set_properties() -{ - // begin wxGlade: ExportAnimationDialog::set_properties - SetTitle(wxTRANS("Export Animation")); - filterTreeCtrl->SetToolTip(wxTRANS("Select filter")); - propertyGrid->CreateGrid(0, 2); - propertyGrid->SetColLabelValue(0, wxTRANS("Property")); - propertyGrid->SetColLabelValue(1, wxTRANS("Value")); - propertyGrid->SetToolTip(wxTRANS("Select property")); - animationGrid->CreateGrid(0, 5); - animationGrid->SetColLabelValue(0, wxTRANS("Filter")); - animationGrid->SetColLabelValue(1, wxTRANS("Property")); - animationGrid->SetColLabelValue(2, wxTRANS("Mode")); - animationGrid->SetColLabelValue(3, wxTRANS("Start Frame")); - animationGrid->SetColLabelValue(4, wxTRANS("End Frame")); - animationGrid->SetToolTip(wxTRANS("Keyframe table")); - keyFrameRemoveButton->SetToolTip(wxTRANS("Remove the selected keyframe from the table")); - textWorkDir->SetToolTip(wxTRANS("Enter where the animation frames will be exported to")); - buttonWorkDir->SetToolTip(wxTRANS("Browse to directory where the animation frames will be exported to")); - checkImageOutput->SetValue(1); - textImageName->SetToolTip(wxTRANS("Enter a descriptive name for output files")); - textImageSize->SetToolTip(wxTRANS("Enter the target resoltuion (image size)")); - comboRangeFormat->SetSelection(-1); - frameSlider->SetToolTip(wxTRANS("Select frame for property display")); - textFrame->SetToolTip(wxTRANS("Enter frame number to change frame (eg 1/20)")); - checkPoints->SetToolTip(wxTRANS("Save point data (POS files) in output folder?")); - checkPlotData->SetToolTip(wxTRANS("Save plots (as text files) in output folder?")); - checkVoxelData->SetToolTip(wxTRANS("Save voxel data (raw files) in output folder?")); - checkRangeData->SetToolTip(wxTRANS("Save range files in output folder?")); - framePropGrid->CreateGrid(0, 3); - framePropGrid->SetColLabelValue(0, wxTRANS("Filter")); - framePropGrid->SetColLabelValue(1, wxTRANS("Property")); - framePropGrid->SetColLabelValue(2, wxTRANS("Value")); - framePropGrid->SetToolTip(wxTRANS("Animation parameters for current frame")); - cancelButton->SetToolTip(wxTRANS("Abort animation")); - okButton->SetToolTip(wxTRANS("Run Animation")); - // end wxGlade -} - - -void ExportAnimationDialog::do_layout() -{ - // begin wxGlade: ExportAnimationDialog::do_layout - wxBoxSizer* animateSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* globalButtonSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* frameViewSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* propGridSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* frameSliderSizer = new wxBoxSizer(wxHORIZONTAL); - wxStaticBoxSizer* outputDataSizer = new wxStaticBoxSizer(outputDataSizer_staticbox, wxVERTICAL); - wxBoxSizer* rangeFileDropDownSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* outputImageOptionsSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* imageSizeSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* filePrefixSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* outputDirHorizSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* filterViewPaneSizerH = new wxBoxSizer(wxHORIZONTAL); - wxStaticBoxSizer* keyFramesSizer = new wxStaticBoxSizer(keyFramesSizer_staticbox, wxVERTICAL); - wxBoxSizer* keyFrameButtonSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* animationGridSizer = new wxBoxSizer(wxHORIZONTAL); - wxStaticBoxSizer* filterPropertySizer = new wxStaticBoxSizer(filterPropertySizer_staticbox, wxVERTICAL); - filterPropertySizer->Add(filterTreeCtrl, 1, wxALL|wxEXPAND, 3); - filterPropertySizer->Add(propertyGrid, 1, wxALL|wxEXPAND, 3); - filterLeftPane->SetSizer(filterPropertySizer); - animationGridSizer->Add(animationGrid, 1, wxALL|wxEXPAND, 3); - keyFramesSizer->Add(animationGridSizer, 1, wxEXPAND, 0); - keyFrameButtonSizer->Add(keyFrameRemoveButton, 0, wxALIGN_CENTER_HORIZONTAL, 0); - keyFramesSizer->Add(keyFrameButtonSizer, 0, wxALL|wxEXPAND, 3); - filterRightPane->SetSizer(keyFramesSizer); - splitPaneFilter->SplitVertically(filterLeftPane, filterRightPane); - filterViewPaneSizerH->Add(splitPaneFilter, 1, wxEXPAND, 0); - filterViewPane->SetSizer(filterViewPaneSizerH); - outputDirHorizSizer->Add(labelWorkDir, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 3); - outputDirHorizSizer->Add(textWorkDir, 1, wxEXPAND, 0); - outputDirHorizSizer->Add(buttonWorkDir, 0, wxLEFT|wxRIGHT, 2); - outputDataSizer->Add(outputDirHorizSizer, 0, wxALL|wxEXPAND, 4); - sizer_1->Add(20, 20, 0, 0, 0); - sizer_1->Add(checkOutOnlyChanged, 0, 0, 0); - outputDataSizer->Add(sizer_1, 0, wxBOTTOM|wxEXPAND, 5); - outputDataSizer->Add(outputDataSepLine, 0, wxTOP|wxBOTTOM|wxEXPAND, 3); - outputDataSizer->Add(labelDataType, 0, wxTOP|wxBOTTOM, 4); - outputDataSizer->Add(checkImageOutput, 0, wxLEFT|wxTOP, 3); - filePrefixSizer->Add(lblImageName, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 3); - filePrefixSizer->Add(textImageName, 1, wxALL|wxEXPAND, 4); - outputImageOptionsSizer->Add(filePrefixSizer, 0, wxALL|wxEXPAND, 3); - imageSizeSizer->Add(labelImageSize, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 3); - imageSizeSizer->Add(textImageSize, 1, wxALL|wxEXPAND, 4); - imageSizeSizer->Add(buttonImageSize, 0, wxALL, 4); - outputImageOptionsSizer->Add(imageSizeSizer, 0, wxALL|wxEXPAND, 3); - outputDataSizer->Add(outputImageOptionsSizer, 0, wxEXPAND, 0); - outputDataSizer->Add(checkPoints, 1, wxLEFT|wxBOTTOM, 3); - outputDataSizer->Add(checkPlotData, 1, wxLEFT|wxTOP, 3); - outputDataSizer->Add(checkVoxelData, 1, wxLEFT|wxTOP|wxBOTTOM, 3); - outputDataSizer->Add(checkRangeData, 1, wxALL, 3); - rangeFileDropDownSizer->Add(labelRangeFormat, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 3); - rangeFileDropDownSizer->Add(comboRangeFormat, 1, wxLEFT|wxRIGHT|wxEXPAND, 3); - outputDataSizer->Add(rangeFileDropDownSizer, 0, wxLEFT|wxBOTTOM|wxEXPAND, 5); - outputDataSizer->Add(20, 20, 2, 0, 0); - frameViewSizer->Add(outputDataSizer, 1, wxEXPAND, 0); - frameViewSizer->Add(static_line_1, 0, wxLEFT|wxRIGHT|wxEXPAND, 5); - frameSliderSizer->Add(labelFrame, 0, wxALIGN_CENTER_VERTICAL, 0); - frameSliderSizer->Add(frameSlider, 1, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); - frameSliderSizer->Add(textFrame, 0, wxALIGN_CENTER_VERTICAL, 0); - propGridSizer->Add(frameSliderSizer, 0, wxALL|wxEXPAND, 3); - propGridSizer->Add(framePropGrid, 1, wxEXPAND, 0); - frameViewSizer->Add(propGridSizer, 2, wxALL|wxEXPAND, 3); - frameViewPane->SetSizer(frameViewSizer); - viewNotebook->AddPage(filterViewPane, wxTRANS("Filter view")); - viewNotebook->AddPage(frameViewPane, wxTRANS("Frame view")); - animateSizer->Add(viewNotebook, 1, wxEXPAND, 0); - globalButtonSizer->Add(20, 1, 1, wxEXPAND, 0); - globalButtonSizer->Add(cancelButton, 0, wxALL|wxALIGN_BOTTOM, 3); - globalButtonSizer->Add(okButton, 0, wxALL|wxALIGN_BOTTOM, 3); - animateSizer->Add(globalButtonSizer, 0, wxEXPAND, 0); - SetSizer(animateSizer); - animateSizer->Fit(this); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/animateFilterDialog.h 3depict-0.0.13/src/dialogs/animateFilterDialog.h --- 3depict-0.0.12/src/dialogs/animateFilterDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateFilterDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,236 +0,0 @@ -/* - * animateFilterDialog - GUI for animate filter - * Copyright (C) 2012, D. Haley, A Ceguerra - - * 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 . - */ - -#ifndef ANIMATEFILTERDIALOG_H -#define ANIMATEFILTERDIALOG_H - -#include -#include -// begin wxGlade: ::dependencies -#include -#include -#include -#include -#include -// end wxGlade - - -#include "animator.h" - - -// begin wxGlade: ::extracode -// end wxGlade - -#include "viscontrol.h" -#include "wxcommon.h" - -enum -{ - FILENAME_IMAGE, - FILENAME_IONS, - FILENAME_RANGE, - FILENAME_PLOT, - FILENAME_VOXEL -}; - -enum -{ - RANGE_OAKRIDGE, - RANGE_AMETEK_RRNG, - RANGE_AMETEK_ENV, - RANGE_FORMATNAME_END -}; - -class ExportAnimationDialog: public wxDialog { -public: - // begin wxGlade: ExportAnimationDialog::ids - // end wxGlade - - ExportAnimationDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - ~ExportAnimationDialog(); - - //!Must be called before displaying dialog, and after setting tree - void prepare(); - - //obtain the desired filename for a particular type of output - std::string getFilename(unsigned int frame, unsigned int nameType, unsigned int number=0) const ; - //Obtain the desired width of the output image - unsigned int getImageWidth() const { return imageWidth;} - //Obtain the desired height of the output image - unsigned int getImageHeight() const { return imageHeight;}; - - //Get the number of frames that are in the animation sequence - size_t getNumFrames() const { return propertyAnimator.getMaxFrame();} - - //Return a modified version f the filter tree, applying the changes requested - // by the user - bool getModifiedTree(size_t frame, FilterTree &t,bool &needUp) const; - - //Set the tree that we are to work with - void setTree(const FilterTree &origTree) { filterTree=&origTree;}; - - //Does the user want to obtain image output? - bool wantsImages() const { return wantImageOutput;} - //Does the user want to obtain plot output? - bool wantsPlots() const { return wantPlotOutput;} - //Does the user want to obtain ion output? - bool wantsIons() const { return wantIonOutput;} - //Does the user want to obtain range output? - bool wantsRanges() const { return wantRangeOutput;} - //Does the user want to obtain range output? - bool wantsVoxels() const { return wantVoxelOutput;} - - //Does the user want all data output, or only when the data - // changes (needs a refresh) - bool wantsOnlyChanges() const { return wantOnlyChanges;} - - //!Obtain the format the user wants to save ranges in - size_t getRangeFormat() const; -private: - //!Tree of filters that can be manipulated - const FilterTree *filterTree; - //!Mapping from ID of filter to the pointer in the filter tree - map filterMap; - - //!Mapping to allow for converting entry of RNG selection combo into - // the correct range enum value - map rangeMap; - //!Default height/width desired for output imgaes - size_t imageWidth,imageHeight; - bool imageSizeOK; - - PropertyAnimator propertyAnimator; - - //!Working directory for outputting data - string workDir; - - string imagePrefix; - //!True if any con - bool existsConflicts; - //!true if the user has selected image output functionality - bool wantImageOutput; - //!True if the user has requetsed ion data out[ut - bool wantIonOutput; - //!True if the user wants plots output - bool wantPlotOutput; - //!True if the user wants to save voxel data - bool wantVoxelOutput; - //!True if the user wants to save range data - bool wantRangeOutput; - //!True if the user only wants to save data if it changes - bool wantOnlyChanges; - - //!Current frame that the user wants to see in the frame view - size_t currentFrame; - - //!Type of rangefile to export - size_t rangeExportMode; - - - //Used to jump out of wx events that are generated by - // the code, rather than the user, eg text events - bool programmaticEvent; - //UI update function - void update(); - - - //Enable/disable the OK button depending upon dialog state - void updateOKButton(); - //update function for filter view page, grid control - void updateFilterViewGrid(); - //update function for frame view page, grid contorl - void updateFrameViewGrid(); - //Updates the slider on the frame view page - void updateFrameViewSlider(); - // begin wxGlade: ExportAnimationDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - -protected: - // begin wxGlade: ExportAnimationDialog::attributes - wxStaticBox* outputDataSizer_staticbox; - wxStaticBox* keyFramesSizer_staticbox; - wxStaticBox* filterPropertySizer_staticbox; - wxTreeCtrl* filterTreeCtrl; - wxPropertyGrid* propertyGrid; - wxPanel* filterLeftPane; - wxGrid* animationGrid; - wxButton* keyFrameRemoveButton; - wxPanel* filterRightPane; - wxSplitterWindow* splitPaneFilter; - wxPanel* filterViewPane; - wxStaticText* labelWorkDir; - wxTextCtrl* textWorkDir; - wxButton* buttonWorkDir; - wxCheckBox* checkOutOnlyChanged; - wxStaticLine* outputDataSepLine; - wxStaticText* labelDataType; - wxCheckBox* checkImageOutput; - wxStaticText* lblImageName; - wxTextCtrl* textImageName; - wxStaticText* labelImageSize; - wxTextCtrl* textImageSize; - wxButton* buttonImageSize; - wxCheckBox* checkPoints; - wxCheckBox* checkPlotData; - wxCheckBox* checkVoxelData; - wxCheckBox* checkRangeData; - wxStaticText* labelRangeFormat; - wxComboBox* comboRangeFormat; - wxStaticLine* static_line_1; - wxStaticText* labelFrame; - wxSlider* frameSlider; - wxTextCtrl* textFrame; - wxGrid* framePropGrid; - wxPanel* frameViewPane; - wxNotebook* viewNotebook; - wxButton* cancelButton; - wxButton* okButton; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnFilterTreeCtrlSelChanged(wxTreeEvent &event); // wxGlade: - virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // wxGlade: - virtual void OnAnimateGridCellEditorShow(wxGridEvent &event); // wxGlade: - virtual void OnFrameGridCellEditorShow(wxGridEvent &event); // wxGlade: - virtual void OnButtonKeyFrameRemove(wxCommandEvent &event); // wxGlade: - virtual void OnOutputDirText(wxCommandEvent &event); // wxGlade: - virtual void OnButtonWorkDir(wxCommandEvent &event); // wxGlade: - virtual void OnCheckOutDataChange(wxCommandEvent &event); // wxGlade: - virtual void OnCheckImageOutput(wxCommandEvent &event); // wxGlade: - virtual void OnImageFilePrefix(wxCommandEvent &event); // wxGlade: - virtual void OnTextImageSize(wxCommandEvent &event); // wxGlade: - virtual void OnBtnResolution(wxCommandEvent &event); // wxGlade: - virtual void OnCheckPointOutput(wxCommandEvent &event); // wxGlade: - virtual void OnCheckPlotOutput(wxCommandEvent &event); // wxGlade: - virtual void OnCheckVoxelOutput(wxCommandEvent &event); // wxGlade: - virtual void OnCheckRangeOutput(wxCommandEvent &event); // wxGlade: - virtual void OnRangeTypeCombo(wxCommandEvent &event); // wxGlade: - virtual void OnFrameViewSlider(wxScrollEvent &event); // wxGlade: - virtual void OnTextFrame(wxCommandEvent &event); // wxGlade: - virtual void OnButtonCancel(wxCommandEvent &event); // wxGlade: - virtual void OnButtonOK(wxCommandEvent &event); // wxGlade: - virtual void OnFilterViewUnsplit(wxSplitterEvent &event); // wxGlade: - -}; // wxGlade: end class - - -#endif // ANIMATEFILTERDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp 3depict-0.0.13/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp --- 3depict-0.0.12/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp 2012-11-18 11:09:09.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Sun Sep 23 22:52:41 2012 - -#include "choiceKeyFrameDialog.h" - -// begin wxGlade: ::extracode - -// end wxGlade - -#include "../../assertion.h" -#include "../../basics.h" -#include "../../wxcommon.h" - - -ChoiceKeyFrameDialog::ChoiceKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE) -{ - // begin wxGlade: ChoiceKeyFrameDialog::ChoiceKeyFrameDialog - labelFrame = new wxStaticText(this, wxID_ANY, wxT("Frame")); - textFrame = new wxTextCtrl(this, ID_TEXT_FRAME, wxEmptyString); - labelSelection = new wxStaticText(this, wxID_ANY, wxT("Selection")); - comboChoice = new wxComboBox(this, ID_COMBO_CHOICE, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxCB_SIMPLE|wxCB_READONLY); - btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - - startFrameOK=false; - - - set_properties(); - do_layout(); - // end wxGlade -} - - -BEGIN_EVENT_TABLE(ChoiceKeyFrameDialog, wxDialog) - // begin wxGlade: ChoiceKeyFrameDialog::event_table - EVT_COMBOBOX(ID_COMBO_CHOICE, ChoiceKeyFrameDialog::OnChoiceCombo) - EVT_TEXT(ID_TEXT_FRAME, ChoiceKeyFrameDialog::OnFrameText) - // end wxGlade -END_EVENT_TABLE(); - - -void ChoiceKeyFrameDialog::OnChoiceCombo(wxCommandEvent &event) -{ - choice=comboChoice->GetSelection(); -} - -void ChoiceKeyFrameDialog::OnFrameText(wxCommandEvent &event) -{ - if(validateTextAsStream(textFrame,startFrame)) - startFrameOK=true; - - updateOKButton(); -} - -// wxGlade: add ChoiceKeyFrameDialog event handlers - -void ChoiceKeyFrameDialog::updateOKButton() -{ - btnOK->Enable(startFrameOK); -} - -void ChoiceKeyFrameDialog::buildCombo(size_t defaultChoice) -{ - ASSERT(choiceStrings.size()); - - - comboChoice->Clear(); - - for(size_t ui=0;uiAppend(wxStr(choiceStrings[ui])); - - comboChoice->SetSelection(defaultChoice); -} - - -void ChoiceKeyFrameDialog::setChoices(const std::vector &choices, - size_t defChoice) -{ - choiceStrings=choices; - - buildCombo(defChoice); - choice=defChoice; -} - -void ChoiceKeyFrameDialog::set_properties() -{ - // begin wxGlade: ChoiceKeyFrameDialog::set_properties - SetTitle(wxT("Key Frame")); - // end wxGlade -} - - -void ChoiceKeyFrameDialog::do_layout() -{ - // begin wxGlade: ChoiceKeyFrameDialog::do_layout - wxBoxSizer* frameSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* textSizer = new wxBoxSizer(wxHORIZONTAL); - textSizer->Add(labelFrame, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 20); - textSizer->Add(textFrame, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 5); - frameSizer->Add(textSizer, 0, wxALL|wxEXPAND, 10); - comboSizer->Add(labelSelection, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); - comboSizer->Add(comboChoice, 0, wxLEFT, 5); - frameSizer->Add(comboSizer, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 10); - buttonSizer->Add(20, 20, 1, 0, 0); - buttonSizer->Add(btnCancel, 0, wxRIGHT, 5); - buttonSizer->Add(btnOK, 0, wxLEFT, 5); - frameSizer->Add(buttonSizer, 0, wxALL|wxEXPAND, 5); - SetSizer(frameSizer); - frameSizer->Fit(this); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.h 3depict-0.0.13/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.h --- 3depict-0.0.12/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.h 2012-11-10 17:31:16.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/choiceKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Sun Sep 23 22:52:41 2012 - -#include -#include -// begin wxGlade: ::dependencies -// end wxGlade - -#include -#include - -#ifndef CHOICEKEYFRAMEDIALOG_H -#define CHOICEKEYFRAMEDIALOG_H - - -// begin wxGlade: ::extracode -enum -{ - ID_TEXT_FRAME, - ID_COMBO_CHOICE -}; -// end wxGlade - - -class ChoiceKeyFrameDialog: public wxDialog { -public: - // begin wxGlade: ChoiceKeyFrameDialog::ids - // end wxGlade - - ChoiceKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - - //Set the choices that are allowed to be selected - void setChoices(const std::vector &choices,size_t defaultChoice=0); - - //Obtain the choice from the user - size_t getChoiceIndex() const { return choice;}; - - std::string getChoice() const { return choiceStrings[choice];}; - - size_t getStartFrame() const { return startFrame;} -private: - // begin wxGlade: ChoiceKeyFrameDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //List of choices that can go into the combo box - std::vector choiceStrings; - - //Drop-down value chosen by user - size_t choice; - - //True if the start frame entered by user is valid - bool startFrameOK; - - //Current start frame - size_t startFrame; - - //enable or disable the OK button based upon validation results - void updateOKButton(); - - //build up the combo box items - void buildCombo(size_t defaultChoice); -protected: - // begin wxGlade: ChoiceKeyFrameDialog::attributes - wxStaticText* labelFrame; - wxTextCtrl* textFrame; - wxStaticText* labelSelection; - wxComboBox* comboChoice; - wxButton* btnCancel; - wxButton* btnOK; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnChoiceCombo(wxCommandEvent &event); // wxGlade: - virtual void OnFrameText(wxCommandEvent &event); // wxGlade: -}; // wxGlade: end class - - -#endif // CHOICEKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 3depict-0.0.13/src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp --- 3depict-0.0.12/src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 2012-11-24 11:21:20.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,267 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Fri Sep 14 09:37:57 2012 - -#include "colourKeyFrameDialog.h" -#include "../../basics.h" -#include "../../wxcommon.h" -#include "../../translation.h" - -#include - -#include - -using std::string; - -// begin wxGlade: ::extracode -enum{ - ID_COMBO_TRANSITION, - ID_BTN_START_VALUE, - ID_BTN_FINAL_VALUE, - ID_TEXT_INITIAL_VALUE, - ID_TEXT_FRAME_START, - ID_TEXT_FRAME_END -}; - -// end wxGlade - -//FIXME: Is currently duplicated from realKeyframeDialog. Needs to be -// unified -enum -{ - TRANSITION_STEP, - TRANSITION_INTERP, - TRANSITION_END -}; - - -ColourKeyFrameDialog::ColourKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX) -{ - // begin wxGlade: ColourKeyFrameDialog::ColourKeyFrameDialog - sizerMainArea_staticbox = new wxStaticBox(this, -1, wxTRANS("Keyframe Data")); - labelTransition = new wxStaticText(this, wxID_ANY, wxTRANS("Transition")); - //FIXME: THis is declared in animator.h - use that def. - const wxString comboTransition_choices[] = { - wxTRANS("Step"), - wxTRANS("Ramp") - }; - comboTransition = new wxComboBox(this, ID_COMBO_TRANSITION, _(""), wxDefaultPosition, wxDefaultSize, 2, comboTransition_choices, wxCB_DROPDOWN|wxCB_READONLY); - labelFrameStart = new wxStaticText(this, wxID_ANY, wxTRANS("Start Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textFrameStart = new wxTextCtrl(this, ID_TEXT_FRAME_START, wxEmptyString); - labelFrameEnd = new wxStaticText(this, wxID_ANY, wxTRANS("End Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textFrameEnd = new wxTextCtrl(this, ID_TEXT_FRAME_END, wxEmptyString); - verticalLine = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); - labelStartVal = new wxStaticText(this, wxID_ANY, wxTRANS("Initial Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - btnStartColour = new wxButton(this, ID_BTN_START_VALUE, wxTRANS("startColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - labelFinalVal = new wxStaticText(this, wxID_ANY, wxTRANS("Final Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - btnEndColour = new wxButton(this, ID_BTN_FINAL_VALUE, wxTRANS("endColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - buttonCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - buttonOK = new wxButton(this, wxID_OK, wxEmptyString); - - comboTransition->SetSelection(1); - transitionMode=TRANSITION_INTERP; - endFrameOK=startFrameOK=false; - startRed=startGreen=startBlue=0; - endRed=endGreen=endBlue=0; - - - updateOKButton(); - updateButtonColours(); - - set_properties(); - do_layout(); - // end wxGlade -} - - -BEGIN_EVENT_TABLE(ColourKeyFrameDialog, wxDialog) - // begin wxGlade: ColourKeyFrameDialog::event_table - EVT_COMBOBOX(ID_COMBO_TRANSITION, ColourKeyFrameDialog::OnComboTransition) - EVT_TEXT(ID_TEXT_FRAME_START, ColourKeyFrameDialog::OnTextStartFrame) - EVT_TEXT(ID_TEXT_FRAME_END, ColourKeyFrameDialog::OnTextEndFrame) - EVT_BUTTON(ID_BTN_START_VALUE, ColourKeyFrameDialog::OnBtnStartColour) - EVT_BUTTON(ID_BTN_FINAL_VALUE, ColourKeyFrameDialog::OnBtnEndColour) - // end wxGlade -END_EVENT_TABLE(); - -std::string ColourKeyFrameDialog::getEndValue() const -{ - ASSERT(transitionMode!=TRANSITION_STEP); - std::string s; - genColString(endRed,endGreen,endBlue,s); - return s; -} - -std::string ColourKeyFrameDialog::getStartValue() const -{ - std::string s; - genColString(startRed,startGreen,startBlue,s); - return s; -} - -void ColourKeyFrameDialog::OnComboTransition(wxCommandEvent &event) -{ - ASSERT(event.GetInt() < TRANSITION_END); - - transitionMode=event.GetInt(); - - btnEndColour->Enable(transitionMode != TRANSITION_STEP); - textFrameEnd->Enable(transitionMode!=TRANSITION_STEP); -} - -void ColourKeyFrameDialog::OnTextStartFrame(wxCommandEvent &event) -{ - startFrameOK=validateTextAsStream(textFrameStart,startFrame); - updateOKButton(); -} - - -void ColourKeyFrameDialog::OnTextEndFrame(wxCommandEvent &event) -{ - endFrameOK=validateTextAsStream(textFrameEnd,endFrame); - updateOKButton(); -} - - -void ColourKeyFrameDialog::OnBtnStartColour(wxCommandEvent &event) -{ - wxColourData d; - wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); - - if( colDg->ShowModal() == wxID_OK) - { - wxColour c; - //Change the colour - c=colDg->GetColourData().GetColour(); - - startRed=c.Red(); - startGreen=c.Green(); - startBlue=c.Blue(); - - updateButtonColours(); - } -} - - -void ColourKeyFrameDialog::OnBtnEndColour(wxCommandEvent &event) -{ - wxColourData d; - wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); - - if( colDg->ShowModal() == wxID_OK) - { - wxColour c; - //Change the colour - c=colDg->GetColourData().GetColour(); - - endRed=c.Red(); - endGreen=c.Green(); - endBlue=c.Blue(); - - updateButtonColours(); - } - - colDg->Destroy(); -} - -void ColourKeyFrameDialog::updateOKButton() -{ - bool isOK=true; - isOK&=startFrameOK; - isOK&=endFrameOK; - - //Ensure start frame is > end frame - if(isOK) - { - isOK&=(startFrameSetBackgroundColour(*wxCYAN); - textFrameEnd->SetBackgroundColour(*wxCYAN); - } - else - { - textFrameStart->SetBackgroundColour(wxNullColour); - textFrameEnd->SetBackgroundColour(wxNullColour); - } - } - - buttonOK->Enable(isOK); -} - -void ColourKeyFrameDialog::updateButtonColours() -{ - wxColour colD; - colD.Set(startRed,startGreen,startBlue); - btnStartColour->SetForegroundColour(colD); - - colD.Set(endRed,endGreen,endBlue); - btnEndColour->SetForegroundColour(colD); - -} -// wxGlade: add ColourKeyFrameDialog event handlers - - -void ColourKeyFrameDialog::set_properties() -{ - // begin wxGlade: ColourKeyFrameDialog::set_properties - SetTitle(wxTRANS("Key Frame : Colour")); - comboTransition->SetSelection(-1); - btnStartColour->SetToolTip(wxTRANS("Colour at the start of the transtition")); - btnEndColour->SetToolTip(wxTRANS("Colour at end of transition")); - // end wxGlade -} - - -void ColourKeyFrameDialog::do_layout() -{ - // begin wxGlade: ColourKeyFrameDialog::do_layout - wxBoxSizer* sizerTop = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerBUttons = new wxBoxSizer(wxHORIZONTAL); - wxStaticBoxSizer* sizerMainArea = new wxStaticBoxSizer(sizerMainArea_staticbox, wxHORIZONTAL); - wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerRightFinal = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerRightInitial = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerEndFrame = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerStartFrame = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerTransition = new wxBoxSizer(wxHORIZONTAL); - sizerTop->Add(20, 5, 0, 0, 0); - sizerMainArea->Add(10, 20, 0, 0, 0); - sizerLeft->Add(20, 10, 0, 0, 0); - sizerTransition->Add(labelTransition, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 14); - sizerTransition->Add(comboTransition, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 5); - sizerLeft->Add(sizerTransition, 1, wxEXPAND, 0); - sizerStartFrame->Add(labelFrameStart, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); - sizerStartFrame->Add(textFrameStart, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); - sizerLeft->Add(sizerStartFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerEndFrame->Add(labelFrameEnd, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 12); - sizerEndFrame->Add(textFrameEnd, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); - sizerLeft->Add(sizerEndFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerLeft->Add(20, 10, 0, 0, 0); - sizerMainArea->Add(sizerLeft, 2, wxEXPAND, 0); - sizerMainArea->Add(verticalLine, 0, wxLEFT|wxRIGHT|wxEXPAND, 5); - sizerRight->Add(20, 20, 1, 0, 0); - sizerRightInitial->Add(20, 20, 1, 0, 0); - sizerRightInitial->Add(labelStartVal, 2, wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); - sizerRightInitial->Add(btnStartColour, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3); - sizerRightInitial->Add(20, 20, 1, 0, 0); - sizerRight->Add(sizerRightInitial, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerRightFinal->Add(20, 20, 1, 0, 0); - sizerRightFinal->Add(labelFinalVal, 2, wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 9); - sizerRightFinal->Add(btnEndColour, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3); - sizerRightFinal->Add(20, 20, 1, 0, 0); - sizerRight->Add(sizerRightFinal, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerRight->Add(20, 20, 1, 0, 0); - sizerMainArea->Add(sizerRight, 2, wxEXPAND, 0); - sizerMainArea->Add(10, 20, 0, 0, 0); - sizerTop->Add(sizerMainArea, 1, wxEXPAND, 0); - sizerBUttons->Add(20, 20, 1, 0, 0); - sizerBUttons->Add(buttonCancel, 0, wxALL, 4); - sizerBUttons->Add(buttonOK, 0, wxALL, 4); - sizerTop->Add(sizerBUttons, 0, wxEXPAND, 0); - SetSizer(sizerTop); - sizerTop->Fit(this); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/colourKeyFrameDialog.h 3depict-0.0.13/src/dialogs/animateSubDialogs/colourKeyFrameDialog.h --- 3depict-0.0.12/src/dialogs/animateSubDialogs/colourKeyFrameDialog.h 2012-11-10 17:31:16.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/colourKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Fri Sep 14 09:37:57 2012 - -#include -#include -// begin wxGlade: ::dependencies -#include - -// end wxGlade - -#include "../../assertion.h" - -#ifndef COLOURKEYFRAMEDIALOG_H -#define COLOURKEYFRAMEDIALOG_H - - -// begin wxGlade: ::extracode -// end wxGlade - - -class ColourKeyFrameDialog: public wxDialog { -public: - // begin wxGlade: ColourKeyFrameDialog::ids - // end wxGlade - - ColourKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - - size_t getTransitionMode() const { return transitionMode;}; - - //Get the staring colour as a hex string - std::string getStartValue() const; - //Get the ending colour as a hex string - std::string getEndValue() const; - - size_t getStartFrame() const { ASSERT(startFrameOK); return startFrame;}; - - size_t getEndFrame() const { ASSERT(endFrameOK); return endFrame;}; -private: - // begin wxGlade: ColourKeyFrameDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //Starting gred, green and blue values for transition - unsigned char startRed,startGreen, startBlue; - unsigned char endRed,endGreen, endBlue; - size_t startFrame,endFrame; - size_t transitionMode; - - bool startFrameOK,endFrameOK; - - //!Update the OK button's enabled/disabled state - // based upon text field validity - void updateOKButton(); - //!Update the colour chooser buttons appearance - void updateButtonColours(); - -protected: - // begin wxGlade: ColourKeyFrameDialog::attributes - wxStaticBox* sizerMainArea_staticbox; - wxStaticText* labelTransition; - wxComboBox* comboTransition; - wxStaticText* labelFrameStart; - wxTextCtrl* textFrameStart; - wxStaticText* labelFrameEnd; - wxTextCtrl* textFrameEnd; - wxStaticLine* verticalLine; - wxStaticText* labelStartVal; - wxButton* btnStartColour; - wxStaticText* labelFinalVal; - wxButton* btnEndColour; - wxButton* buttonCancel; - wxButton* buttonOK; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnComboTransition(wxCommandEvent &event); // wxGlade: - virtual void OnTextStartFrame(wxCommandEvent &event); // wxGlade: - virtual void OnTextEndFrame(wxCommandEvent &event); // wxGlade: - virtual void OnBtnStartColour(wxCommandEvent &event); // wxGlade: - virtual void OnBtnEndColour(wxCommandEvent &event); // wxGlade: -}; // wxGlade: end class - - -#endif // COLOURKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/realKeyFrameDialog.h 3depict-0.0.13/src/dialogs/animateSubDialogs/realKeyFrameDialog.h --- 3depict-0.0.12/src/dialogs/animateSubDialogs/realKeyFrameDialog.h 2012-11-20 22:42:04.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/realKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,328 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Tue Aug 28 22:07:07 2012 -#ifndef REALKEYFRAMEDIALOG_H -#define REALKEYFRAMEDIALOG_H - -#include -#include -// begin wxGlade: ::dependencies -#include -// end wxGlade - -#include "../../basics.h" -#include "../../wxcommon.h" - -enum -{ - TRANSITION_STEP, - TRANSITION_INTERP, - TRANSITION_END -}; - - -// begin wxGlade: ::extracode -enum -{ - ID_COMBO_TRANSITION, - ID_TEXT_FRAME_START, - ID_TEXT_FRAME_END, - ID_TEXT_FINAL_VALUE, - ID_TEXT_INITIAL_VALUE, -}; -// end wxGlade - -template -class RealKeyFrameDialog: public wxDialog -{ -public: - // begin wxGlade: RealKeyFrameDialog::ids - // end wxGlade - - RealKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - - //!Return the keyframe transition style selected by user - size_t getTransitionMode() const { return transitionMode;} - - //!Return the initial frame from user - size_t getEndFrame() const { return endFrame;} - //!Return the start frame, as was given by user - size_t getStartFrame() const { return startFrame;} - - //!Return the initial value, as given by user - T getEndValue() const { return endValue;} - //!Return the start value, as was given by user - T getStartValue() const { return startValue;} -private: - size_t transitionMode; - size_t startFrame, endFrame; - T startValue, endValue; - - bool startFrameOK,endFrameOK; - bool startValueOK,endValueOK; - - void updateOKButton(); - - // begin wxGlade: RealKeyFrameDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - -protected: - // begin wxGlade: RealKeyFrameDialog::attributes - wxStaticBox* sizerMainArea_staticbox; - wxStaticText* labelTransition; - wxComboBox* comboTransition; - wxStaticText* labelFrameStart; - wxTextCtrl* textFrameStart; - wxStaticText* labelFrameEnd; - wxTextCtrl* textFrameEnd; - wxStaticLine* verticalLine; - wxStaticText* labelStartVal; - wxTextCtrl* textStartVal; - wxStaticText* labelEndVal; - wxTextCtrl* textEndVal; - wxButton* buttonCancel; - wxButton* buttonOK; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnComboTransition(wxCommandEvent &event); // wxGlade: - virtual void OnTextStartFrame(wxCommandEvent &event); // wxGlade: - virtual void OnTextEndFrame(wxCommandEvent &event); // wxGlade: - virtual void OnTextStartValue(wxCommandEvent &event); // wxGlade: - virtual void OnTextEndValue(wxCommandEvent &event); // wxGlade: -}; // wxGlade: end class - -using std::string; - -bool validatePoint3D(wxTextCtrl *t, Point3D &i) -{ - bool isOK; - std::string s; - s= stlStr(t->GetValue()); - - //string cannot be empty - bool condition; - condition = s.empty() || !parsePointStr(s,i); - - if(condition) - { - //OK, so bad things happened. Prevent the user from doing this - isOK=false; - - //if it is bad and non-empty, highlight it as such - // if it is empty, then just set it to normal colour - if(s.empty()) - t->SetBackgroundColour(wxNullColour); - else - t->SetBackgroundColour(*wxCYAN); - } - else - { - t->SetBackgroundColour(wxNullColour); - isOK=true; - } - - - return isOK; -} - -template -RealKeyFrameDialog::RealKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX) -{ - // begin wxGlade: RealKeyFrameDialog::RealKeyFrameDialog - sizerMainArea_staticbox = new wxStaticBox(this, -1, wxT("Keyframe Data")); - labelTransition = new wxStaticText(this, wxID_ANY, wxT("Transition")); - //FIXME: This is declared in animator.h, use it! - const wxString comboTransition_choices[] = { - wxT("Step"), - wxT("Ramp") - }; - comboTransition = new wxComboBox(this, ID_COMBO_TRANSITION, wxT(""), wxDefaultPosition, wxDefaultSize, 2, comboTransition_choices, wxCB_DROPDOWN|wxCB_READONLY); - labelFrameStart = new wxStaticText(this, wxID_ANY, wxT("Start Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textFrameStart = new wxTextCtrl(this, ID_TEXT_FRAME_START, wxEmptyString); - labelFrameEnd = new wxStaticText(this, wxID_ANY, wxT("End Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textFrameEnd = new wxTextCtrl(this, ID_TEXT_FRAME_END, wxEmptyString); - verticalLine = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); - labelStartVal = new wxStaticText(this, wxID_ANY, wxT("Start Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textStartVal = new wxTextCtrl(this, ID_TEXT_INITIAL_VALUE, wxEmptyString); - labelEndVal = new wxStaticText(this, wxID_ANY, wxT("End Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textEndVal = new wxTextCtrl(this, ID_TEXT_FINAL_VALUE, wxEmptyString); - buttonCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - buttonOK = new wxButton(this, wxID_OK, wxEmptyString); - - startFrameOK=endFrameOK=startValueOK=endValueOK=false; - - const int DEFAULT_TRANSITION=TRANSITION_INTERP; - comboTransition->SetSelection(DEFAULT_TRANSITION); - transitionMode=DEFAULT_TRANSITION; - - set_properties(); - do_layout(); - // end wxGlade -} - - - -BEGIN_EVENT_TABLE_TEMPLATE1(RealKeyFrameDialog, wxDialog,T) - // begin wxGlade: RealKeyFrameDialog::event_table - EVT_COMBOBOX(ID_COMBO_TRANSITION, RealKeyFrameDialog::OnComboTransition) - EVT_TEXT(ID_TEXT_FRAME_START, RealKeyFrameDialog::OnTextStartFrame) - EVT_TEXT(ID_TEXT_FRAME_END, RealKeyFrameDialog::OnTextEndFrame) - EVT_TEXT(ID_TEXT_INITIAL_VALUE, RealKeyFrameDialog::OnTextStartValue) - EVT_TEXT(ID_TEXT_FINAL_VALUE, RealKeyFrameDialog::OnTextEndValue) - // end wxGlade -END_EVENT_TABLE(); - -template -void RealKeyFrameDialog::updateOKButton() -{ - bool isOK=true; - isOK&=startFrameOK; - //step transitions need to be handled without end frmae - isOK&=endFrameOK || transitionMode==TRANSITION_STEP; - - //Ensure start frame is > end frame - if(isOK && transitionMode != TRANSITION_STEP) - { - isOK&=(startFrameSetBackgroundColour(*wxCYAN); - textFrameEnd->SetBackgroundColour(*wxCYAN); - } - else - { - textFrameStart->SetBackgroundColour(wxNullColour); - textFrameEnd->SetBackgroundColour(wxNullColour); - } - } - - isOK&=startValueOK; - isOK&=endValueOK || transitionMode==TRANSITION_STEP; - - buttonOK->Enable(isOK); -} - -template -void RealKeyFrameDialog::OnComboTransition(wxCommandEvent &event) -{ - ASSERT(event.GetInt() < TRANSITION_END); - - transitionMode=event.GetInt(); - - textEndVal->Enable(transitionMode != TRANSITION_STEP); - textFrameEnd->Enable(transitionMode!=TRANSITION_STEP); -} - - -template -void RealKeyFrameDialog::OnTextStartFrame(wxCommandEvent &event) -{ - startFrameOK=validateTextAsStream(textFrameStart,startFrame); - updateOKButton(); -} - -template -void RealKeyFrameDialog::OnTextEndFrame(wxCommandEvent &event) -{ - endFrameOK=validateTextAsStream(textFrameEnd,endFrame); - updateOKButton(); -} - -template -void RealKeyFrameDialog::OnTextStartValue(wxCommandEvent &event) -{ - startValueOK=validateTextAsStream(textStartVal,startValue); - updateOKButton(); -} - -template<> -void RealKeyFrameDialog::OnTextStartValue(wxCommandEvent &evt) -{ - startValueOK=validatePoint3D(textStartVal,startValue); - updateOKButton(); -} - - -template -void RealKeyFrameDialog::OnTextEndValue(wxCommandEvent &event) -{ - endValueOK=validateTextAsStream(textEndVal,endValue); - updateOKButton(); -} - -template<> -void RealKeyFrameDialog::OnTextEndValue(wxCommandEvent &evt) -{ - endValueOK=validatePoint3D(textEndVal,endValue); - updateOKButton(); -} - -// wxGlade: add RealKeyFrameDialog event handlers - - -template -void RealKeyFrameDialog::set_properties() -{ - // begin wxGlade: RealKeyFrameDialog::set_properties - comboTransition->SetSelection(-1); - // end wxGlade -} - - -template -void RealKeyFrameDialog::do_layout() -{ - // begin wxGlade: RealKeyFrameDialog::do_layout - wxBoxSizer* sizerTop = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerBUttons = new wxBoxSizer(wxHORIZONTAL); - wxStaticBoxSizer* sizerMainArea = new wxStaticBoxSizer(sizerMainArea_staticbox, wxHORIZONTAL); - wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerRightEnd = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerRightStart = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerEndFrame = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerStartFrame = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerTransition = new wxBoxSizer(wxHORIZONTAL); - sizerTop->Add(20, 5, 0, 0, 0); - sizerMainArea->Add(10, 20, 0, 0, 0); - sizerLeft->Add(20, 10, 0, 0, 0); - sizerTransition->Add(labelTransition, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 14); - sizerTransition->Add(comboTransition, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 5); - sizerLeft->Add(sizerTransition, 1, wxEXPAND, 0); - sizerStartFrame->Add(labelFrameStart, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); - sizerStartFrame->Add(textFrameStart, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); - sizerLeft->Add(sizerStartFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerEndFrame->Add(labelFrameEnd, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 12); - sizerEndFrame->Add(textFrameEnd, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); - sizerLeft->Add(sizerEndFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerLeft->Add(20, 10, 0, 0, 0); - sizerMainArea->Add(sizerLeft, 1, wxEXPAND, 0); - sizerMainArea->Add(verticalLine, 0, wxLEFT|wxRIGHT|wxEXPAND, 5); - sizerRight->Add(20, 20, 1, 0, 0); - sizerRightStart->Add(labelStartVal, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); - sizerRightStart->Add(textStartVal, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); - sizerRight->Add(sizerRightStart, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerRightEnd->Add(labelEndVal, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 9); - sizerRightEnd->Add(textEndVal, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); - sizerRight->Add(sizerRightEnd, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizerRight->Add(20, 20, 1, 0, 0); - sizerMainArea->Add(sizerRight, 1, wxEXPAND, 0); - sizerMainArea->Add(10, 20, 0, 0, 0); - sizerTop->Add(sizerMainArea, 1, wxEXPAND, 0); - sizerBUttons->Add(20, 20, 1, 0, 0); - sizerBUttons->Add(buttonCancel, 0, wxALL, 4); - sizerBUttons->Add(buttonOK, 0, wxALL, 4); - sizerTop->Add(sizerBUttons, 0, wxEXPAND, 0); - SetSizer(sizerTop); - sizerTop->Fit(this); - Layout(); - // end wxGlade -} - - - -#endif // REALKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp 3depict-0.0.13/src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp --- 3depict-0.0.12/src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp 2012-11-18 12:03:59.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,370 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Sat Sep 22 21:13:08 2012 - -#include "stringKeyFrameDialog.h" - -#include "../../translation.h" -#include "../../basics.h" -#include "../../wxcommon.h" - -using std::string; -using std::vector; - -// begin wxGlade: ::extracode -enum -{ - ID_TEXT_START_FRAME, - ID_RADIO_FROM_FILE, - ID_TEXT_FROM_FILE, - ID_RADIO_FROM_TABLE, - ID_GRID_STRINGS -}; -// end wxGlade - - -StringKeyFrameDialog::StringKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) -{ - // begin wxGlade: StringKeyFrameDialog::StringKeyFrameDialog - labelStartFrame = new wxStaticText(this, wxID_ANY, wxTRANS("Start Frame: ")); - textStartFrame = new wxTextCtrl(this, ID_TEXT_START_FRAME, wxEmptyString); - radioFromFile = new wxRadioButton(this, ID_RADIO_FROM_FILE, wxTRANS("From File")); - textFilename = new wxTextCtrl(this, ID_TEXT_FROM_FILE, wxEmptyString); - btnChooseFile = new wxButton(this, wxID_OPEN, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - radioFromTable = new wxRadioButton(this, ID_RADIO_FROM_TABLE, wxTRANS("From Table")); - gridStrings = new wxGrid(this, ID_GRID_STRINGS); - btnStringAdd = new wxButton(this, wxID_ADD, wxEmptyString); - btnRemove = new wxButton(this, wxID_REMOVE, wxEmptyString); - btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - - - - set_properties(); - do_layout(); - // end wxGlade - startFrame=0; - startFrameOK=filenameOK=false; - string s; - stream_cast(s,startFrame); - textStartFrame->SetValue(wxStr(s)); - - radioFromFile->SetValue(true); - - dataSourceFromFile=radioFromFile->GetValue(); -} - - -BEGIN_EVENT_TABLE(StringKeyFrameDialog, wxDialog) - // begin wxGlade: StringKeyFrameDialog::event_table - EVT_TEXT(ID_TEXT_START_FRAME, StringKeyFrameDialog::OnTextStart) - EVT_RADIOBUTTON(ID_RADIO_FROM_FILE, StringKeyFrameDialog::OnFileRadio) - EVT_TEXT(ID_TEXT_FROM_FILE, StringKeyFrameDialog::OnTextFilename) - EVT_BUTTON(wxID_OPEN, StringKeyFrameDialog::OnBtnChooseFile) - EVT_RADIOBUTTON(ID_RADIO_FROM_TABLE, StringKeyFrameDialog::OnTableRadio) - EVT_GRID_CMD_CELL_CHANGE(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridCellChange) - EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridEditorShown) - EVT_BUTTON(wxID_ADD, StringKeyFrameDialog::OnBtnAdd) - EVT_BUTTON(wxID_REMOVE, StringKeyFrameDialog::OnBtnRemove) - // end wxGlade -END_EVENT_TABLE(); - -void StringKeyFrameDialog::buildGrid() -{ - gridStrings->BeginBatch(); - //Empty the grid - if(gridStrings->GetNumberCols()) - gridStrings->DeleteCols(0,gridStrings->GetNumberCols()); - if(gridStrings->GetNumberRows()) - gridStrings->DeleteRows(0,gridStrings->GetNumberRows()); - - gridStrings->AppendCols(2); - gridStrings->SetColLabelValue(0,wxTRANS("Frame")); - gridStrings->SetColLabelValue(1,wxTRANS("Value")); - - gridStrings->AppendRows(valueStrings.size()); - - wxGridCellAttr *readOnlyColAttr=new wxGridCellAttr; - readOnlyColAttr->SetReadOnly(true); - gridStrings->SetColAttr(0,readOnlyColAttr); - - for(size_t ui=0;uiSetCellValue(ui,0,wxStr(pos)); - gridStrings->SetCellValue(ui,1,wxStr(valueStrings[ui])); - } - gridStrings->EndBatch(); -} - -bool StringKeyFrameDialog::getStrings(vector &res) const -{ - if(dataSourceFromFile) - { - vector > dataVec; - if(loadTextStringData(dataFilename.c_str(), dataVec,"\t")) - return false; - - res.reserve(dataVec.size()); - for(size_t ui=0;uiGetValue(); - if(dataSourceFromFile) - { - //Disable grid & enable text box - gridStrings->Enable(false); - textFilename->Enable(true); - btnChooseFile->Enable(true); - } - else - { - //Enable grid & disable text box - gridStrings->Enable(true); - textFilename->Enable(false); - btnChooseFile->Enable(false); - } -} - -void StringKeyFrameDialog::OnTableRadio(wxCommandEvent &event) -{ - dataSourceFromFile=!radioFromTable->GetValue(); - if(dataSourceFromFile) - { - //Disable grid & enable text box - gridStrings->Enable(false); - textFilename->Enable(true); - btnChooseFile->Enable(true); - } - else - { - //Enable grid & disable text box - gridStrings->Enable(true); - textFilename->Enable(false); - btnChooseFile->Enable(false); - } -} -void StringKeyFrameDialog::OnTextFilename(wxCommandEvent &event) -{ - if(!wxFileExists(textFilename->GetValue())) - { - textFilename->SetBackgroundColour(*wxCYAN); - filenameOK=false; - dataFilename.clear(); - } - else - { - textFilename->SetBackgroundColour(wxNullColour); - filenameOK=true; - dataFilename=stlStr(textFilename->GetValue()); - } - - updateOKButton(); -} - -void StringKeyFrameDialog::updateOKButton() -{ - bool isOK=true; - isOK&=startFrameOK; - - if(dataSourceFromFile) - isOK&=filenameOK; - else - isOK&=(bool)(valueStrings.size()); - - btnOK->Enable(isOK); -} - -void StringKeyFrameDialog::OnGridCellChange(wxGridEvent &event) -{ - std::string s; - s=stlStr(gridStrings->GetCellValue(event.GetRow(),event.GetCol())); - valueStrings[event.GetRow()] = s; -} - -void StringKeyFrameDialog::OnGridEditorShown(wxGridEvent &event) -{ - event.Skip(); - wxLogDebug(wxT("Event handler (StringKeyFrameDialog::OnGridEditorShown) not implemented yet")); //notify the user that he hasn't implemented the event handler yet -} - -void StringKeyFrameDialog::OnBtnChooseFile(wxCommandEvent &event) -{ - //Pop up a directory dialog, to choose the base path for the new folder - wxFileDialog *wxD = new wxFileDialog(this,wxTRANS("Select text file..."), wxT(""), - wxT(""),wxTRANS("Text files (*.txt)|*.txt;|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST); - - unsigned int res; - res = wxD->ShowModal(); - - while(res != wxID_CANCEL) - { - //If dir exists, exit - if(wxFileExists(wxD->GetPath())) - break; - - res=wxD->ShowModal(); - } - - //User aborted directory choice. - if(res==wxID_CANCEL) - { - wxD->Destroy(); - return; - } - - textFilename->SetValue(wxD->GetPath()); - wxD->Destroy(); -} - - -void StringKeyFrameDialog::OnBtnAdd(wxCommandEvent &event) -{ - wxMouseState wxm = wxGetMouseState(); - if(wxm.ShiftDown()) - valueStrings.resize(valueStrings.size() + 5,""); - else if (wxm.CmdDown()) - valueStrings.resize(valueStrings.size() + 10,""); - else - valueStrings.push_back(""); - buildGrid(); - updateOKButton(); -} - -void StringKeyFrameDialog::OnBtnRemove(wxCommandEvent &event) -{ - if(!gridStrings->GetNumberRows()) - return; - // Whole selected rows. - const wxArrayInt& rows(gridStrings->GetSelectedRows()); - for (size_t i = rows.size(); i--; ) - { - valueStrings.erase(valueStrings.begin() + rows[i], - valueStrings.begin()+rows[i]+1); - } - - - if(!rows.size()) - { - - //Obtain the IDs of the selected rows, or partially selected rows - wxGridCellCoordsArray selectedRows = gridStrings->GetSelectedCells(); - - wxGridCellCoordsArray arrayTL(gridStrings->GetSelectionBlockTopLeft()); - wxGridCellCoordsArray arrayBR(gridStrings->GetSelectionBlockBottomRight()); - - //This is an undocumented class AFAIK. :( - if(arrayTL.Count() && arrayBR.Count()) - { - //Grab the coordinates f the selection block, - // top left (TL) and bottom right (BR) - wxGridCellCoords coordTL = arrayTL.Item(0); - wxGridCellCoords coordBR = arrayBR.Item(0); - - size_t rows = coordBR.GetRow() - coordTL.GetRow()+1; - - ASSERT(coordTL.GetRow()+rows-1GetGridCursorRow(); - ASSERT(rowToKillSetToolTip(wxTRANS("Frame offset for data start")); - textFilename->SetToolTip(wxTRANS("File to use as string data source, one value per row")); - btnChooseFile->SetToolTip(wxTRANS("Select file to use as data source")); - radioFromTable->SetToolTip(wxTRANS("Use table below for data source")); - gridStrings->CreateGrid(0, 2); - gridStrings->SetColLabelValue(0, wxTRANS("Frame")); - gridStrings->SetColSize(0, 1); - gridStrings->SetColLabelValue(1, wxTRANS("Value")); - gridStrings->SetColSize(1, 3); - btnStringAdd->SetToolTip(wxTRANS("Add new data rows to table, hold shift/cmd to insert multiple rows")); - btnRemove->SetToolTip(wxTRANS("Remove selected strings from table")); - btnCancel->SetToolTip(wxTRANS("Abort value selection and return to previous window")); - btnOK->SetToolTip(wxTRANS("Accept data values")); - // end wxGlade -} - - -void StringKeyFrameDialog::do_layout() -{ - // begin wxGlade: StringKeyFrameDialog::do_layout - wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* footerSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* gridAreaSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* gridButtonSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* fromFileSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* startFrameSizer = new wxBoxSizer(wxHORIZONTAL); - startFrameSizer->Add(labelStartFrame, 0, wxALIGN_CENTER_VERTICAL, 0); - startFrameSizer->Add(textStartFrame, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 6); - startFrameSizer->Add(20, 20, 1, 0, 0); - mainSizer->Add(startFrameSizer, 0, wxALL|wxEXPAND, 6); - fromFileSizer->Add(radioFromFile, 0, wxALIGN_CENTER_VERTICAL, 0); - fromFileSizer->Add(textFilename, 1, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 6); - fromFileSizer->Add(btnChooseFile, 0, wxLEFT|wxRIGHT, 6); - mainSizer->Add(fromFileSizer, 0, wxALL|wxEXPAND, 6); - mainSizer->Add(radioFromTable, 0, wxLEFT, 6); - gridAreaSizer->Add(gridStrings, 1, wxALL|wxEXPAND, 5); - gridButtonSizer->Add(btnStringAdd, 0, wxBOTTOM, 5); - gridButtonSizer->Add(btnRemove, 0, 0, 0); - gridAreaSizer->Add(gridButtonSizer, 0, wxRIGHT|wxEXPAND, 5); - mainSizer->Add(gridAreaSizer, 1, wxEXPAND, 0); - footerSizer->Add(20, 20, 1, 0, 0); - footerSizer->Add(btnCancel, 0, wxALL, 5); - footerSizer->Add(btnOK, 0, wxALL, 5); - mainSizer->Add(footerSizer, 0, wxEXPAND, 0); - SetSizer(mainSizer); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/animateSubDialogs/stringKeyFrameDialog.h 3depict-0.0.13/src/dialogs/animateSubDialogs/stringKeyFrameDialog.h --- 3depict-0.0.12/src/dialogs/animateSubDialogs/stringKeyFrameDialog.h 2012-11-10 17:31:16.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/animateSubDialogs/stringKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Sat Sep 22 21:13:08 2012 - -#include -// begin wxGlade: ::dependencies -#include -// end wxGlade - -#include -#include - -#include "../../assertion.h" - -#ifndef STRINGKEYFRAMEDIALOG_H -#define STRINGKEYFRAMEDIALOG_H - - -class StringKeyFrameDialog: public wxDialog { -public: - // begin wxGlade: StringKeyFrameDialog::ids - // end wxGlade - - StringKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - - //!Data - size_t getStartFrame() const { ASSERT(startFrameOK); return startFrame;}; - - bool getStrings(std::vector &res) const; - -private: - // begin wxGlade: StringKeyFrameDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //!Should we be using a file as the string data source? - bool dataSourceFromFile; - - //!File to use as the data source - std::string dataFilename; - - //!Initial frame to use for value strings - size_t startFrame; - - //strings that are to be used as the data for each frame - std::vector valueStrings; - - //!Check to see if the various data elements are OK - bool startFrameOK, filenameOK,gridOK; - - //Enable/disable OK button, checking dialog content validity - void updateOKButton(); - - //Build the grid UI from the internal string value data - void buildGrid(); - -protected: - // begin wxGlade: StringKeyFrameDialog::attributes - wxStaticText* labelStartFrame; - wxTextCtrl* textStartFrame; - wxRadioButton* radioFromFile; - wxTextCtrl* textFilename; - wxButton* btnChooseFile; - wxRadioButton* radioFromTable; - wxGrid* gridStrings; - wxButton* btnStringAdd; - wxButton* btnRemove; - wxButton* btnCancel; - wxButton* btnOK; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnTextStart(wxCommandEvent &event); // wxGlade: - virtual void OnFileRadio(wxCommandEvent &event); // wxGlade: - virtual void OnTextFilename(wxCommandEvent &event); // wxGlade: - virtual void OnBtnChooseFile(wxCommandEvent &event); // wxGlade: - virtual void OnTableRadio(wxCommandEvent &event); // wxGlade: - virtual void OnGridCellChange(wxGridEvent &event); // wxGlade: - virtual void OnGridEditorShown(wxGridEvent &event); // wxGlade: - virtual void OnBtnAdd(wxCommandEvent &event); // wxGlade: - virtual void OnBtnRemove(wxCommandEvent &event); // wxGlade: -}; // wxGlade: end class - - -#endif // STRINGKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/autosaveDialog.cpp 3depict-0.0.13/src/dialogs/autosaveDialog.cpp --- 3depict-0.0.12/src/dialogs/autosaveDialog.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/autosaveDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Thu Jun 7 12:47:44 2012 - -#include "autosaveDialog.h" -#include "../wxcommon.h" -#include "../translation.h" -// begin wxGlade: ::extracode - -// end wxGlade - - - -AutosaveDialog::AutosaveDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) -{ - - selectedItem=(size_t)-1; - haveRemovedItems=false; - - // begin wxGlade: AutosaveDialog::AutosaveDialog - const wxString *listStates_choices = NULL; - listStates = new wxListBox(this, ID_LIST_STATES, wxDefaultPosition, wxDefaultSize, 0, listStates_choices, wxLB_SINGLE|wxLB_NEEDED_SB); - btnRemoveAll = new wxButton(this, ID_REMOVE_ALL, wxTRANS("Remove &All")); - btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - - set_properties(); - do_layout(); - // end wxGlade -} - - -BEGIN_EVENT_TABLE(AutosaveDialog, wxDialog) - // begin wxGlade: AutosaveDialog::event_table - EVT_LISTBOX_DCLICK(ID_LIST_STATES, AutosaveDialog::OnListStatesDClick) - EVT_LISTBOX(ID_LIST_STATES, AutosaveDialog::OnListStates) - EVT_BUTTON(ID_REMOVE_ALL, AutosaveDialog::OnRemoveAll) - EVT_BUTTON(wxID_CANCEL, AutosaveDialog::OnCancel) - EVT_BUTTON(wxID_OK, AutosaveDialog::OnOK) - // end wxGlade -END_EVENT_TABLE(); - -void AutosaveDialog::OnListStates(wxCommandEvent &event) -{ - //Get the first selected item - selectedItem= listStates->GetSelection(); -} - -void AutosaveDialog::OnListStatesDClick(wxCommandEvent &event) -{ - EndModal(wxID_OK); -} - - -void AutosaveDialog::OnRemoveAll(wxCommandEvent &event) -{ - haveRemovedItems=true; - btnRemoveAll->Enable(false); - listStates->Clear(); - listStates->Enable(false); -} - - -void AutosaveDialog::OnCancel(wxCommandEvent &event) -{ - EndModal(wxID_CANCEL); -} - - -void AutosaveDialog::OnOK(wxCommandEvent &event) -{ - EndModal(wxID_OK); -} - - -// wxGlade: add AutosaveDialog event handlers - -void AutosaveDialog::setItems( const std::vector &newItems) -{ - for(size_t ui=0;uiInsert(wxStr(newItems[ui]),ui); -} - -void AutosaveDialog::set_properties() -{ - // begin wxGlade: AutosaveDialog::set_properties - SetTitle(wxTRANS("Restore state?")); - // end wxGlade -} - - -void AutosaveDialog::do_layout() -{ - // begin wxGlade: AutosaveDialog::do_layout - wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL); - wxStaticText* labelHeader = new wxStaticText(this, wxID_ANY, wxTRANS("Multiple autosave states were found; would you like to restore one?"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - sizer_1->Add(labelHeader, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 8); - sizer_1->Add(listStates, 1, wxALL|wxEXPAND, 8); - sizer_2->Add(btnRemoveAll, 0, wxLEFT|wxBOTTOM, 8); - sizer_2->Add(20, 20, 1, 0, 0); - sizer_2->Add(btnCancel, 0, wxLEFT|wxRIGHT|wxBOTTOM, 8); - sizer_2->Add(btnOK, 0, wxRIGHT|wxBOTTOM, 8); - sizer_1->Add(sizer_2, 0, wxEXPAND, 0); - SetSizer(sizer_1); - sizer_1->Fit(this); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/autosaveDialog.h 3depict-0.0.13/src/dialogs/autosaveDialog.h --- 3depict-0.0.12/src/dialogs/autosaveDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/autosaveDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.5 on Thu Jun 7 12:47:44 2012 - -#include -#include -// begin wxGlade: ::dependencies -// end wxGlade - - -#ifndef AUTOSAVEDIALOG_H -#define AUTOSAVEDIALOG_H -#include -#include -#include - -// begin wxGlade: ::extracode -enum -{ - ID_LIST_STATES = wxID_ANY+1, - ID_REMOVE_ALL -}; -// end wxGlade - - -class AutosaveDialog: public wxDialog { -public: - // begin wxGlade: AutosaveDialog::ids - // end wxGlade - - AutosaveDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=wxT(""), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - -private: - // begin wxGlade: AutosaveDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //! the index of the selected item, -1 otherwise - size_t selectedItem; - - //True if the remove all button was - // depressed - bool haveRemovedItems; -protected: - // begin wxGlade: AutosaveDialog::attributes - wxListBox* listStates; - wxButton* btnRemoveAll; - wxButton* btnCancel; - wxButton* btnOK; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - virtual void OnListStates(wxCommandEvent &event); // wxGlade: - virtual void OnListStatesDClick(wxCommandEvent &event); // wxGlade: - virtual void OnRemoveAll(wxCommandEvent &event); // wxGlade: - virtual void OnCancel(wxCommandEvent &event); // wxGlade: - virtual void OnOK(wxCommandEvent &event); // wxGlade: - - //Set the items that are to be displayed in the listbox. - void setItems(const std::vector &items); - //!Get the item that was selected, returning the position of the selected - // item in the original vector - unsigned int getSelectedItem() const { return selectedItem;}; - - bool removedItems() const {return haveRemovedItems;}; - -}; // wxGlade: end class - - -#endif // AUTOSAVEDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/filterErrorDialog.cpp 3depict-0.0.13/src/dialogs/filterErrorDialog.cpp --- 3depict-0.0.12/src/dialogs/filterErrorDialog.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/filterErrorDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.3 on Sun Jun 24 00:03:00 2012 - -#include "filterErrorDialog.h" -#include "../wxcommon.h" -#include "../translation.h" -//Art for buttons -#include -// begin wxGlade: ::extracode -// end wxGlade - -using std::string; - - -FilterErrorDialog::FilterErrorDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) -{ - // begin wxGlade: FilterErrorDialog::FilterErrorDialog - textErrorMessage = new wxTextCtrl(this, wxID_ANY, wxEmptyString,wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE|wxTE_READONLY); - bitmapError = new wxStaticBitmap(this, wxID_ANY, wxArtProvider::GetBitmap(wxART_ERROR)); - labelError = new wxStaticText(this, wxID_ANY, wxTRANS("Error")); - bitmapWarning = new wxStaticBitmap(this, wxID_ANY,wxArtProvider::GetBitmap(wxART_WARNING)); - labelWarning = new wxStaticText(this, wxID_ANY, wxTRANS("Warning")); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - - SetTitle(wxTRANS("Filter Errors")); - set_properties(); - do_layout(); - // end wxGlade -} - - -void FilterErrorDialog::set_properties() -{ - // begin wxGlade: FilterErrorDialog::set_properties - SetTitle(wxTRANS("Filter Errors")); - SetSize(wxSize(551, 414)); - // end wxGlade -} - -void FilterErrorDialog::SetText(const std::vector &text) -{ - std::string bigMessage; - for(unsigned int ui=0;uiClear(); - textErrorMessage->AppendText(wxStr(bigMessage)); -} - -void FilterErrorDialog::do_layout() -{ - // begin wxGlade: FilterErrorDialog::do_layout - wxBoxSizer* sizerMain = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerTop = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerKey = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerWarn = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizerError = new wxBoxSizer(wxHORIZONTAL); - sizerTop->Add(textErrorMessage, 4, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 6); - sizerKey->Add(10, 10, 0, 0, 0); - sizerError->Add(bitmapError, 0, 0, 0); - sizerError->Add(labelError, 0, wxALIGN_CENTER_VERTICAL, 0); - sizerKey->Add(sizerError, 0, wxTOP|wxEXPAND, 5); - sizerWarn->Add(bitmapWarning, 0, 0, 0); - sizerWarn->Add(labelWarning, 0, wxALIGN_CENTER_VERTICAL, 0); - sizerKey->Add(sizerWarn, 0, wxTOP|wxEXPAND, 6); - sizerKey->Add(20, 20, 0, 0, 0); - sizerTop->Add(sizerKey, 1, wxEXPAND, 0); - sizerMain->Add(sizerTop, 1, wxEXPAND, 0); - sizerMain->Add(btnOK, 0, wxALL|wxALIGN_RIGHT, 5); - SetSizer(sizerMain); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/filterErrorDialog.h 3depict-0.0.13/src/dialogs/filterErrorDialog.h --- 3depict-0.0.12/src/dialogs/filterErrorDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/filterErrorDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.3 on Sun Jun 24 00:03:00 2012 - -#include -#include - -#include -#include -// begin wxGlade: ::dependencies -// end wxGlade - - -#ifndef FILTERERRORDIALOG_H -#define FILTERERRORDIALOG_H - - -// begin wxGlade: ::extracode -// end wxGlade - - -class FilterErrorDialog: public wxDialog { -public: - // begin wxGlade: FilterErrorDialog::ids - // end wxGlade - - FilterErrorDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=wxT(""), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - - void SetText(const std::vector &text); -private: - // begin wxGlade: FilterErrorDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - -protected: - // begin wxGlade: FilterErrorDialog::attributes - wxTextCtrl* textErrorMessage; - wxStaticBitmap* bitmapError; - wxStaticText* labelError; - wxStaticBitmap* bitmapWarning; - wxStaticText* labelWarning; - wxButton* btnOK; - // end wxGlade -}; // wxGlade: end class - - -#endif // FILTERERRORDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/prefDialog.cpp 3depict-0.0.13/src/dialogs/prefDialog.cpp --- 3depict-0.0.12/src/dialogs/prefDialog.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/prefDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,624 +0,0 @@ -/* - * prefDialog.cpp - mathgl plot wrapper class - * Copyright (C) 2012, 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 . -*/ - -// -*- C++ -*- generated by wxGlade HG on Fri Dec 3 22:26:29 2010 - -#include "prefDialog.h" - -#include "../filters/allFilter.h" -#include "../translation.h" - -#include - -#include "wxcommon.h" - -using std::vector; - - - -// begin wxGlade: ::extracode -// end wxGlade -enum -{ - ID_LIST_FILTERS = wxID_ANY+1, - ID_GRID_PROPERTIES, - ID_BTN_RESET_FILTER, - ID_BTN_RESET_FILTER_ALL, - ID_START_CHECK_CONTROL, - ID_START_CHECK_PLOTLIST, - ID_START_CHECK_RAWDATA, - ID_START_COMBO_PANEL, - ID_MOUSE_MOVE_SLIDER, - ID_MOUSE_ZOOM_SLIDER, -}; - - -//Number that -enum -{ - STARTUP_COMBO_SELECT_SHOW_ALL, - STARTUP_COMBO_SELECT_REMEMBER, - STARTUP_COMBO_SELECT_SPECIFY -}; - - -PrefDialog::PrefDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, style) -{ - SetTitle(wxTRANS("Preferences")); - // begin wxGlade: prefDialog::prefDialog - notePrefPanels = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); - notePrefPanels_pane_3 = new wxPanel(notePrefPanels, wxID_ANY); - panelStartup = new wxPanel(notePrefPanels, wxID_ANY); - panelFilters = new wxPanel(notePrefPanels, wxID_ANY); -#ifndef DISABLE_ONLINE_UPDATE - updateSizer_staticbox = new wxStaticBox(panelStartup, -1, wxTRANS("Online Updates")); -#endif - sizer_2_staticbox = new wxStaticBox(panelStartup, -1, wxTRANS("Panel Display")); - sizerCamSpeed_staticbox = new wxStaticBox(notePrefPanels_pane_3, -1, wxTRANS("Camera Speed")); - filterPropSizer_staticbox = new wxStaticBox(panelFilters, -1, wxTRANS("Filter Defaults")); - lblFilters = new wxStaticText(panelFilters, wxID_ANY, wxTRANS("Available Filters")); - listFilters = new wxListBox(panelFilters, ID_LIST_FILTERS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_SORT); - filterGridProperties = new wxPropertyGrid(panelFilters, ID_GRID_PROPERTIES); - filterBtnResetAllFilters = new wxButton(panelFilters, ID_BTN_RESET_FILTER_ALL, wxTRANS("Reset All")); - filterResetDefaultFilter = new wxButton(panelFilters, ID_BTN_RESET_FILTER, wxTRANS("Reset")); - const wxString comboPanelStartMode_choices[] = { - wxNTRANS("Show all panels"), - wxNTRANS("Remember last"), - wxNTRANS("Show Selected") - }; - comboPanelStartMode = new wxComboBox(panelStartup, ID_START_COMBO_PANEL, wxT(""), wxDefaultPosition, wxDefaultSize, 3, comboPanelStartMode_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY); - chkControl = new wxCheckBox(panelStartup, ID_START_CHECK_CONTROL, wxTRANS("Control Pane")); - chkRawData = new wxCheckBox(panelStartup, ID_START_CHECK_RAWDATA, wxTRANS("Raw Data Panel")); - chkPlotlist = new wxCheckBox(panelStartup, ID_START_CHECK_PLOTLIST, wxTRANS("Plot List")); -#ifndef DISABLE_ONLINE_UPDATE - checkAllowOnlineUpdate = new wxCheckBox(panelStartup, wxID_ANY, wxTRANS("Periodically notify about available updates")); -#endif - lblMoveSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Move Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - labelSlowCamMoveRate = new wxStaticText(notePrefPanels_pane_3,wxID_ANY, wxTRANS("(slow)")); - sliderCamMoveRate = new wxSlider(notePrefPanels_pane_3, ID_MOUSE_MOVE_SLIDER, 25, 1, 400,wxDefaultPosition,wxDefaultSize,wxSL_HORIZONTAL|wxSL_LABELS); - labelFastCamMoveRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(fast)")); - lblZoomSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Zoom Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - labelSlowCamZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(slow)")); - sliderCamZoomRate = new wxSlider(notePrefPanels_pane_3, ID_MOUSE_ZOOM_SLIDER, 25, 1, 400,wxDefaultPosition,wxDefaultSize,wxSL_HORIZONTAL|wxSL_LABELS); - labelSlowFastZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(fast)")); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); - - filterGridProperties->CreateGrid(0, 2); - filterGridProperties->EnableDragRowSize(false); - filterGridProperties->SetColLabelValue(0, wxTRANS("Param")); - filterGridProperties->SetColLabelValue(1, wxTRANS("Value")); - - bool enable=(comboPanelStartMode->GetSelection() == STARTUP_COMBO_SELECT_SPECIFY); - - chkRawData->Enable(enable); - chkControl->Enable(enable); - chkPlotlist->Enable(enable); - - comboPanelStartMode->SetSelection(0); - programmaticEvent=false; - curFilter=0; - - set_properties(); - do_layout(); - // end wxGlade -} - -PrefDialog::~PrefDialog() -{ - filterGridProperties->Destroy(); -} - -BEGIN_EVENT_TABLE(PrefDialog, wxDialog) - // begin wxGlade: PrefDialog::event_table - EVT_LISTBOX(ID_LIST_FILTERS, PrefDialog::OnFilterListClick) - EVT_GRID_CMD_CELL_CHANGE(ID_GRID_PROPERTIES, PrefDialog::OnFilterCellChange) - EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_PROPERTIES,PrefDialog::OnFilterGridCellEditorShow) - EVT_BUTTON(ID_BTN_RESET_FILTER,PrefDialog::OnResetFilterButton) - EVT_BUTTON(ID_BTN_RESET_FILTER_ALL,PrefDialog::OnResetFilterAllButton) - EVT_COMBOBOX(ID_START_COMBO_PANEL, PrefDialog::OnStartupPanelCombo) - EVT_COMMAND_SCROLL(ID_MOUSE_ZOOM_SLIDER, PrefDialog::OnMouseZoomSlider) - EVT_COMMAND_SCROLL(ID_MOUSE_MOVE_SLIDER, PrefDialog::OnMouseMoveSlider) - // end wxGlade -END_EVENT_TABLE(); - - -void PrefDialog::createFilterListing() -{ - listFilters->Clear(); - - wxString s; - vector v; - for(size_t ui=0;uitypeString()); - v.push_back(filterDefaults[ui]->getType()); - listFilters->Append(s); - } - - std::sort(v.begin(),v.end()); - unsigned int pos=0; - for(unsigned int ui=0;ui=v.size() || v[pos] != ui) - { - //This is a bit of a hack, but it works. - Filter *t; - t=makeFilter(ui); - s = wxStr(t->typeString()); - listFilters->Append(s); - delete t; - } - else - pos++; - } - -} - -void PrefDialog::initialise() -{ - createFilterListing(); - - //Transfer the movement rates from class to the slider - ASSERT(mouseZoomRatePercent >=sliderCamZoomRate->GetMin() && - mouseZoomRatePercent <=sliderCamZoomRate->GetMax()); - ASSERT(mouseMoveRatePercent >=sliderCamMoveRate->GetMin() && - mouseMoveRatePercent <=sliderCamMoveRate->GetMax()); - - - sliderCamZoomRate->SetValue(mouseZoomRatePercent); - sliderCamMoveRate->SetValue(mouseMoveRatePercent); - - - -} - -void PrefDialog::cleanup() -{ - for(unsigned int ui=0;ui &defs) const -{ - defs.resize(filterDefaults.size()); - - for(unsigned int ui=0;uicloneUncached(); -} - -void PrefDialog::setFilterDefaults(const vector &defs) -{ - filterDefaults.resize(defs.size()); - - for(unsigned int ui=0;uicloneUncached(); -} - -void PrefDialog::OnFilterListClick(wxCommandEvent &event) -{ - - //get the string associated with the current click - string s; - - //Check to see if we need to delete the current filter - //or if we have it as a default - if(find(filterDefaults.begin(),filterDefaults.end(), - curFilter) == filterDefaults.end()) - delete curFilter; - - - Filter *f=0; - s=stlStr(listFilters->GetString(event.GetSelection())); - - for(size_t ui=0;uigetUserString() == s) - { - f=filterDefaults[ui]; - break; - } - } - - if(!f) - f=makeFilterFromDefUserString(s); - - ASSERT(f); - updateFilterProp(f); - - curFilter=f; -} - - -void PrefDialog::OnFilterCellChange(wxGridEvent &event) -{ - //Disallow programmatic event from causing filter update (stack loop->overflow) - if(programmaticEvent) - { - event.Veto(); - return; - } - - //Grab the changed value - std::string value; - int row=event.GetRow(); - value = stlStr(filterGridProperties->GetCellValue( - row,1)); - programmaticEvent=true; - - bool needUpdate; - curFilter->setProperty(filterGridProperties->getKeyFromRow(row), - value,needUpdate); - - if(find(filterDefaults.begin(),filterDefaults.end(), - curFilter) == filterDefaults.end()) - filterDefaults.push_back(curFilter); - - updateFilterProp(curFilter); - programmaticEvent=false; -} - - - -//This function modifies the properties before showing the cell content editor.T -//This is needed only for certain data types (colours, bools) other data types are edited -//using the default editor and modified using ::OnGridFilterPropertyChange -void PrefDialog::OnFilterGridCellEditorShow(wxGridEvent &event) -{ - //Find where the event occured (cell & property) - const GRID_PROPERTY *item=0; - - unsigned int key; - key=filterGridProperties->getKeyFromRow(event.GetRow()); - - item=filterGridProperties->getProperty(key); - - bool needUpdate; - switch(item->type) - { - case PROPERTY_TYPE_BOOL: - { - std::string s; - //Toggle the property in the grid - if(item->data == "0") - s= "1"; - else - s="0"; - curFilter->setProperty(key,s,needUpdate); - - event.Veto(); - - updateFilterProp(curFilter); - break; - } - case PROPERTY_TYPE_COLOUR: - { - //Show a wxColour choose dialog. - wxColourData d; - - unsigned char r,g,b,a; - parseColString(item->data,r,g,b,a); - - d.SetColour(wxColour(r,g,b,a)); - wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); - - - if( colDg->ShowModal() == wxID_OK) - { - wxColour c; - //Change the colour - c=colDg->GetColourData().GetColour(); - - std::string s; - genColString(c.Red(),c.Green(),c.Blue(),s); - - //Pass the new colour to the viscontrol system, which updates - //the filters - curFilter->setProperty(key,s,needUpdate); - } - - //Set the filter property - //Disallow direct editing of the grid cell - event.Veto(); - - - updateFilterProp(curFilter); - break; - } - case PROPERTY_TYPE_CHOICE: - break; - default: - //we will handle this after the user has edited the cell contents - break; - } - - //Add to the modified filter defaults as needed - if(find(filterDefaults.begin(),filterDefaults.end(), - curFilter) == filterDefaults.end()) - filterDefaults.push_back(curFilter); -} - -void PrefDialog::OnResetFilterButton(wxCommandEvent &evt) -{ - - if(!curFilter) - { - evt.Skip(); - return; - } - - //Erase the filter from the modified defaults list - for(size_t ui=0;uiGetString( - listFilters->GetSelection())); - curFilter=makeFilterFromDefUserString(s); - - //Update the prop grid - updateFilterProp(curFilter); - break; - } - } - -} - -void PrefDialog::OnResetFilterAllButton(wxCommandEvent &evt) -{ - if(!curFilter) - { - evt.Skip(); - return; - } - - //Check to see if we have it in the non-"true" default list - for(size_t ui=0;uiGetString( - listFilters->GetSelection())); - - curFilter=makeFilterFromDefUserString(s); - updateFilterProp(curFilter); -} - - -void PrefDialog::updateFilterProp(const Filter *f) -{ - if(!(f->canBeHazardous())) - { - filterGridProperties->Enable(true); - updateFilterPropertyGrid(filterGridProperties,f); - } - else - { - //If the filter is potentially hazardous, - //then we will disallow editing of the properties. - //and give a notice to that effect - filterGridProperties->BeginBatch(); - filterGridProperties->Enable(false); - wxGridCellAttr *readOnlyColAttr=new wxGridCellAttr; - - //Empty the grid - //then fill it up with a note. - if(filterGridProperties->GetNumberCols()) - filterGridProperties->DeleteCols(0,filterGridProperties->GetNumberCols()); - if(filterGridProperties->GetNumberRows()) - filterGridProperties->DeleteRows(0,filterGridProperties->GetNumberRows()); - - filterGridProperties->AppendRows(1); - filterGridProperties->AppendCols(1); - filterGridProperties->AutoSizeColumn(0,true); - filterGridProperties->SetColAttr(0,readOnlyColAttr); - filterGridProperties->SetColLabelValue(0,wxTRANS("Notice")); - - filterGridProperties->SetCellValue(0,0, - wxTRANS("For security reasons, defaults are not modifiable for this filter")); - - filterGridProperties->EndBatch(); - - //Set the column size so you can see the message - filterGridProperties->SetColSize(0, filterGridProperties->GetSize().GetWidth() - - filterGridProperties->GetScrollThumb(wxVERTICAL) - 15); - - } -} - -//-------------- End Filter page----------------------- - -//-------------- Startup panel page----------------------- - -void PrefDialog::OnStartupPanelCombo(wxCommandEvent &event) -{ - setStartupCheckboxEnables(event.GetSelection()); -} - -void PrefDialog::setStartupCheckboxEnables(unsigned int value) -{ - bool enable=( value == STARTUP_COMBO_SELECT_SPECIFY); - - chkRawData->Enable(enable); - chkControl->Enable(enable); - chkPlotlist->Enable(enable); - switch(value) - { - case STARTUP_COMBO_SELECT_SHOW_ALL: - comboPanelStartMode->SetToolTip(wxTRANS("Show all panels when starting program")); - break; - case STARTUP_COMBO_SELECT_REMEMBER: - comboPanelStartMode->SetToolTip(wxTRANS("Show panels visible at last shutdown when starting program")); - - chkRawData->SetValue(true); - chkControl->SetValue(true); - chkPlotlist->SetValue(true); - break; - case STARTUP_COMBO_SELECT_SPECIFY: - comboPanelStartMode->SetToolTip(wxTRANS("Show selected panels when starting program")); - break; - default: - ASSERT(false); - } -} -void PrefDialog::setPanelDefaults(unsigned int panelMode, bool panelControl, - bool panelRaw,bool panelPlotlist) -{ - ASSERT(panelMode < comboPanelStartMode->GetCount()); - - chkRawData->SetValue(panelRaw); - chkControl->SetValue(panelControl); - chkPlotlist->SetValue(panelPlotlist); - - comboPanelStartMode->SetSelection(panelMode); - setStartupCheckboxEnables(panelMode); - -} -void PrefDialog::getPanelDefaults(unsigned int &panelMode, bool &panelControl, - bool &panelRaw,bool &panelPlotlist) const -{ - panelControl=chkControl->IsChecked(); - panelRaw=chkRawData->IsChecked(); - panelPlotlist=chkPlotlist->IsChecked(); - - panelMode=comboPanelStartMode->GetSelection(); -} - - -//-------------- End Startup panel page----------------------- - - -//------------Mouse page ----------- -void PrefDialog::OnMouseZoomSlider(wxScrollEvent &event) -{ - mouseZoomRatePercent=sliderCamZoomRate->GetValue(); -} -void PrefDialog::OnMouseMoveSlider(wxScrollEvent &event) -{ - mouseMoveRatePercent=sliderCamMoveRate->GetValue(); -} -//------------End mouse page------------- -// wxGlade: add PrefDialog event handlers - - -void PrefDialog::set_properties() -{ - // begin wxGlade: PrefDialog::set_properties - SetTitle(wxTRANS("Preferences")); - SetSize(wxSize(640, 487)); - comboPanelStartMode->SetToolTip(wxTRANS("Set the method of panel layout when starting the program")); - comboPanelStartMode->SetSelection(0); -#ifndef DISABLE_ONLINE_UPDATE - checkAllowOnlineUpdate->SetToolTip(wxTRANS("Lets the program check the internet to see if updates to the program version are available, then notifies you about updates now and again.")); -#endif - sliderCamMoveRate->SetToolTip(wxTRANS("Camera translation, orbit and swivel rates. ")); - sliderCamZoomRate->SetToolTip(wxTRANS("Camera zooming rate.")); - - filterResetDefaultFilter->SetToolTip(wxTRANS("Reset the filter initial values back to program defaults")); - filterBtnResetAllFilters->SetToolTip(wxTRANS("Reset all filter initial values back to program defaults")); - - // end wxGlade -} - - -void PrefDialog::do_layout() -{ - // begin wxGlade: PrefDialog::do_layout - wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* exitButtonSizer = new wxBoxSizer(wxHORIZONTAL); - wxStaticBoxSizer* sizerCamSpeed = new wxStaticBoxSizer(sizerCamSpeed_staticbox, wxVERTICAL); - wxBoxSizer* sizer_6_copy = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_6 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); -#ifndef DISABLE_ONLINE_UPDATE - wxStaticBoxSizer* updateSizer = new wxStaticBoxSizer(updateSizer_staticbox, wxVERTICAL); -#endif - wxStaticBoxSizer* sizer_2 = new wxStaticBoxSizer(sizer_2_staticbox, wxVERTICAL); - wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_4 = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* filterPropSizer = new wxStaticBoxSizer(filterPropSizer_staticbox, wxHORIZONTAL); - wxBoxSizer* filterRightSideSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* resetButtonSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* filterLeftSizer = new wxBoxSizer(wxVERTICAL); - filterLeftSizer->Add(lblFilters, 0, 0, 0); - filterLeftSizer->Add(listFilters, 1, wxEXPAND, 0); - filterPropSizer->Add(filterLeftSizer, 1, wxEXPAND, 0); - filterPropSizer->Add(20, 20, 0, 0, 0); - filterRightSideSizer->Add(filterGridProperties, 1, wxEXPAND, 0); - resetButtonSizer->Add(filterBtnResetAllFilters, 0, 0, 0); - resetButtonSizer->Add(filterResetDefaultFilter, 0, 0, 0); - resetButtonSizer->Add(20, 20, 1, 0, 0); - filterRightSideSizer->Add(resetButtonSizer, 0, wxEXPAND, 0); - filterPropSizer->Add(filterRightSideSizer, 2, wxEXPAND, 0); - panelFilters->SetSizer(filterPropSizer); - sizer_2->Add(comboPanelStartMode, 0, 0, 0); - sizer_3->Add(20, 20, 0, 0, 0); - sizer_4->Add(chkControl, 0, 0, 0); - sizer_4->Add(chkRawData, 0, 0, 0); - sizer_4->Add(chkPlotlist, 0, 0, 0); - sizer_3->Add(sizer_4, 1, wxEXPAND, 0); - sizer_2->Add(sizer_3, 1, wxEXPAND, 0); - sizer_1->Add(sizer_2, 0, wxALL|wxEXPAND, 5); -#ifndef DISABLE_ONLINE_UPDATE - updateSizer->Add(checkAllowOnlineUpdate, 0, 0, 0); - sizer_1->Add(updateSizer, 0, wxALL|wxEXPAND, 5); -#endif - panelStartup->SetSizer(sizer_1); - sizer_6->Add(lblMoveSpeed, 0, wxALIGN_CENTER_VERTICAL, 0); - sizer_6->Add(20, 20, 0, 0, 0); - sizer_6->Add(labelSlowCamMoveRate, 0, wxALIGN_CENTER_VERTICAL, 0); - sizer_6->Add(sliderCamMoveRate, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizer_6->Add(labelFastCamMoveRate, 0, wxALIGN_CENTER_VERTICAL, 0); - sizerCamSpeed->Add(sizer_6, 1, wxEXPAND, 0); - sizer_6_copy->Add(lblZoomSpeed, 0, wxALIGN_CENTER_VERTICAL, 0); - sizer_6_copy->Add(20, 20, 0, 0, 0); - sizer_6_copy->Add(labelSlowCamZoomRate, 0, wxALIGN_CENTER_VERTICAL, 0); - sizer_6_copy->Add(sliderCamZoomRate, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); - sizer_6_copy->Add(labelSlowFastZoomRate, 0, wxALIGN_CENTER_VERTICAL, 0); - sizerCamSpeed->Add(sizer_6_copy, 1, wxEXPAND, 0); - notePrefPanels_pane_3->SetSizer(sizerCamSpeed); - notePrefPanels->AddPage(panelFilters, wxTRANS("Pref")); - notePrefPanels->AddPage(panelStartup, wxTRANS("Startup")); - notePrefPanels->AddPage(notePrefPanels_pane_3, wxTRANS("Camera")); - panelSizer->Add(notePrefPanels, 2, wxEXPAND, 0); - exitButtonSizer->Add(20, 20, 1, wxEXPAND, 0); - exitButtonSizer->Add(btnOK, 0, wxTOP, 8); - exitButtonSizer->Add(btnCancel, 0, wxLEFT|wxTOP|wxBOTTOM, 8); - exitButtonSizer->Add(10, 20, 0, 0, 0); - panelSizer->Add(exitButtonSizer, 0, wxEXPAND, 0); - SetSizer(panelSizer); - Layout(); - // end wxGlade -} - diff -Nru 3depict-0.0.12/src/dialogs/prefDialog.h 3depict-0.0.13/src/dialogs/prefDialog.h --- 3depict-0.0.12/src/dialogs/prefDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/prefDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -// -*- C++ -*- generated by wxGlade HG on Fri Dec 3 22:26:29 2010 -/* - * prefDialog.h - program preferences management dialog - * 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 - * 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 . - */ - -#include -#include -// begin wxGlade: ::dependencies -#include -#include -// end wxGlade - -#ifndef PREFDIALOG_H -#define PREFDIALOG_H - - -#include - -#include "../filter.h" - -// begin wxGlade: ::extracode -// end wxGlade - -//As a courtesy, we do not allow online update checking under linux -//its pointless, as linux systems usually have proper package management -// apple crashes wx -#if defined( __linux__) || defined(__APPLE__) - #define DISABLE_ONLINE_UPDATE -#endif - -class PrefDialog: public wxDialog -{ - -private: - // begin wxGlade: PrefDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - - //the user specified defaults. This class must clean up this poitner - std::vector filterDefaults; - - //!Current default filter setting (def. filter panel). Is null iff using hard-coded version - Filter *curFilter; - - bool programmaticEvent; - //!Generate the list of filters which can have their defaults set - void createFilterListing(); - - //!Enable/disable the check controls ont he startup panel as needed - void setStartupCheckboxEnables(unsigned int comboSel); - - //!Update the filter property grid, as needed - void updateFilterProp(const Filter *f); - - //!Percentile speeds for mouse zoom and move - unsigned int mouseZoomRatePercent,mouseMoveRatePercent; -protected: - // begin wxGlade: PrefDialog::attributes - wxStaticBox* sizerCamSpeed_staticbox; - wxStaticBox* updateSizer_staticbox; - wxStaticBox* sizer_2_staticbox; - wxStaticBox* filterPropSizer_staticbox; - wxStaticText* lblFilters; - wxListBox* listFilters; - wxPropertyGrid* filterGridProperties; - wxButton* filterBtnResetAllFilters; - wxButton* filterResetDefaultFilter; - wxPanel* panelFilters; - wxComboBox* comboPanelStartMode; - wxCheckBox* chkControl; - wxCheckBox* chkRawData; - wxCheckBox* chkPlotlist; -#ifndef DISABLE_ONLINE_UPDATE - wxCheckBox* checkAllowOnlineUpdate; -#endif - wxPanel* panelStartup; - wxStaticText* lblMoveSpeed; - wxNotebook* notePrefPanels; - wxButton* btnOK; - wxButton* btnCancel; - wxSlider* sliderCamMoveRate; - wxStaticText* labelFastCamMoveRate; - wxStaticText* labelSlowCamMoveRate; - wxStaticText* lblZoomSpeed; - wxStaticText* labelSlowCamZoomRate; - wxSlider* sliderCamZoomRate; - wxStaticText* labelSlowFastZoomRate; - wxPanel* notePrefPanels_pane_3; - // end wxGlade - - DECLARE_EVENT_TABLE(); - -public: - // begin wxGlade: PrefDialog::ids - // end wxGlade - PrefDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=_(""), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); - virtual ~PrefDialog(); - virtual void OnFilterListClick(wxCommandEvent &event); // wxGlade: - virtual void OnFilterCellChange(wxGridEvent &event); // wxGlade: - virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // wxGlade: - virtual void OnResetFilterButton(wxCommandEvent &event); // wxGlade: - virtual void OnResetFilterAllButton(wxCommandEvent &event); // wxGlade: - - //set the filter defaults. note that the incoming pointers are cloned, and control is NOT transferred to this class - void setFilterDefaults(const std::vector &defs); - //Get the filter defaults. Note clones are returned, not the orignals - void getFilterDefaults(std::vector &defs) const; - - void setPanelDefaults(unsigned int panelMode, bool panelControl, - bool panelRaw,bool panelPlotlist); - void getPanelDefaults(unsigned int &panelMode, bool &panelControl, - bool &panelRaw,bool &panelPlotlist) const; - -#ifndef DISABLE_ONLINE_UPDATE - bool getAllowOnlineUpdate() const { return checkAllowOnlineUpdate->IsChecked();}; - void setAllowOnlineUpdate(bool allowed) { checkAllowOnlineUpdate->SetValue(allowed);}; -#endif - void setMouseZoomRate(unsigned int rate) { mouseZoomRatePercent=rate;}; - void setMouseMoveRate(unsigned int rate) { mouseMoveRatePercent=rate;}; - - unsigned int getMouseZoomRate() const { return mouseZoomRatePercent;}; - unsigned int getMouseMoveRate() const { return mouseMoveRatePercent;}; - - virtual void OnStartupPanelCombo(wxCommandEvent &event); // wxGlade: - void OnMouseMoveSlider(wxScrollEvent &event); - void OnMouseZoomSlider(wxScrollEvent &event); - - void initialise(); - void cleanup(); -}; // wxGlade: end class - - -#endif // PREFDIALOG_H diff -Nru 3depict-0.0.12/src/dialogs/resolutionDialog.cpp 3depict-0.0.13/src/dialogs/resolutionDialog.cpp --- 3depict-0.0.12/src/dialogs/resolutionDialog.cpp 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/resolutionDialog.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,488 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.3 on Mon May 7 00:46:06 2012 - -#include "resolutionDialog.h" - -#include "../wxcommon.h" -#include "../basics.h" -#include "../translation.h" - -#include - -// begin wxGlade: ::extracode - -// end wxGlade - - -enum -{ - ID_RESET=wxID_ANY+1, - ID_TEXT_WIDTH, - ID_TEXT_HEIGHT, - ID_LOCK_ASPECT -}; - -const float MOUSEWHEEL_RATE_MULTIPLIER=1.0f; - -ResolutionDialog::ResolutionDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): - wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) -{ - // begin wxGlade: ResolutionDialog::ResolutionDialog - labelWidth = new wxStaticText(this, wxID_ANY, wxTRANS("Width :"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - textWidth = new wxTextCtrl(this, ID_TEXT_WIDTH, wxT("")); - labelHeight = new wxStaticText(this, wxID_ANY, wxTRANS("Height :")); - textHeight = new wxTextCtrl(this, ID_TEXT_HEIGHT, wxT("")); - checkLockAspect = new wxCheckBox(this, ID_LOCK_ASPECT, wxTRANS("Lock Aspect")); - static_line_1 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); - panelImage = new wxPanel(this, wxID_ANY); - static_line_2 = new wxStaticLine(this, wxID_ANY); - btnReset = new wxButton(this, ID_RESET, wxTRANS("Reset")); - btnOK = new wxButton(this, wxID_OK, wxEmptyString); - button_2 = new wxButton(this, wxID_CANCEL, wxEmptyString); - -#if wxCHECK_VERSION(2, 9, 0) - textWidth->Bind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this); - textHeight->Bind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this); - SetBackgroundStyle(wxBG_STYLE_PAINT); -#else - textWidth->Connect(wxID_ANY, wxEVT_MOUSEWHEEL, - wxMouseEventHandler(ResolutionDialog::OnMouseWheelWidth),NULL,this); - textHeight->Connect(wxID_ANY, wxEVT_MOUSEWHEEL, - wxMouseEventHandler(ResolutionDialog::OnMouseWheelHeight),NULL,this); -#endif - - - - set_properties(); - do_layout(); - // end wxGlade - - programmaticEvent=0; - - updateImage(); -} - - -BEGIN_EVENT_TABLE(ResolutionDialog, wxDialog) - // begin wxGlade: ResolutionDialog::event_table - EVT_TEXT(ID_TEXT_WIDTH, ResolutionDialog::OnTextWidth) - EVT_TEXT(ID_TEXT_HEIGHT, ResolutionDialog::OnTextHeight) - EVT_CHECKBOX(ID_LOCK_ASPECT, ResolutionDialog::OnCheckLockAspect) - EVT_BUTTON(ID_RESET, ResolutionDialog::OnBtnReset) - EVT_BUTTON(wxID_OK, ResolutionDialog::OnBtnOK) - EVT_BUTTON(wxID_CANCEL, ResolutionDialog::OnBtnCancel) - EVT_PAINT(ResolutionDialog::OnPaint) - EVT_KEY_DOWN(ResolutionDialog::OnKeypress) - // end wxGlade -END_EVENT_TABLE(); - -void ResolutionDialog::updateImage() -{ - wxPaintEvent paintEvt; - wxPostEvent(this,paintEvt); -} - -void ResolutionDialog::setRes(unsigned int w, unsigned int h, bool asReset) -{ - //Increment programattic lock counter - programmaticEvent++; - - std::string s; - stream_cast(s,w); - textWidth->SetValue(wxStr(s)); - - stream_cast(s,h); - textHeight->SetValue(wxStr(s)); - - resWidth=w; - resHeight=h; - - //do we want to use this as the reset value? - if(asReset) - { - resOrigWidth=w; - resOrigHeight=h; - - if(resOrigWidth) - aspect=(float)resOrigHeight/(float)resOrigWidth; - else - aspect=0; - } - - programmaticEvent--; -} - -void ResolutionDialog::OnTextWidth(wxCommandEvent &event) -{ - - if(programmaticEvent) - return; - - programmaticEvent++; - - //Validate that string is numerical - //--- - wxString s =event.GetString(); - std::string textStr; - textStr=stlStr(s); - if(textStr.find_first_not_of("0123456789")!=std::string::npos ) - { - stream_cast(textStr,resWidth); - textWidth->SetValue(wxStr(textStr)); - programmaticEvent--; - return; - } - //--- - - - int width; - textStr = stlStr(textWidth->GetValue()); - - if(stream_cast(width,textStr)) - { - programmaticEvent--; - return; - } - resWidth=width; - - //if we are locking the aspect ratio, set the other text box to have the same ratio - if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) - { - resHeight=(unsigned int)(width*aspect); - stream_cast(textStr,resHeight); - textHeight->SetValue(wxStr(textStr)); - } - - - updateImage(); - - programmaticEvent--; -} - -void ResolutionDialog::OnTextHeight(wxCommandEvent &event) -{ - - if(programmaticEvent) - return; - - programmaticEvent++; - - - //Validate that string is numerical - //--- - wxString s =event.GetString(); - std::string textStr; - textStr=stlStr(s); - if(textStr.find_first_not_of("0123456789")!=std::string::npos ) - { - stream_cast(textStr,resHeight); - textHeight->SetValue(wxStr(textStr)); - programmaticEvent--; - return; - } - //--- - - - int height; - textStr = stlStr(textHeight->GetValue()); - - if(stream_cast(height,textStr)) - { - programmaticEvent--; - return; - } - - resHeight=height; - - //if we are locking the aspect ratio, set the other text box to preserve the same ratio - if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) - { - resWidth=(unsigned int)(height/aspect); - stream_cast(textStr,resWidth); - textWidth->SetValue(wxStr(textStr)); - } - - updateImage(); - - programmaticEvent--; -} - - -void ResolutionDialog::OnCheckLockAspect(wxCommandEvent &event) -{ - //Recompute the desired aspect - if(resWidth) - aspect=(float)resHeight/(float)resWidth; - else - aspect=0; -} - - -void ResolutionDialog::OnBtnReset(wxCommandEvent &event) -{ - setRes(resOrigWidth,resOrigHeight); - - //Recompute the desired aspect as per the original - if(resOrigWidth) - aspect=(float)resOrigHeight/(float)resOrigWidth; - else - aspect=0; -} - - -void ResolutionDialog::OnBtnOK(wxCommandEvent &event) -{ - finishDialog(); -} - - -void ResolutionDialog::OnBtnCancel(wxCommandEvent &event) -{ - EndModal(wxID_CANCEL); -} - -void ResolutionDialog::OnMouseWheelWidth(wxMouseEvent &event) -{ - - bool haveCtrl,haveShift; - haveShift=event.ShiftDown(); - haveCtrl=event.CmdDown(); - - //normal move rate - float moveRate=(float)event.GetWheelRotation()/(float)event.GetWheelDelta()*MOUSEWHEEL_RATE_MULTIPLIER; - - //scroll rate multiplier for this scroll event - { - float multiplier; - if(haveShift) - multiplier=5.0f; - else if(haveCtrl) - multiplier=10.0f; - else - multiplier=1.0f; - - moveRate*=multiplier; - } - - - if(resWidth+moveRate <= 0) - return; - - programmaticEvent++; - setRes(resWidth+moveRate,resHeight); - - //if we are locking the aspect ratio, set the other text box to preserve the same ratio - if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) - { - std::string textStr; - resHeight=(unsigned int)resWidth*aspect; - stream_cast(textStr,resHeight); - textHeight->SetValue(wxStr(textStr)); - } - - updateImage(); - programmaticEvent--; -} - -void ResolutionDialog::OnMouseWheelHeight(wxMouseEvent &event) -{ - - - bool haveCtrl,haveShift; - haveShift=event.ShiftDown(); - haveCtrl=event.CmdDown(); - - //normal move rate - float moveRate=(float)event.GetWheelRotation()/(float)event.GetWheelDelta()*MOUSEWHEEL_RATE_MULTIPLIER; - - //scroll rate multiplier for this scroll event - { - float multiplier; - if(haveShift) - multiplier=5.0f; - else if(haveCtrl) - multiplier=10.0f; - else - multiplier=1.0f; - - moveRate*=multiplier; - } - - - - if(resHeight+moveRate <= 0) - return; - - programmaticEvent++; - - setRes(resWidth,(unsigned int)(resHeight+moveRate)); - - //if we are locking the aspect ratio, set the other text box to preserve the same ratio - if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) - { - std::string textStr; - resWidth=(unsigned int)(resHeight/aspect); - stream_cast(textStr,resWidth); - textWidth->SetValue(wxStr(textStr)); - } - - updateImage(); - programmaticEvent--; -} - -void ResolutionDialog::OnPaint(wxPaintEvent &event) -{ -#ifdef __APPLE__ - wxDC *dialogDC = new wxClientDC(this); -#else - wxDC *dialogDC = new wxAutoBufferedPaintDC(this); -#endif - - int widthLabelY,heightLabelY,checkBoxY,connectorX; - int tmpY,tmpX,tmp; - - labelWidth->GetPosition(&connectorX,&tmpY); - labelWidth->GetSize(&tmpX,&tmp); - widthLabelY=tmpY + tmp/2; - - labelHeight->GetPosition(&tmpX,&tmpY); - labelHeight->GetSize(&tmpX,&tmp); - heightLabelY=tmpY + tmp/2; - - checkLockAspect->GetPosition(&tmpX,&tmpY); - checkLockAspect->GetSize(&tmpX,&tmp); - checkBoxY=tmpY + tmp/2; - - //Draw the connecting lines in an "E" shape - const int LINE_STANDOFF=8; - - dialogDC->DrawLine(connectorX-LINE_STANDOFF/2,widthLabelY, - connectorX-LINE_STANDOFF,widthLabelY); - dialogDC->DrawLine(connectorX-LINE_STANDOFF/2,heightLabelY, - connectorX-LINE_STANDOFF,heightLabelY); - dialogDC->DrawLine(connectorX-LINE_STANDOFF/2,checkBoxY, - connectorX-LINE_STANDOFF,checkBoxY); - - dialogDC->DrawLine(connectorX-LINE_STANDOFF,checkBoxY, - connectorX-LINE_STANDOFF,widthLabelY); - - - delete dialogDC; - -#ifdef __APPLE__ - wxDC *paintDC = new wxClientDC(panelImage); -#else - wxDC *paintDC = new wxAutoBufferedPaintDC(panelImage); -#endif - - drawImageRectangle(paintDC); - - delete paintDC; -} - -void ResolutionDialog::drawImageRectangle(wxDC *paintDC) -{ - paintDC->Clear(); - int width,height; - width=resWidth; - height=resHeight; - - - if(!(width && height)) - return; - - - int panelHeight,panelWidth; - - panelImage->GetClientSize(&panelWidth,&panelHeight); - - - float scaleFactor; - //Rescale the dimensions to fit - // into image panel - scaleFactor=std::min((float)panelHeight/(float)height, - (float)panelWidth/(float)width); - - width=(unsigned int)(width*scaleFactor); - height=(unsigned int)(height*scaleFactor); - - int startX,startY; - - startX = (int)((float)(panelWidth - width)*0.5f); - startY = (int)((float)(panelHeight - height)*0.5f); - - paintDC->DrawRectangle(startX,startY,width,height); - -} - -void ResolutionDialog::OnKeypress(wxKeyEvent &evt) -{ - if( evt.GetKeyCode() == WXK_RETURN) - finishDialog(); - evt.Skip(); -} - -// wxGlade: add ResolutionDialog event handlers - -void ResolutionDialog::finishDialog() -{ - //programmatic event counter should be decremented to zero - ASSERT(!programmaticEvent); - -#if wxCHECK_VERSION(2, 9, 0) - textWidth->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this); - textHeight->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this); -#else - textWidth->Disconnect(); - textHeight->Disconnect(); -#endif - EndModal(wxID_OK); -} - -void ResolutionDialog::set_properties() -{ - // begin wxGlade: ResolutionDialog::set_properties - SetTitle(wxTRANS("Resolution Selection")); - // end wxGlade -} - - -void ResolutionDialog::do_layout() -{ - // begin wxGlade: ResolutionDialog::do_layout - wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* upperSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* leftSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* heightTextSizer = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* widthTextSizer = new wxBoxSizer(wxHORIZONTAL); - upperSizer->Add(10, 20, 0, 0, 0); - leftSizer->Add(20, 20, 2, 0, 0); - widthTextSizer->Add(labelWidth, 0, wxALIGN_CENTER_VERTICAL, 0); - widthTextSizer->Add(textWidth, 0, wxALL|wxALIGN_CENTER_VERTICAL, 8); - leftSizer->Add(widthTextSizer, 1, wxEXPAND, 0); - heightTextSizer->Add(labelHeight, 0, wxALIGN_CENTER_VERTICAL, 0); - heightTextSizer->Add(textHeight, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5); - leftSizer->Add(heightTextSizer, 1, wxEXPAND, 0); - leftSizer->Add(checkLockAspect, 0, wxALIGN_CENTER_VERTICAL, 3); - leftSizer->Add(20, 20, 2, 0, 0); - upperSizer->Add(leftSizer, 0, wxLEFT|wxEXPAND, 8); - upperSizer->Add(10, 10, 0, 0, 0); - upperSizer->Add(static_line_1, 0, wxEXPAND, 0); - upperSizer->Add(panelImage, 5, wxALL|wxEXPAND, 5); - mainSizer->Add(upperSizer, 1, wxEXPAND, 0); - mainSizer->Add(static_line_2, 0, wxEXPAND, 0); - buttonSizer->Add(btnReset, 0, wxALL, 5); - buttonSizer->Add(20, 20, 1, 0, 0); - buttonSizer->Add(btnOK, 0, wxALL, 5); - buttonSizer->Add(button_2, 0, wxALL, 5); - mainSizer->Add(buttonSizer, 0, wxTOP|wxBOTTOM|wxEXPAND, 5); - SetSizer(mainSizer); - mainSizer->Fit(this); - Layout(); - // end wxGlade -} - - - - - diff -Nru 3depict-0.0.12/src/dialogs/resolutionDialog.h 3depict-0.0.13/src/dialogs/resolutionDialog.h --- 3depict-0.0.12/src/dialogs/resolutionDialog.h 2012-11-11 19:54:15.000000000 +0000 +++ 3depict-0.0.13/src/dialogs/resolutionDialog.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -// -*- C++ -*- generated by wxGlade 0.6.3 on Mon May 7 00:46:06 2012 - -#include -#include -// begin wxGlade: ::dependencies -#include -#include -// end wxGlade - - -#ifndef RESOLUTIONDIALOG_H -#define RESOLUTIONDIALOG_H - -//!resolution chooser dialog -class ResolutionDialog: public wxDialog { -public: - // begin wxGlade: ResolutionDialog::ids - // end wxGlade - - ResolutionDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); - -private: - //Resolution width and height or the final output - unsigned int resWidth,resHeight; - - //!Reset value for resolution - unsigned int resOrigWidth,resOrigHeight; - - //!Programmatic event counter - // Non-zero if event is being generated programatically - int programmaticEvent; - - //!aspect ratio for when locking aspect. Zero if undefined - float aspect; - - // begin wxGlade: ResolutionDialog::methods - void set_properties(); - void do_layout(); - // end wxGlade - //!Finish up the dialog - void finishDialog(); - //!Update the drawn image representing the output shape - void updateImage(); - - //!Draw the image rectangle - void drawImageRectangle(wxDC *dc); -protected: - // begin wxGlade: ResolutionDialog::attributes - wxStaticText* labelWidth; - wxTextCtrl* textWidth; - wxStaticText* labelHeight; - wxTextCtrl* textHeight; - wxCheckBox* checkLockAspect; - wxStaticLine* static_line_1; - wxPanel* panelImage; - wxStaticLine* static_line_2; - wxButton* btnReset; - wxButton* btnOK; - wxButton* button_2; - // end wxGlade - - DECLARE_EVENT_TABLE(); - - -public: - virtual void OnTextWidth(wxCommandEvent &event); // wxGlade: - virtual void OnTextHeight(wxCommandEvent &event); // wxGlade: - virtual void OnCheckLockAspect(wxCommandEvent &event); // wxGlade: - virtual void OnBtnReset(wxCommandEvent &event); // wxGlade: - virtual void OnBtnOK(wxCommandEvent &event); // wxGlade: - virtual void OnBtnCancel(wxCommandEvent &event); // wxGlade: - virtual void OnMouseWheelWidth(wxMouseEvent &event); - virtual void OnMouseWheelHeight(wxMouseEvent &event); - virtual void OnPaint(wxPaintEvent &event); - - virtual void OnKeypress(wxKeyEvent &evt); - - - //!get the width as entered in the dialog - unsigned int getWidth() const {return resWidth;}; - //!Get the height as entered in the dialog box - unsigned int getHeight() const {return resHeight;}; - //!Set the resolution and update text boxes - void setRes(unsigned int w, unsigned int h, bool asReset=false); -}; // wxGlade: end class - - -#endif // RES_H diff -Nru 3depict-0.0.12/src/drawables.cpp 3depict-0.0.13/src/drawables.cpp --- 3depict-0.0.12/src/drawables.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/drawables.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2039 +0,0 @@ -/* - * drawables.cpp - opengl drawable objects cpp file - * Copyright (C) 2012, 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 . -*/ - -#include "drawables.h" - -#include "colourmap.h" - -#include "isoSurface.h" - -#include -#include "mathfuncs.h" - -//OpenGL debugging macro -#if DEBUG -#include -#include -#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; \ -} -#else -#define glError() -#endif - -const float DEPTH_SORT_REORDER_EPSILON = 1e-2; - -//Static class variables -//==== -const Camera *DrawableObj::curCamera = 0; -//== - - -//Common functions -// -void drawBox(Point3D pMin, Point3D pMax, float r,float g, float b, float a) -{ - //TODO: Could speedup with LINE_STRIP/LOOP. This is - //not a bottleneck atm though. - glBegin(GL_LINES); - glColor4f(r,g,b,a); - //Bottom corner out (three lines from corner) - glVertex3f(pMin[0],pMin[1],pMin[2]); - glVertex3f(pMax[0],pMin[1],pMin[2]); - - glVertex3f(pMin[0],pMin[1],pMin[2]); - glVertex3f(pMin[0],pMax[1],pMin[2]); - - glVertex3f(pMin[0],pMin[1],pMin[2]); - glVertex3f(pMin[0],pMin[1],pMax[2]); - - //Top Corner out (three lines from corner) - glVertex3f(pMax[0],pMax[1],pMax[2]); - glVertex3f(pMin[0],pMax[1],pMax[2]); - - glVertex3f(pMax[0],pMax[1],pMax[2]); - glVertex3f(pMax[0],pMin[1],pMax[2]); - - glVertex3f(pMax[0],pMax[1],pMax[2]); - glVertex3f(pMax[0],pMax[1],pMin[2]); - - //Missing pieces - in an "across-down-across" shape - glVertex3f(pMin[0],pMax[1],pMin[2]); - glVertex3f(pMax[0],pMax[1],pMin[2]); - - glVertex3f(pMax[0],pMax[1],pMin[2]); - glVertex3f(pMax[0],pMin[1],pMin[2]); - - glVertex3f(pMax[0],pMin[1],pMin[2]); - glVertex3f(pMax[0],pMin[1],pMax[2]); - - glVertex3f(pMax[0],pMin[1],pMax[2]); - glVertex3f(pMin[0],pMin[1],pMax[2]); - - glVertex3f(pMin[0],pMin[1],pMax[2]); - glVertex3f(pMin[0],pMax[1],pMax[2]); - - glVertex3f(pMin[0],pMax[1],pMax[2]); - glVertex3f(pMin[0],pMax[1],pMin[2]); - glEnd(); -} - - -using std::vector; - -DrawableObj::DrawableObj() : active(true), haveChanged(true), canSelect(false), wantsLight(false) -{ -} - -DrawableObj::~DrawableObj() -{ -} - -//===== - -DrawPoint::DrawPoint() : origin(0.0f,0.0f,0.0f), r(1.0f), g(1.0f), b(1.0f), a(1.0f) -{ -} - -DrawPoint::DrawPoint(float x, float y, float z) : origin(x,y,z), r(1.0f), g(1.0f), b(1.0f) -{ -} - -DrawPoint::~DrawPoint() -{ -} - - - - -void DrawPoint::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - - - -void DrawPoint::setOrigin(const Point3D &pt) -{ - origin = pt; -} - - -void DrawPoint::draw() const -{ - glColor4f(r,g,b,a); - glBegin(GL_POINT); - glVertex3f(origin[0],origin[1],origin[2]); - glEnd(); -} - -DrawVector::DrawVector() : origin(0.0f,0.0f,0.0f), vector(0.0f,0.0f,1.0f),drawArrow(true), - arrowSize(1.0f),scaleArrow(true),doubleEnded(false), - r(1.0f), g(1.0f), b(1.0f), a(1.0f), lineSize(1.0f) -{ -} - -DrawVector::~DrawVector() -{ -} - - -void DrawVector::getBoundingBox(BoundCube &b) const -{ - b.setBounds(origin,vector+origin); -} - -void DrawVector::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - - -void DrawVector::setEnds(const Point3D &startNew, const Point3D &endNew) -{ - origin = startNew; - vector =endNew-startNew; -} - -void DrawVector::setOrigin(const Point3D &pt) -{ - origin = pt; -} - -void DrawVector::setVector(const Point3D &pt) -{ - vector= pt; -} - -void DrawVector::draw() const -{ - const unsigned int NUM_CONE_SEGMENTS=20; - const float numConeRadiiLen = 1.5f; - const float radius= arrowSize; - - glColor3f(r,g,b); - - //Disable lighting calculations for arrow stem - glPushAttrib(GL_LIGHTING_BIT); - glDisable(GL_LIGHTING); - float oldLineWidth; - glGetFloatv(GL_LINE_WIDTH,&oldLineWidth); - - glLineWidth(lineSize); - glBegin(GL_LINES); - - if(arrowSize < sqrt(std::numeric_limits::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(); - } - - - - - - //Now compute & draw the cone tip - //---- - - Point3D axis; - axis = vector; - - if(axis.sqrMag() < sqrt(std::numeric_limits::epsilon())) - axis=Point3D(0,0,1); - else - axis.normalise(); - - - //Tilt space to align to cone axis - Point3D zAxis(0,0,1); - float tiltAngle; - tiltAngle = zAxis.angle(axis); - - Point3D rotAxis; - rotAxis=zAxis.crossProd(axis); - - Point3D *ptArray = new Point3D[NUM_CONE_SEGMENTS]; - if(tiltAngle > sqrt(std::numeric_limits::epsilon()) && - rotAxis.sqrMag() > sqrt(std::numeric_limits::epsilon())) - { - - //Draw an angled cone - Point3f vertex,r; - rotAxis.normalise(); - - - r.fx=rotAxis[0]; - r.fy=rotAxis[1]; - r.fz=rotAxis[2]; - - - //we have to rotate the cone points around the apex point - for(unsigned int ui=0; ui sqrt(std::numeric_limits::epsilon())) - { - //Downwards pointing cone - for(unsigned int ui=0; ui &vecs, - const std::vector &scalars, unsigned int mode) -{ - switch(mode) - { - case DRAW_VECTOR_BIND_ORIENTATION: - ASSERT(vecs.size() ==1 && scalars.size() ==0); - vector=vecs[0]; - break; - case DRAW_VECTOR_BIND_ORIGIN: - ASSERT(vecs.size() == 1 && scalars.size()==0); - origin=vecs[0]; - break; - case DRAW_VECTOR_BIND_ORIGIN_ONLY: - { - ASSERT(vecs.size() == 1 && scalars.size()==0); - - Point3D dv; - dv=vector-origin; - origin=vecs[0]; - vector=origin+dv; - break; - } - case DRAW_VECTOR_BIND_TARGET: - ASSERT(vecs.size() == 1 && scalars.size()==0); - vector=vecs[0]-origin; - break; - default: - ASSERT(false); - } -} - - - -DrawTriangle::DrawTriangle() : r(1.0f), g(1.0f),b(1.0f),a(1.0f) -{ -} - -DrawTriangle::~DrawTriangle() -{ -} - -void DrawTriangle::setVertex(unsigned int ui, const Point3D &pt) -{ - ASSERT(ui < 3); - vertices[ui] = pt; -} - -void DrawTriangle::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - -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]); - glEnd(); -} - - -DrawSphere::DrawSphere() : radius(1.0f), latSegments(8),longSegments(8) -{ - q=gluNewQuadric(); -} - -DrawSphere::~DrawSphere() -{ - if(q) - gluDeleteQuadric(q); -} - - - -void DrawSphere::getBoundingBox(BoundCube &b) const -{ - for(unsigned int ui=0;ui<3;ui++) - { - b.setBound(ui,0,origin[ui] - radius); - b.setBound(ui,1,origin[ui] + radius); - } -} - -void DrawSphere::setOrigin(const Point3D &p) -{ - origin = p; -} - -void DrawSphere::setLatSegments(unsigned int ui) -{ - latSegments = ui; -} - -void DrawSphere::setLongSegments(unsigned int ui) -{ - longSegments = ui; -} - -void DrawSphere::setRadius(float rad) -{ - radius=rad; -} - -void DrawSphere::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - -void DrawSphere::draw() const -{ - if(!q) - return; - - glPushMatrix(); - glTranslatef(origin[0],origin[1],origin[2]); - glColor4f(r,g,b,a); - gluSphere(q,radius,latSegments,longSegments); - glPopMatrix(); -} - - -void DrawSphere::recomputeParams(const vector &vecs, - const vector &scalars, unsigned int mode) -{ - switch(mode) - { - case DRAW_SPHERE_BIND_ORIGIN: - ASSERT(vecs.size() ==1 && scalars.size() ==0); - origin=vecs[0]; - break; - case DRAW_SPHERE_BIND_RADIUS: - ASSERT(scalars.size() == 1 && vecs.size()==0); - radius=scalars[0]; - break; - default: - ASSERT(false); - } -} -//=========== - -DrawCylinder::DrawCylinder() : radius(1.0f), - origin(0.0f,0.0f,0.0f), direction(0.0f,0.0f,1.0f), slices(4),stacks(4) -{ - q= gluNewQuadric(); - qCap[0]= gluNewQuadric(); - if(qCap[0]) - gluQuadricOrientation(qCap[0],GLU_INSIDE); - qCap[1]= gluNewQuadric(); - if(qCap[1]) - gluQuadricOrientation(qCap[1],GLU_OUTSIDE); - radiiLocked=false; -} - -bool DrawCylinder::needsDepthSorting() const -{ - return a< 1 && a > std::numeric_limits::epsilon(); -} - -DrawCylinder::~DrawCylinder() -{ - if(q) - gluDeleteQuadric(q); - if(qCap[0]) - gluDeleteQuadric(qCap[0]); - if(qCap[1]) - gluDeleteQuadric(qCap[1]); -} - - -void DrawCylinder::setOrigin(const Point3D& pt) -{ - origin=pt; -} - - -void DrawCylinder::setDirection(const Point3D &p) -{ - direction=p; -} - - -void DrawCylinder::draw() const -{ - if(!q || !qCap[0] || !qCap[1]) - return; - - //Cross product desired drection with default - //direction to produce rotation vector - Point3D dir(0.0f,0.0f,1.0f); - - glPushMatrix(); - glTranslatef(origin[0],origin[1],origin[2]); - - Point3D dirNormal(direction); - dirNormal.normalise(); - - float length=sqrtf(direction.sqrMag()); - float angle = dir.angle(dirNormal); - if(angle < M_PI - sqrt(std::numeric_limits::epsilon()) && - angle > sqrt(std::numeric_limits::epsilon())) - { - //we need to rotate - dir = dir.crossProd(dirNormal); - - glRotatef(angle*180.0f/M_PI,dir[0],dir[1],dir[2]); - } - - //OpenGL defined cylinder starting at 0 and going to lenght. I want it starting at 0 and going to+-l/2 - glTranslatef(0,0,-length/2.0f); - glColor4f(r,g,b,a); - - //Draw the end cap at z=0 - if(radiiLocked) - { - gluDisk(qCap[0],0,radius,slices,1); - gluCylinder(q,radius,radius, length,slices,stacks); - - //Draw the start cap at z=l - glTranslatef(0,0,length); - gluDisk(qCap[1],0,radius,slices,1); - } - else - { - ASSERT(false); - } - - glPopMatrix(); -} - -void DrawCylinder::setSlices(unsigned int i) -{ - slices=i; -} - -void DrawCylinder::setStacks(unsigned int i) -{ - stacks=i; -} - -void DrawCylinder::setRadius(float rad) -{ - radius=rad; -} - -void DrawCylinder::recomputeParams(const vector &vecs, - const vector &scalars, unsigned int mode) -{ - switch(mode) - { - case DRAW_CYLINDER_BIND_ORIGIN: - ASSERT(vecs.size() ==1 && scalars.size() ==0); - origin=vecs[0]; - break; - - case DRAW_CYLINDER_BIND_DIRECTION: - ASSERT(vecs.size() ==1 && scalars.size() ==0); - direction=vecs[0]; - break; - case DRAW_CYLINDER_BIND_RADIUS: - ASSERT(scalars.size() == 1 && vecs.size()==0); - radius=scalars[0]; - break; - default: - ASSERT(false); - } -} - - -void DrawCylinder::setLength(float len) -{ - ASSERT(direction.sqrMag()); - direction=direction.normalise()*len; -} - -void DrawCylinder::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - -void DrawCylinder::getBoundingBox(BoundCube &b) const -{ - - float tmp; - - Point3D normAxis(direction); - normAxis.normalise(); - - //Height offset for ending circles. - //The joint bounding box of these two is the - //overall bounding box - Point3D offset; - - - - //X component - tmp=sin(acos(normAxis.dotProd(Point3D(1,0,0)))); - offset[0] = radius*tmp; - - //Y component - tmp=sin(acos(normAxis.dotProd(Point3D(0,1,0)))); - offset[1] = radius*tmp; - - //Z component - tmp=sin(acos(normAxis.dotProd(Point3D(0,0,1)))); - offset[2] = radius*tmp; - - vector p; - p.resize(4); - p[0]= offset+(direction*0.5+origin); - p[1]= -offset+(direction*0.5+origin); - p[2]= offset+(-direction*0.5+origin); - p[3]= -offset+(-direction*0.5+origin); - - b.setBounds(p); -} - - -//====== - -DrawManyPoints::DrawManyPoints() : r(1.0f),g(1.0f),b(1.0f),a(1.0f), size(1.0f) -{ - wantsLight=false; -} - -DrawManyPoints::~DrawManyPoints() -{ - wantsLight=false; - haveCachedBounds=false; -} - -void DrawManyPoints::getBoundingBox(BoundCube &b) const -{ - - //Update the cache as needed - if(!haveCachedBounds) - { - haveCachedBounds=true; - cachedBounds.setBounds(pts); - } - - b=cachedBounds; - return; -} - -void DrawManyPoints::explode(vector &simpleObjects) -{ - simpleObjects.resize(pts.size()); - - for(size_t ui=0;ui &vp) -{ - pts.reserve(pts.size()+vp.size()); - std::copy(vp.begin(),vp.end(),pts.begin()); - haveCachedBounds=false; -} - -/* -void DrawManyPoints::addPoints(const vector &vp) -{ - pts.reserve(pts.size()+vp.size()); - for(size_t ui=0; ui::epsilon()) - return; - - const Point3D *p; - glPointSize(size); - glBegin(GL_POINTS); - glColor4f(r,g,b,a); - //TODO: Consider Vertex buffer objects. would be faster, but less portable. - for(unsigned int ui=0; uigetValueArr()); - } - glEnd(); -} - -//====== - -DrawDispList::DrawDispList() : listNum(0),listActive(false) -{ -} - -DrawDispList::~DrawDispList() -{ - if(listNum) - { - ASSERT(!listActive); - ASSERT(glIsList(listNum)); - glDeleteLists(listNum,1); - } - -} - -bool DrawDispList::startList(bool execute) -{ - //Ensure that the user has appropriately closed the list - ASSERT(!listActive); - boundBox.setInverseLimits(); - - //If the list is already genned, clear it - if(listNum) - glDeleteLists(listNum,1); - - //Create the display list (ask for one) - listNum=glGenLists(1); - - if(listNum) - { - if(execute) - glNewList(listNum,GL_COMPILE_AND_EXECUTE); - else - glNewList(listNum,GL_COMPILE); - listActive=true; - } - return (listNum!=0); -} - -void DrawDispList::addDrawable(const DrawableObj *d) -{ - ASSERT(listActive); - BoundCube b; - d->getBoundingBox(b); - boundBox.expand(b); - d->draw(); -} - -bool DrawDispList::endList() -{ - glEndList(); - - ASSERT(boundBox.isValid()); - listActive=false; - return (glGetError() ==0); -} - -void DrawDispList::draw() const -{ - ASSERT(!listActive); - - //Cannot select display list objects, - //as we cannot modify them without a "do-over". - ASSERT(!canSelect); - - ASSERT(glIsList(listNum)); - //Execute the list - glPushMatrix(); - glCallList(listNum); - glPopMatrix(); -} - -//======== - - -DrawGLText::DrawGLText(std::string fontFile, unsigned int mode) :font(0),fontString(fontFile), - curFontMode(mode), origin(0.0f,0.0f,0.0f), - r(0.0),g(0.0),b(0.0),a(1.0), up(0.0f,1.0f,0.0f), - textDir(1.0f,0.0f,0.0f), readDir(0.0f,0.0f,1.0f), - isOK(true),ensureReadFromNorm(true) -{ - - font=0; - switch(mode) - { - case FTGL_BITMAP: - font = new FTGLBitmapFont(fontFile.c_str()); - break; - case FTGL_PIXMAP: - font = new FTGLPixmapFont(fontFile.c_str()); - break; - case FTGL_OUTLINE: - font = new FTGLOutlineFont(fontFile.c_str()); - break; - case FTGL_POLYGON: - font = new FTGLPolygonFont(fontFile.c_str()); - break; - case FTGL_EXTRUDE: - font = new FTGLExtrdFont(fontFile.c_str()); - break; - case FTGL_TEXTURE: - font = new FTGLTextureFont(fontFile.c_str()); - break; - default: - //Don't do this. Use valid font numbers - ASSERT(false); - font=0; - } - - //In case of allocation failure or invalid font num - if(!font || font->Error()) - { - isOK=false; - return; - } - - //Try to make it 100 point - font->FaceSize(5); - font->Depth(20); - - //Use unicode - font->CharMap(ft_encoding_unicode); - - alignMode = DRAWTEXT_ALIGN_LEFT; -} - -DrawGLText::DrawGLText(const DrawGLText &oth) : font(0), fontString(oth.fontString), - curFontMode(oth.curFontMode), origin(oth.origin), r(oth.r), - g(oth.g), b(oth.b), a(oth.a), up(oth.up), textDir(oth.textDir), - readDir(oth.readDir),isOK(oth.isOK), ensureReadFromNorm(oth.ensureReadFromNorm) -{ - - font=0; - switch(curFontMode) - { - case FTGL_BITMAP: - font = new FTGLBitmapFont(fontString.c_str()); - break; - case FTGL_PIXMAP: - font = new FTGLPixmapFont(fontString.c_str()); - break; - case FTGL_OUTLINE: - font = new FTGLOutlineFont(fontString.c_str()); - break; - case FTGL_POLYGON: - font = new FTGLPolygonFont(fontString.c_str()); - break; - case FTGL_EXTRUDE: - font = new FTGLExtrdFont(fontString.c_str()); - break; - case FTGL_TEXTURE: - font = new FTGLTextureFont(fontString.c_str()); - break; - default: - //Don't do this. Use valid font numbers - ASSERT(false); - font=0; - } - - //In case of allocation failure or invalid font num - if(!font || font->Error()) - { - isOK=false; - return; - } - - //Try to make it 100 point - font->FaceSize(5); - font->Depth(20); - //Use unicode - font->CharMap(ft_encoding_unicode); -} - -void DrawGLText::draw() const -{ - if(!isOK) - return; - - //Translate the drawing position to the origin - Point3D offsetVec=textDir; - float advance; - float halfHeight; - - FTBBox box; - box=font->BBox(strText.c_str()); - advance=box.Upper().X()-box.Lower().X(); - - halfHeight=box.Upper().Y()-box.Lower().Y(); - halfHeight/=2.0f; - - switch(alignMode) - { - case DRAWTEXT_ALIGN_LEFT: - break; - case DRAWTEXT_ALIGN_CENTRE: - offsetVec=offsetVec*advance/2.0f; - break; - case DRAWTEXT_ALIGN_RIGHT: - offsetVec=offsetVec*advance; - break; - default: - ASSERT(false); - } - - - glPushMatrix(); - - - glPushAttrib(GL_CULL_FACE); - - glDisable(GL_CULL_FACE); - if(curFontMode !=FTGL_BITMAP) - { - offsetVec=origin-offsetVec; - glTranslatef(offsetVec[0],offsetVec[1],offsetVec[2]); - - //Rotate such that the new X-Y plane is set to the - //desired text orientation. (ie. we want to draw the text in the - //specified combination of updir-textdir, rather than in the X-y plane) - - //--- - //Textdir and updir MUST be normal to one another - ASSERT(textDir.dotProd(up) < sqrtf(std::numeric_limits::epsilon())); - - //rotate around textdir cross X, if the two are not the same - Point3D rotateAxis; - Point3D newUp=up; - float angle=textDir.angle(Point3D(1,0,0) ); - if(angle > sqrtf(std::numeric_limits::epsilon())) - { - rotateAxis = textDir.crossProd(Point3D(-1,0,0)); - rotateAxis.normalise(); - - Point3f tmp,axis; - tmp.fx=up[0]; - tmp.fy=up[1]; - tmp.fz=up[2]; - - axis.fx=rotateAxis[0]; - axis.fy=rotateAxis[1]; - axis.fz=rotateAxis[2]; - - - glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]); - quat_rot(&tmp,&axis,angle); //angle is in radiians - - newUp[0]=tmp.fx; - newUp[1]=tmp.fy; - newUp[2]=tmp.fz; - } - - //rotate new up direction into y around x axis - angle = newUp.angle(Point3D(0,1,0)); - if(angle > sqrtf(std::numeric_limits::epsilon()) && - fabs(angle - M_PI) > sqrtf(std::numeric_limits::epsilon())) - { - rotateAxis = newUp.crossProd(Point3D(0,-1,0)); - rotateAxis.normalise(); - glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]); - } - - //Ensure that the text is not back-culled (i.e. if the - //text normal is pointing away from the camera, it does not - //get drawn). Here we have to flip the normal, by spinning the - //text by 180 around its up direction (which has been modified - //by above code to coincide with the y axis. - if(curCamera) - { - //This is not *quite* right in perspective mode - //but is right in orthogonal - - Point3D textNormal,camVec; - textNormal = up.crossProd(textDir); - textNormal.normalise(); - - camVec = origin - curCamera->getOrigin(); - - //ensure the camera is not sitting on top of the text. - if(camVec.sqrMag() > std::numeric_limits::epsilon()) - { - - camVec.normalise(); - - if(camVec.dotProd(textNormal) < 0) - { - //move halfway along text, noting that - //the text direction is now the x-axis - glTranslatef(advance/2.0f,halfHeight,0); - //spin text around its up direction 180 degrees - glRotatef(180,0,1,0); - //restore back to original position - glTranslatef(-advance/2.0f,-halfHeight,0); - } - - camVec=curCamera->getUpDirection(); - if(camVec.dotProd(up) < 0) - { - //move halfway along text, noting that - //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 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 - glTranslatef(-advance/2.0f,-halfHeight,0); - } - - } - - - } - - } - else - { - //FIXME: The text ends up in a wierd location - //2D coordinate storage for bitmap text - double xWin,yWin,zWin; - //Compute the 2D coordinates - double model_view[16]; - glGetDoublev(GL_MODELVIEW_MATRIX, model_view); - - double projection[16]; - glGetDoublev(GL_PROJECTION_MATRIX, projection); - - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - - //Apply the openGL coordinate transformation pipleine to the - //specified coords - gluProject(offsetVec[0],offsetVec[1],offsetVec[2] - ,model_view,projection,viewport, - &xWin,&yWin,&zWin); - - glRasterPos3f(xWin,yWin,zWin); - - } - //--- - - - glColor4f(r,g,b,a); - - //Draw text - if(curFontMode == FTGL_TEXTURE) - { - glPushAttrib(GL_ENABLE_BIT); - glEnable(GL_TEXTURE_2D); - - font->Render(strText.c_str()); - glPopAttrib(); - } - else - font->Render(strText.c_str()); - - glPopAttrib(); - - glPopMatrix(); -} - -DrawGLText::~DrawGLText() -{ - if(font) - delete font; -} - -void DrawGLText::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - -void DrawGLText::getBoundingBox(BoundCube &b) const -{ - - if(isOK) - { - float minX,minY,minZ; - float maxX,maxY,maxZ; - font->BBox(strText.c_str(),minX,minY,minZ,maxX,maxY,maxZ); - b.setBounds(minX+origin[0],minY+origin[1],minZ+origin[2], - maxX+origin[0],maxY+origin[1],maxZ+origin[2]); - } - else - b.setInverseLimits(); - -} - -void DrawGLText::setAlignment(unsigned int newMode) -{ - ASSERT(newMode < DRAWTEXT_ALIGN_ENUM_END); - alignMode=newMode; -} - -void DrawGLText::recomputeParams(const vector &vecs, - const vector &scalars, unsigned int mode) -{ - switch(mode) - { - case DRAW_TEXT_BIND_ORIGIN: - ASSERT(vecs.size() ==1 && scalars.size() ==0); - origin=vecs[0]; - break; - default: - ASSERT(false); - } -} - -DrawRectPrism::DrawRectPrism() : drawMode(DRAW_WIREFRAME), r(1.0f), g(1.0f), b(1.0f), a(1.0f), lineWidth(1.0f) -{ -} - -DrawRectPrism::~DrawRectPrism() -{ -} - -void DrawRectPrism::getBoundingBox(BoundCube &b) const -{ - b.setBounds(pMin[0],pMin[1],pMin[2], - pMax[0],pMax[1],pMax[2]); -} - -void DrawRectPrism::draw() const -{ - ASSERT(r <=1.0f && g<=1.0f && b <=1.0f && a <=1.0f); - ASSERT(r >=0.0f && g>=0.0f && b >=0.0f && a >=0.0f); - - if(!active) - return; - - switch(drawMode) - { - case DRAW_WIREFRAME: - { - glLineWidth(lineWidth); - drawBox(pMin,pMax,r,g,b,a); - break; - } - case DRAW_FLAT: - { - glBegin(GL_QUADS); - glColor4f(r,g,b,a); - - glNormal3f(0,0,-1); - //Along the bottom - glVertex3f(pMin[0],pMin[1],pMin[2]); - glVertex3f(pMin[0],pMax[1],pMin[2]); - glVertex3f(pMax[0],pMax[1],pMin[2]); - glVertex3f(pMax[0],pMin[1],pMin[2]); - //Up the side - glNormal3f(1,0,0); - glVertex3f(pMax[0],pMax[1],pMax[2]); - glVertex3f(pMax[0],pMin[1],pMax[2]); - glVertex3f(pMax[0],pMin[1],pMin[2]); - glVertex3f(pMax[0],pMax[1],pMin[2]); - //Over the top - glNormal3f(0,0,1); - glVertex3f(pMax[0],pMin[1],pMax[2]); - glVertex3f(pMax[0],pMax[1],pMax[2]); - glVertex3f(pMin[0],pMax[1],pMax[2]); - glVertex3f(pMin[0],pMin[1],pMax[2]); - - //and back down - glNormal3f(-1,0,0); - glVertex3f(pMin[0],pMax[1],pMin[2]); - glVertex3f(pMin[0],pMin[1],pMin[2]); - glVertex3f(pMin[0],pMin[1],pMax[2]); - glVertex3f(pMin[0],pMax[1],pMax[2]); - - //Now the other two sides - glNormal3f(0,-1,0); - glVertex3f(pMax[0],pMin[1],pMax[2]); - glVertex3f(pMin[0],pMin[1],pMax[2]); - glVertex3f(pMin[0],pMin[1],pMin[2]); - glVertex3f(pMax[0],pMin[1],pMin[2]); - - glNormal3f(0,1,0); - glVertex3f(pMax[0],pMax[1],pMax[2]); - glVertex3f(pMax[0],pMax[1],pMin[2]); - glVertex3f(pMin[0],pMax[1],pMin[2]); - glVertex3f(pMin[0],pMax[1],pMax[2]); - - glEnd(); - - break; - - } - default: - ASSERT(false); - } - - -} - -void DrawRectPrism::setAxisAligned( const Point3D &p1, const Point3D &p2) -{ - for(unsigned int ui=0; ui<3; ui++) - { - pMin[ui]=std::min(p1[ui],p2[ui]); - pMax[ui]=std::max(p1[ui],p2[ui]); - } - -} - -void DrawRectPrism::setAxisAligned( const BoundCube &b) -{ - b.getBounds(pMin,pMax); -} - -void DrawRectPrism::setColour(float rnew, float gnew, float bnew, float anew) -{ - r=rnew; - g=gnew; - b=bnew; - a=anew; -} - -void DrawRectPrism::setLineWidth(float newLineWidth) -{ - ASSERT(newLineWidth > 0.0f); - lineWidth=newLineWidth; -} - -void DrawRectPrism::recomputeParams(const vector &vecs, - const vector &scalars, unsigned int mode) -{ - switch(mode) - { - case DRAW_RECT_BIND_TRANSLATE: - { - ASSERT(vecs.size() ==1); - Point3D delta; - delta = (pMax - pMin)*0.5; - //Object has been translated - pMin = vecs[0]-delta; - pMax = vecs[0]+delta; - break; - } - case DRAW_RECT_BIND_CORNER_MOVE: - { - ASSERT(vecs.size() ==1); - //Delta has changed, but origin shoudl stay the same - Point3D mean, corner; - mean = (pMin + pMax)*0.5; - - //Prevent negative offset values, otherwise we can - //get inside out boxes - corner=vecs[0]; - for(unsigned int ui=0;ui<3;ui++) - corner[ui]= fabs(corner[ui]); - - pMin = mean-corner; - pMax = mean+corner; - break; - } - default: - ASSERT(false); - } -} - -DrawTexturedQuadOverlay::DrawTexturedQuadOverlay() : texPool(0) -{ -} - -DrawTexturedQuadOverlay::~DrawTexturedQuadOverlay() -{ -#ifdef DEBUG - textureOK=false; -#endif -} - -void DrawTexturedQuadOverlay::setSize(float s) -{ - length=s; -} - - -void DrawTexturedQuadOverlay::draw() const -{ - if(!textureOK) - return; - - ASSERT(glIsTexture(textureId)); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D(0, winX, winY, 0); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,textureId); - - // Draw overlay quad - glColor3f(1.0f,1.0f,1.0f); - glBegin(GL_QUADS); - glTexCoord2f(0.0f,0.0f); - glVertex3f(position[0]-length/2.0,position[1]-length/2.0,0.0); - glTexCoord2f(0.0f,1.0f); - glVertex3f(position[0]-length/2.0,position[1]+length/2.0,0.0); - glTexCoord2f(1.0f,1.0f); - glVertex3f(position[0]+length/2.0,position[1]+length/2.0,0.0); - glTexCoord2f(1.0f,0.0f); - glVertex3f(position[0]+length/2.0,position[1]-length/2.0,0.0); - glEnd(); - - glDisable(GL_TEXTURE_2D); - /* draw stuff */ - - glPopMatrix(); //Pop modelview matrix - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); -} - - -bool DrawTexturedQuadOverlay::setTexture(const char *textureFile) -{ - ASSERT(texPool); - unsigned int dummy; - - textureOK= texPool->openTexture(textureFile,textureId,dummy); - return textureOK; -} - -void DrawTexturedQuadOverlay::getBoundingBox(BoundCube &b) const -{ - b.setInvalid(); -} - - -DrawColourBarOverlay::DrawColourBarOverlay() -{ - a=1.0; - string f; - f=getDefaultFontFile(); - font = new FTGLPolygonFont(f.c_str()); -}; - -DrawColourBarOverlay::DrawColourBarOverlay(const DrawColourBarOverlay &oth) -{ - string f; - f=getDefaultFontFile(); - - font = new FTGLPolygonFont(f.c_str()); - a=oth.a; - - rgb=oth.rgb; - min=oth.min; - max=oth.max; - - height=oth.height; - width=oth.width; - - tlX=oth.tlX; - tlY=oth.tlY; -}; - -void DrawColourBarOverlay::draw() const -{ - //Draw quads - float elemHeight; - //80% of bar width is for the actual colour bar itself. - float barWidth=0.8*width; - elemHeight=height/(float)rgb.size(); - glBegin(GL_QUADS); - for(unsigned int ui=0;uiError()) - { -#ifdef DEBUG - std::cerr << "Ah bugger. No font!" << std::endl; -#endif - return; - } - - - - //FTGL units are a pain; The devs could not decide - //whether to implement them in opengl coords or real coords - //so they did neither, and implemented them in "points". - //here we assume that we can transform 1 ftgl unit - //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(); - glTranslatef(tlX+width,tlY,0); - string s; - stream_cast(s,max); - //Note negative sign to flip from y-down screen (opengl) to text dir - //(y up) - glScaled(FTGL_DEFAULT_UNIT_SCALE, - -FTGL_DEFAULT_UNIT_SCALE,FTGL_DEFAULT_UNIT_SCALE); - font->Render(s.c_str()); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(tlX+width,tlY+height,0); - stream_cast(s,min); - //Note negative sign to flip from y-down screen (opengl) to text dir - //(y up) - glScaled(FTGL_DEFAULT_UNIT_SCALE, - -FTGL_DEFAULT_UNIT_SCALE,FTGL_DEFAULT_UNIT_SCALE); - font->Render(s.c_str()); - glPopMatrix(); - glEnable(GL_CULL_FACE); - - - -} - -void DrawColourBarOverlay::setColourVec(const vector &r, - const vector &g, - const vector &b) -{ - ASSERT(r.size() == g.size()); - ASSERT(g.size() == b.size()); - rgb.resize(r.size()); - for(unsigned int ui=0;uigetMinBounds(),field->getMaxBounds()); -} - - -void DrawField3D::setField(const Voxels *newField) -{ - field=newField; -} - -void DrawField3D::setRenderMode(unsigned int mode) -{ - volumeRenderMode=mode; -} - -void DrawField3D::setColourMinMax() -{ - colourMapBound[0]=field->min(); - colourMapBound[1]=field->max(); - - ASSERT(colourMapBound[0] <=colourMapBound[1]); -} - - -void DrawField3D::draw() const -{ - if(alphaVal < sqrt(std::numeric_limits::epsilon())) - return; - - ASSERT(field); - - //Depend upon the render mode - switch(volumeRenderMode) - { - case VOLUME_POINTS: - { - size_t fieldSizeX,fieldSizeY,fieldSizeZ; - Point3D p; - - field->getSize(fieldSizeX,fieldSizeY, fieldSizeZ); - - Point3D delta; - delta = field->getPitch(); - delta*=0.5; - if(!ptsCacheOK) - { - ptsCache.clear(); - for(unsigned int uiX=0; uiXgetData(uiX,uiY,uiZ); - if(v > std::numeric_limits::epsilon()) - { - RGBThis rgb; - //Set colour and point loc - colourMapWrap(colourMapID,rgb.v, - field->getData(uiX,uiY,uiZ), - colourMapBound[0],colourMapBound[1]); - - ptsCache.push_back(make_pair(field->getPoint(uiX,uiY,uiZ)+delta,rgb)); - } - } - } - } - - - ptsCacheOK=true; - } - - if(alphaVal < 1.0f) - { - //We need to generate some points, then sort them by distance - //from eye (back to front), otherwise they will not blend properly - std::vector > eyeDists; - - Point3D camOrigin = curCamera->getOrigin(); - - eyeDists.resize(ptsCache.size()); - - //Set up an original index for the eye distances - #pragma omp parallel for - for(unsigned int ui=0;uigetMinBounds(),field->getMaxBounds(), - boxColourR, boxColourG,boxColourB,boxColourA); - } - //Draw the projections -} - -void DrawField3D::setAlpha(float newAlpha) -{ - alphaVal=newAlpha; -} - -void DrawField3D::setPointSize(float size) -{ - pointSize=size; -} - -void DrawField3D::setMapColours(unsigned int mapID) -{ - ASSERT(mapID < NUM_COLOURMAPS); - colourMapID= mapID; -} - -void DrawField3D::setBoxColours(float rNew, float gNew, float bNew, float aNew) -{ - boxColourR = rNew; - boxColourG = gNew; - boxColourB = bNew; - boxColourA = aNew; - -} - - -DrawIsoSurface::DrawIsoSurface() : cacheOK(false), drawMode(DRAW_SMOOTH), - threshold(0.5f), r(0.5f), g(0.5f), b(0.5f), a(0.5f) -{ -#ifdef DEBUG - voxels=0; -#endif -} - -DrawIsoSurface::~DrawIsoSurface() -{ - if(voxels) - delete voxels; -} - - -bool DrawIsoSurface::needsDepthSorting() const -{ - return a< 1 && a > std::numeric_limits::epsilon(); -} - -void DrawIsoSurface::swapVoxels(Voxels *f) -{ - std::swap(f,voxels); - cacheOK=false; - mesh.clear(); -} - - -void DrawIsoSurface::updateMesh() const -{ - - mesh.clear(); - marchingCubes(*voxels, threshold,mesh); - - cacheOK=true; - -} - -void DrawIsoSurface::getBoundingBox(BoundCube &b) const -{ - if(voxels) - { - b.setBounds(voxels->getMinBounds(), - voxels->getMaxBounds()); - } - else - b.setInverseLimits(); -} - - -void DrawIsoSurface::draw() const -{ - if(a< sqrt(std::numeric_limits::epsilon())) - return; - - if(!cacheOK) - { - //Hmm, we don't have a cached copy of the isosurface mesh. - //we will need to compute one, it would seem. - updateMesh(); - } - - - //This could be optimised by using triangle strips - //rather than direct triangles. - if(a < 1.0f) - { - //We need to sort them by distance - //from eye (back to front), otherwise they will not blend properly - std::vector > eyeDists; - - Point3D camOrigin = curCamera->getOrigin(); - eyeDists.resize(mesh.size()); - - //Set up an original index for the eye distances - #pragma omp parallel for shared(camOrigin) - for(unsigned int ui=0;ui. -*/ - -#ifndef DRAWABLES_H -#define DRAWABLES_H - -#include "textures.h" -#include "cameras.h" -#include "voxels.h" -#include "isoSurface.h" -#include "basics.h" - -//STL includes -#include -#include - - - - -//MacOS is "special" and puts it elsewhere -#ifdef __APPLE__ - #include -#else - #include -#endif - -//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) -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 -#include -#include - -enum -{ - FTGL_BITMAP=0, - FTGL_PIXMAP, - FTGL_OUTLINE, - FTGL_POLYGON, - FTGL_EXTRUDE, - FTGL_TEXTURE -}; - -//!Text aligment modes for DrawGLText -enum -{ - DRAWTEXT_ALIGN_LEFT, - DRAWTEXT_ALIGN_CENTRE, - DRAWTEXT_ALIGN_RIGHT, - DRAWTEXT_ALIGN_ENUM_END -}; - - -//!Primitve drawing mode. (wireframe/solid) -enum -{ - DRAW_WIREFRAME, - DRAW_FLAT, - DRAW_SMOOTH, - DRAW_END_ENUM //Not a mode, just a marker to catch end-of-enum -}; - -//!Axis styles -enum -{ - AXIS_IN_SPACE -}; - -//!Drawable types -enum -{ - DRAW_TYPE_POINT, - DRAW_TYPE_MANYPOINT, - DRAW_TYPE_VECTOR, - DRAW_TYPE_TRIANGLE, - DRAW_TYPE_QUAD, - DRAW_TYPE_SPHERE, - DRAW_TYPE_CYLINDER, - DRAW_TYPE_DISPLAYLIST, - DRAW_TYPE_GLTEXT, - DRAW_TYPE_RECTPRISM, - DRAW_TYPE_COLOURBAR, - DRAW_TYPE_TEXTUREDOVERLAY, - DRAW_TYPE_FIELD3D, - DRAW_TYPE_ISOSURFACE, - DRAW_TYPE_AXIS, -}; - - -//!Binding enums. Needed to bind drawable selection -//to internal modification actions inside the drawable -enum -{ - DRAW_SPHERE_BIND_ORIGIN, - DRAW_SPHERE_BIND_RADIUS, - DRAW_VECTOR_BIND_ORIENTATION, - DRAW_VECTOR_BIND_ORIGIN_ONLY, - DRAW_VECTOR_BIND_ORIGIN, - DRAW_VECTOR_BIND_TARGET, - DRAW_CYLINDER_BIND_ORIGIN, - DRAW_CYLINDER_BIND_DIRECTION, - DRAW_CYLINDER_BIND_RADIUS, - DRAW_RECT_BIND_TRANSLATE, - DRAW_RECT_BIND_CORNER_MOVE, - DRAW_TEXT_BIND_ORIGIN, - //DRAW_TEXT_BIND_TEXTDIR, //FIXME: Implement me for annotation todo. - //DRAW_TEXT_BIND_UPDIR, - DRAW_BIND_ENUM_END -}; - - - -//!An abstract bas class for drawing primitives -class DrawableObj -{ - protected: - //!Is the drawable active? - bool active; - - //!Is the object changed since last set? - bool haveChanged; - //!Pointer to current scene camera - static const Camera *curCamera; - - public: - //!Can be selected from openGL viewport interactively? - bool canSelect; - - //!Wants lighting calculations active during render? - bool wantsLight; - - //!Is this an overlay? By default, no - virtual bool isOverlay() const { return false;} - - //!Constructor - DrawableObj(); - - virtual unsigned int getType() const =0; - - //!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;}; - - //!Break object down into simple elements - virtual void explode(std::vector &simpleObjects){ ASSERT(isExplodable()); }; - - virtual bool hasChanged() const { return haveChanged; } - - - //!Set the active state of the object - void setActive(bool active); - //!Pure virtual funciton - draw the object - virtual void draw() const =0; - - //!Set if user can interact with object, needed for opengl hit testing - void setInteract(bool canAct){canSelect=canAct;}; - - virtual void getBoundingBox(BoundCube &b) const = 0; - //!Drawable destructor - virtual ~DrawableObj(); - - //!If we offer any kind of external pointer interface; use this to do a recomputation as needed. This is needed for selection binding behaviour - virtual void recomputeParams(const vector &vecs, const vector &scalars, unsigned int mode) {}; - - //!Set the current camera - static void setCurCamera(const Camera *c){curCamera=c;}; - - //!Get the centre of the object. Only valid if object is simple - virtual Point3D getCentroid() const {ASSERT(!isExplodable());} ; - - // virtual DrawableObj *clone() const; - -}; - -//A single point drawing class -class DrawPoint : public DrawableObj -{ - protected: - //!Point origin - Point3D origin; - //!Point colour (r,g,b,a) range: [0.0f,1.0f] - float r,g,b,a; - public: - //!Constructor - DrawPoint(); - //!Constructor that takes in positional argments - DrawPoint(float,float,float); - //!Destructor - virtual ~DrawPoint(); - - //!Sets the color of the point to be drawn - void setColour(float r, float g, float b, float alpha); - //!Draws the points - void draw() const; - //!Sets the location of the poitns - void setOrigin(const Point3D &); - - void getBoundingBox(BoundCube &b) const { b.setInvalid();}; - - Point3D getCentroid() const{ return origin;} -}; - -//!A point drawing class - for many points of same size & colour -class DrawManyPoints : public DrawableObj -{ - protected: - //!Vector of points to draw - std::vector pts; - //!Point colours (r,g,b,a) range: [0.0f,1.0f] - float r,g,b,a; - //!Size of the point - float size; - - mutable bool haveCachedBounds; - mutable BoundCube cachedBounds; - public: - //!Constructor - DrawManyPoints(); - //!Destructor - virtual ~DrawManyPoints(); - - virtual unsigned int getType() const {return DRAW_TYPE_MANYPOINT;}; - //!Swap out the internal vector with an extenal one - void swap(std::vector &); - //!Remove all points - void clear(); - //!Add points into the drawing vector - void addPoints(const std::vector &); - //!Add a single point into the drawing vector, at a particular offset - // *must call resize first* - void setPoint(size_t offset,const Point3D &); - - //!Reset the number of many points to draw - void resize(size_t newSize); - //! set the color of the points to be drawn - void setColour(float r, float g, float b, float alpha); - //!Set the display size of the drawn poitns - void setSize(float); - //!Draw the points - void draw() const; - - //!Shuffle the points to remove anisotropic drawing effects. Thus must be done prior to draw call. - void shuffle(); - //!Get the bounding box that encapuslates this object - void getBoundingBox(BoundCube &b) const; - - //!return number of points - size_t getNumPts() const { return pts.size();}; - - //!This object is explodable - bool isExplodable() const { return true;} - - //!Explode object into simple point drawables - void explode(vector &simpleObjects); -}; - -//!Draw a vector -class DrawVector: public DrawableObj -{ - protected: - //!Vector origin - Point3D origin; - Point3D vector; - - //!Do we draw the arrow head? - bool drawArrow; - - //!Radius of tail of arrow - float arrowSize; - - //!Scale arrow head by vector size - bool scaleArrow; - - //!Whether to draw the arrow head at both ends - bool doubleEnded; - - //!Vector colour (r,g,b,a) range: [0.0f,1.0f] - float r,g,b,a; - - //!Size of "tail" line to draw - float lineSize; - public: - //!Constructor - DrawVector(); - //!Destructor - virtual ~DrawVector(); - - virtual unsigned int getType() const {return DRAW_TYPE_VECTOR;}; - - //!Set if we want to draw the arrow or not - void setDrawArrow(bool wantDraw) { drawArrow=wantDraw;} - //!Sets the color of the point to be drawn - void setColour(float r, float g, float b, float alpha); - //!Draws the points - void draw() const; - //!Sets the location of the poitns - void setOrigin(const Point3D &); - //!Sets the location of the poitns - void setVector(const Point3D &); - - //Set the start/end of vector in one go - void setEnds(const Point3D &start, const Point3D &end); - - //Set to draw both ends - void setDoubleEnded(bool wantDoubleEnd=true); - - //!Gets the arrow axis direction - Point3D getVector() const { return vector;}; - - //!Gets the arrow axis direction - Point3D getOrigin() const{ return origin;}; - - //!Set the arrowhead size - void setArrowSize(float size) { arrowSize=size;} - - //!Set the "tail" line size - void setLineSize(float size) { lineSize=size;} - void getBoundingBox(BoundCube &b) const; - - - //!Recompute the internal parameters using the input vector information - void recomputeParams(const std::vector &vecs, - const std::vector &scalars, unsigned int mode); - -}; - -//! A single colour triangle -class DrawTriangle : public DrawableObj -{ - protected: - //!The vertices of the triangle - Point3D vertices[3]; - Point3D vertNorm[3]; - //!Colour data - red, green, blue, alpha - float r,g,b,a; - public: - //!Constructor - DrawTriangle(); - //!Destructor - virtual ~DrawTriangle(); - - virtual unsigned int getType() const {return DRAW_TYPE_TRIANGLE;}; - - //!Set one of three vertices (0-2) locations - void setVertex(unsigned int, const Point3D &); - //!Set the vertex normals - void setVertexNorm(unsigned int, const Point3D &); - //!Set the colour of the triangle - void setColour(float r, float g, float b, float a); - //!Draw the triangle - void draw() const; - //!Get bounding cube - void getBoundingBox(BoundCube &b) const { b.setBounds(vertices,3);} -}; - -//!A smooth coloured quad -/* According to openGL, the quad's vertices need not be coplanar, - * but they must be convex - */ -class DrawQuad : public DrawableObj -{ - private: - //!Vertices of the quad - Point3D vertices[4]; - - //!Colour data for the quad - //!The lighting normal of the triangle - /*! 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(); - //!Destructor - virtual ~DrawQuad(); - - virtual unsigned int getType() const {return DRAW_TYPE_QUAD;}; - //!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 &); - //!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 - /*!Uses the first 3 vertices to calculate the normal. - */ - void calcNormal(); - //!Draw the triangle - void draw() const; - //!Get bounding cube - void getBoundingBox(BoundCube &b) const { return b.setBounds(vertices,4);} -}; - -//!A sphere drawing -class DrawSphere : public DrawableObj -{ - protected: - - //!Pointer to the GLU quadric doohicker - GLUquadricObj *q; - //!Origin of the object - Point3D origin; - //!Colour data - rgba - float r,g,b,a; - //!Sphere radius - float radius; - //!Number of lateral and longitudinal segments - unsigned int latSegments,longSegments; - public: - //!Default Constructor - DrawSphere(); - //! Destructor - virtual ~DrawSphere(); - - virtual unsigned int getType() const {return DRAW_TYPE_SPHERE;}; - //!Sets the location of the sphere's origin - void setOrigin(const Point3D &p); - //!Gets the location of the sphere's origin - Point3D getOrigin() const { return origin;}; - //!Set the number of lateral segments - void setLatSegments(unsigned int); - //!Set the number of longitudinal segments - void setLongSegments(unsigned int); - //!Set the radius - void setRadius(float); - //!get the radius - float getRadius() const { return radius;}; - //!Set the colour (rgba) of the object - void setColour(float r,float g,float b,float a); - //!Draw the sphere - void draw() const; - //!Get the bounding box that encapuslates this object - void getBoundingBox(BoundCube &b) const ; - - //!Recompute the internal parameters using the input vector information - // i.e. this is used for (eg) mouse interaction - void recomputeParams(const vector &vecs, - const vector &scalars, unsigned int mode); - -}; - -//!A tapered cylinder drawing class -class DrawCylinder : public DrawableObj -{ - protected: - //!Pointer to quadric, required for glu. Note the caps are defined as well - GLUquadricObj *q,*qCap[2]; - //!Colours for cylinder - float r,g,b,a; - //!Cylinder start and end radii - float radius; - //!Length of the cylinder - float length; - - //!Origin of base and direction of cylinder - Point3D origin, direction; - //!number of sectors (pie slices) - unsigned int slices; - //!number of vertical slices (should be 1 if endradius equals start radius - unsigned int stacks; - - //!Do we lock the drawing to only use the first radius? - bool radiiLocked; - public: - //!Constructor - DrawCylinder(); - //!Destructor - virtual ~DrawCylinder(); - - virtual unsigned int getType() const {return DRAW_TYPE_CYLINDER;}; - //!Set the location of the base of the cylinder - void setOrigin(const Point3D &pt); - //!Number of cuts perpendicular to axis - ie disks - void setSlices(unsigned int i); - //!Number of cuts along axis - ie segments - void setStacks(unsigned int i); - - //!Gets the location of the origin - Point3D getOrigin() const { return origin;}; - //!Gets the cylinder axis direction - Point3D getDirection() const{ return direction;}; - //!Set end radius - void setRadius(float val); - //!get the radius - float getRadius() const { return radius;}; - //!Set the orientation of cylinder - void setDirection(const Point3D &pt); - //!Set the length of cylinder - void setLength(float len); - //!Set the color of the cylinder - void setColour(float r,float g,float b,float a); - - //!Draw the clyinder - void draw() const; - //!Get the bounding box that encapuslates this object - void getBoundingBox(BoundCube &b) const ; - - //!Recompute the internal parameters using the input vector information - void recomputeParams(const vector &vecs, const vector &scalars, unsigned int mode); - - virtual bool needsDepthSorting() const; - - - - //!Lock (or unlock) the radius to the start radius (i.e. synch the two) - void lockRadii(bool doLock=true) {radiiLocked=doLock;}; -}; - -//!Drawing mode enumeration for scalar field -enum -{ - VOLUME_POINTS=0 -}; - -//!A display list generating class -/*! This class allows for the creation of display lists for openGL objects - * You can use this class to create a display list which will allow you to - * reference cached openGL calls already stored in the video card. - * This can be used to reduce the overhead in the drawing routines - */ -class DrawDispList : public DrawableObj -{ - private: - //!Static variable for the next list number to generate - unsigned int listNum; - //!True if the list is active (collecting/accumulating) - bool listActive; - //!Bounding box of objects in display list - BoundCube boundBox; - public: - //!Constructor - DrawDispList(); - //!Destructor - virtual ~DrawDispList(); - - virtual unsigned int getType() const {return DRAW_TYPE_DISPLAYLIST;} - - //!Execute the display list - void draw() const; - - //!Set it such that many openGL calls map to the display list. - /*!If "execute" is true, the commands will be excuted after - * accumulating the display list buffer - * For a complete list of which calls map to the dispaly list, - * see the openGL spec, "Display lists" - */ - bool startList(bool execute); - - //!Add a drawable object - list MUST be active - /* If the list is not active, this will simply exectue - * the draw function of the drawable - */ - void addDrawable(const DrawableObj *); - - //!Close the list - this *will* clear the gl error system - bool endList(); - //!Get bounding cube - void getBoundingBox(BoundCube &b) const { b=boundBox;} - -}; - -//!A class to draw text obects using FTGL -/*May not be the best way to do this. - * MIght be better to have static instances - * of each possible type of font, then - * render the text appropriately - */ -class DrawGLText : public DrawableObj -{ - - private: - - //!FTGL font instance - FTFont *font; - - //!Font string - std::string fontString; - //!Current font mode - unsigned int curFontMode; - - //!Text string - std::string strText; - //!Origin of text - Point3D origin; - //!Alignment mode - unsigned int alignMode; - - //!Colours for text - float r,g,b,a; - - //Two vectors required to define - //these should always give a dot prod of - //zero - - //!Up direction for text - Point3D up; - - //!Text flow direction - Point3D textDir; - - //!Direction for which text should be legible - /*! This will ensure that the text is legible from - * the direction being pointed to by normal. It is - * not the true normal of the quad. as the origin and the - * up direction specify some of that data already - */ - Point3D readDir; - - //!True if no erro - bool isOK; - - //!Ensure that the text is never mirrored from view direction - bool ensureReadFromNorm; - public: - //!Constructor (font file & text mode) - /* Valid font types are FTGL_x where x is - * BITMAP - * PIXMAP - * OUTLINE - * POLYGON - * EXTRUDE - * TEXTURE - */ - DrawGLText(std::string fontFile, - unsigned int ftglTextMode); - DrawGLText(const DrawGLText &other); - - //!Destructor - virtual ~DrawGLText(); - - virtual unsigned int getType() const {return DRAW_TYPE_GLTEXT;} - //!Set the size of the text (in points (which may be GL units, - //unsure)) - inline void setSize(unsigned int size) - {if(isOK){font->FaceSize(size);}}; - //!Set the depth of the text (in points, may be GL units, unsure) - inline void setDepth(unsigned int depth) - {if(isOK){font->Depth(depth);}}; - //!Returs true if the class data is good - inline bool ok() const - {return isOK;}; - - //!Set the text string to be displayed - inline void setString(const std::string &str) - {strText=str;}; - - //!Render the text string - void draw() const; - - //!Set the up direction for the text - /*!Note that this must be orthogonal to - * the reading direction - */ - inline void setUp(const Point3D &p) - { up=p;up.normalise();}; - //!Set the origin - inline void setOrigin(const Point3D &p) - { origin=p;}; - //!Set the reading direction - /*!The reading direction is the direction - * from which the text should be legible - * This direction is important only if ensureReadFromNorm - * is set - */ - inline void setReadDir(const Point3D &p) - { readDir=p;}; - - //!Set the text flow direction - /*! This *must* be orthogonal to the up vector - * i.e. forms a right angle with - */ - inline void setTextDir(const Point3D &p) - {textDir=p;textDir.normalise();} - //!Return the location of the lower-left of the text - inline Point3D getOrigin() const - {return origin;}; - - inline void setReadFromNorm(bool b) - {ensureReadFromNorm=b;} - - //!Set the colour (rgba) of the object - void setColour(float r,float g,float b,float a); - - //!Get the bounding box for the text - void getBoundingBox(BoundCube &b) const; - - //!Set the text alignment (default is left) - void setAlignment(unsigned int mode); - - //Binding parameter recomputation - void recomputeParams(const vector &vecs, - const vector &scalars, unsigned int mode); -}; - - - - -//!A class to draw rectangluar prisms -/* TODO: extend to non-axis aligned version - */ -class DrawRectPrism : public DrawableObj -{ - private: - //!Drawing mode, (line or surface); - unsigned int drawMode; - //!Colours for prism - float r,g,b,a; - //!Lower left and upper right of box - Point3D pMin, pMax; - //!Thickness of line - float lineWidth; - public: - DrawRectPrism(); - ~DrawRectPrism(); - - virtual unsigned int getType() const {return DRAW_TYPE_RECTPRISM;} - - //!Draw object - void draw() const; - - //!Set the draw mode - void setDrawMode(unsigned int n) { drawMode=n;}; - //!Set colour of box - void setColour(float rnew, float gnew, float bnew, float anew); - //!Set thickness of box - void setLineWidth(float lineWidth); - //!Set up box as axis-aligned rectangle using two points - void setAxisAligned(const Point3D &p1,const Point3D &p2); - //!Set up box as axis-aligned rectangle using bounding box - void setAxisAligned(const BoundCube &b); - - void getBoundingBox(BoundCube &b) const; - - //!Recompute the internal parameters using the input vector information - void recomputeParams(const vector &vecs, const vector &scalars, unsigned int mode); -}; - -struct RGBFloat -{ - float v[3]; -}; - -class DrawColourBarOverlay : public DrawableObj -{ - private: - FTFont *font; - - //!Colours for each element - vector rgb; - //alpha (transparancy) value - float a; - //!Minimum and maximum values for the colour bar (for ticks) - float min,max; - //!Height and width of bar (total) - float height,width; - //!top left of bar - float tlX,tlY; - - public: - - DrawColourBarOverlay(); - DrawColourBarOverlay(const DrawColourBarOverlay &o); - ~DrawColourBarOverlay(){delete font;}; - - - virtual unsigned int getType() const {return DRAW_TYPE_COLOURBAR;} - - void getBoundingBox(BoundCube &b) const ; - - //!This is an overlay - bool isOverlay() const {return true;}; - void setColourVec(const vector &r, - const vector &g, - const vector &b); - //!Draw object - void draw() const; - - void setAlpha(float alpha) { a=alpha;}; - void setSize(float widthN, float heightN) {height=heightN, width=widthN;} - void setPosition(float newTLX,float newTLY) { tlX=newTLX; tlY=newTLY;} - void setMinMax(float minNew,float maxNew) { min=minNew;max=maxNew;}; - -}; - -//!A class to hande textures to draw -class DrawTexturedQuadOverlay : public DrawableObj -{ - private: - TexturePool *texPool; - unsigned int textureId; - float position[2]; - float length; - unsigned int winX,winY; - - bool textureOK; - public: - DrawTexturedQuadOverlay(); - ~DrawTexturedQuadOverlay(); - - virtual unsigned int getType() const {return DRAW_TYPE_TEXTUREDOVERLAY;} - - //!This is an overlay - bool isOverlay() const {return true;}; - - 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;}; - - void setSize(float size); - - //!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; - - void getBoundingBox(BoundCube &b) const ; -}; - - -struct RGBThis -{ - unsigned char v[3]; -}; - -//!This class allows for the visualisation of 3D scalar fields -class DrawField3D : public DrawableObj -{ - private: - mutable std::vector > ptsCache; - mutable bool ptsCacheOK; - protected: - //!Alpha transparancy of objects in field - float alphaVal; - - //!Size of points in the field - - //only meaningful if the render mode is set to alpha blended points - float pointSize; - - //!True if the scalar field's bounding box is to be drawn - bool drawBoundBox; - - //!Colours for the bounding boxes - float boxColourR,boxColourG,boxColourB,boxColourA; - - //!True if volume grid is enabled - bool volumeGrid; - - //!Colour map lower and upper bounds - float colourMapBound[2]; - - //!Which colourmap to use - unsigned int colourMapID; - - //!Sets the render mode for the 3D volume - /* Possible modes - * 0: Alpha blended points - */ - unsigned int volumeRenderMode; - //!The scalar field - used to store data values - const Voxels *field; - public: - //!Default Constructor - DrawField3D(); - //!Destructor - virtual ~DrawField3D(); - - virtual unsigned int getType() const {return DRAW_TYPE_FIELD3D;} - - //!Get the bounding box for this object - void getBoundingBox(BoundCube &b) const; - - //!Set the render mode (see volumeRenderMode variable for details) - void setRenderMode(unsigned int); - - //!Set the field pointer - void setField(const Voxels *field); - - //!Set the alpha value for elemnts - void setAlpha(float alpha); - - //!Set the colour bar minima and maxima from current field values - void setColourMinMax(); - - //!Set the colourMap ID - void setColourMapID(unsigned int i){ colourMapID=i;}; - - //!Render the field - void draw() const; - - //!Set the size of points - void setPointSize(float size); - - //!Set the colours that ar ebeing used in the tempMap - void setMapColours(unsigned int map); - - //!Set the coour of the bounding box - void setBoxColours(float r, float g, float b, float a); - -}; - -class DrawIsoSurface: public DrawableObj -{ -private: - - mutable bool cacheOK; - - //!should we draw the thing - // - in wireframe - // -Flat - // -Smooth - // - unsigned int drawMode; - - //!Isosurface scalar threshold - float threshold; - - Voxels *voxels; - - mutable vector mesh; - - //!Warning. Although I declare this as const, I do some naughty mutating to the cache. - void updateMesh() const; - - //!Point colour (r,g,b,a) range: [0.0f,1.0f] - float r,g,b,a; -public: - - DrawIsoSurface(); - ~DrawIsoSurface(); - - virtual unsigned int getType() const {return DRAW_TYPE_ISOSURFACE;} - //!Transfer ownership of data pointer to class - void swapVoxels(Voxels *v); - - //!Set the drawing method - - //Draw - void draw() const; - - //!Set the isosurface value - void setScalarThresh(float thresh) { threshold=thresh;cacheOK=false;mesh.clear();}; - - //!Get the bouding box (of the entire scalar field) - void getBoundingBox(BoundCube &b) const ; - - //!Sets the color of the point to be drawn - void setColour(float rP, float gP, float bP, float alpha) { r=rP;g=gP;b=bP;a=alpha;} ; - - //!Do we need depth sorting? - bool needsDepthSorting() const; -}; - - -class DrawAxis : public DrawableObj -{ - private: - //!Drawing style - unsigned int style; - Point3D position; - //!size - float size; - public: - DrawAxis(); - ~DrawAxis(); - - virtual unsigned int getType() const {return DRAW_TYPE_AXIS;} - - //!Draw object - void draw() const; - - - void setStyle(unsigned int style); - void setSize(float newSize); - void setPosition(const Point3D &p); - - void getBoundingBox(BoundCube &b) const; -}; -#endif diff -Nru 3depict-0.0.12/src/effect.cpp 3depict-0.0.13/src/effect.cpp --- 3depict-0.0.12/src/effect.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/effect.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,696 +0,0 @@ -/* - * effect.cpp - 3D visuals effects implementation - * Copyright (C) 2012, 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 . -*/ - - -#include "effect.h" -#include - -#include -#include -using std::endl; - -#include - -#include "mathfuncs.h" -#include "xmlHelper.h" -#include "basics.h" - -#include "commonConstants.h" - -Camera* Effect::curCam=0; -BoundCube Effect::bc; -float MIN_CROP_FRACTION=0.0001; - -const unsigned int NUM_EFFECTS=2; -const char *EFFECT_NAMES[] = { "boxcrop", - "anaglyph" - }; - -//factory functions -Effect *makeEffect(unsigned int effectID) -{ - Effect *e; - switch(effectID) - { - case EFFECT_ANAGLYPH: - e = new AnaglyphEffect; - break; - - case EFFECT_BOX_CROP: - e=new BoxCropEffect; - break; - - default: - ASSERT(false); - } - - return e; -} - - - -Effect *makeEffect(const std::string &str) -{ - Effect *e=0; - - for(unsigned int ui=0;uigetType()]; -} - -BoxCropEffect::BoxCropEffect() : openGLIdStart(0), useCamCoordinates(false) -{ - effectType=EFFECT_BOX_CROP; -} - -void BoxCropEffect::enable(unsigned int pass) const -{ - - //we only need to do anything on the first pass. All other passes are unchanged - if(pass) - return; - //Compute the bounding box that is the clipped boundary - Point3D pAAB[2]; //Axis aligned box - bc.getBounds(pAAB[0],pAAB[1]); - - Point3D pCentre; - pCentre = (pAAB[0] + pAAB[1])*0.5f; - - unsigned int glOffset=openGLIdStart; - - if(useCamCoordinates) - { - Point3f pBox[8]; - for(unsigned int ui=0;ui<8;ui++) - { - //Counting in binary to generate box corner vertices. - pBox[ui].fx = pAAB[(ui>>2) &1][0]; - pBox[ui].fy = pAAB[(ui>>1) &1][1]; - pBox[ui].fz = pAAB[ui&1][2]; - } - //Translate to rotate around the box centre - for(unsigned int ui=0;ui<8;ui++) - { - pBox[ui].fx-=pCentre[0]; - pBox[ui].fy-=pCentre[1]; - pBox[ui].fz-=pCentre[2]; - } - - Point3D x,y,z; - //get camera orientation data - z= curCam->getUpDirection(); - y= curCam->getViewDirection(); - - //We need to first do a "passive" coordinate transformation on the box coordinates - //to determine the box coordinates in camera basis vectors (after translation such tat - //centre of box is in centre of world). - - //Active transformations are v'=Tv_orig. Passive transformation is that v_prime = T^-1 v_orig - // - - z.normalise(); //Not needed, I think.. but can't hurt - y.normalise(); - x= z.crossProd(y); - - float angle; - angle=z.angle(Point3D(0,0,1)); - - - - //If needed, perform a rotation to align the box up - //vector with the camera up vector - Point3f r; - Point3D yTmpRot; - if(fabs(angle) > sqrtf(std::numeric_limits::epsilon())) - { - Point3D rotateAxis; - - - //Check for numerical stability problem when camera - //& world z axes point exactly apart - if( fabs(angle-M_PI) ::epsilon())) - rotateAxis=Point3D(1,0,0); //Pick *any* vector in X-Y plane. - else - rotateAxis = z.crossProd(Point3D(0,0,1)); - rotateAxis.normalise(); - - r.fx=rotateAxis[0]; - r.fy=rotateAxis[1]; - r.fz=rotateAxis[2]; - - for(unsigned int ui=0;ui<8;ui++) - quat_rot(&(pBox[ui]),&r,angle); - - - Point3f yRot; - yRot.fx=0; - yRot.fy=1; - yRot.fz=0; - quat_rot(&yRot,&r,angle); - - yTmpRot=Point3D(yRot.fx,yRot.fy,yRot.fz); - - ASSERT(yTmpRot.sqrMag() > sqrtf(std::numeric_limits::epsilon())); - - } - else - yTmpRot=Point3D(0,1,0); - - //Rotating around the z axis to set "spin" - r.fx=z[0]; - r.fy=z[1]; - r.fz=z[2]; - - angle=y.angle(yTmpRot); - - - if( fabs(angle) > sqrtf(std::numeric_limits::epsilon())) - { - //Spin the box around to match the final coordinate system - for(unsigned int ui=0;ui<8;ui++) - quat_rot(&(pBox[ui]),&r,angle); - } - - - //Now compute the box coordinates, then break their position - //vectors (from box centre) down into the basis - //coordinates of our camera - Point3D pBoxVertices[8]; - - for(unsigned int ui=0;ui<8;ui++) - pBoxVertices[ui]= Point3D(pBox[ui].fx, - pBox[ui].fy,pBox[ui].fz); - - float dotValue[3]; - dotValue[0]=dotValue[1]=dotValue[2]=-std::numeric_limits::max(); - //Find the largest positive basis components (these form the camera BB limits) - for(unsigned int ui=0;ui<8;ui++) - { - float tmp; - tmp =x.dotProd(pBoxVertices[ui]); - if(tmp > dotValue[0]) - dotValue[0]=tmp; - - tmp =y.dotProd(pBoxVertices[ui]); - if(tmp > dotValue[1]) - dotValue[1]=tmp; - - tmp =z.dotProd(pBoxVertices[ui]); - if(tmp > dotValue[2]) - dotValue[2]=tmp; - - } - - //Compute the cropping deltas in the range [-1,1] - float dC[6]; - for(unsigned int ui=0;ui<6;ui++) - { - - if(ui&1) - { - //upper - dC[ui] =2.0*(0.5- cropFractions[ui]); - } - else - { - //Lower - dC[ui]=2.0*(cropFractions[ui]-0.5); - } - } - - //Cropping delta * dotproduct *basisvector == crop point - //Note the reversal of the Z and Y vectors - pAAB[0] = pCentre + x*dotValue[0]*dC[0] - +y*dotValue[1]*dC[2]+z*dotValue[2]*dC[4]; - pAAB[1] = pCentre + x*dotValue[0]*dC[1] - +y*dotValue[1]*dC[3]+z*dotValue[2]*dC[5]; - - - //Draw crop iff crop fractiosn are +ve - - //X - if(cropFractions[0] >=MIN_CROP_FRACTION) - { - doClip(pAAB[0],x,glOffset); - glOffset++; - } - if(cropFractions[1] >=MIN_CROP_FRACTION) - { - doClip(pAAB[1],-x,glOffset); - glOffset++; - } - - //Y - if(cropFractions[2] >=MIN_CROP_FRACTION) - { - doClip(pAAB[0],y,glOffset); - glOffset++; - } - if(cropFractions[3] >=MIN_CROP_FRACTION) - { - doClip(pAAB[1],-y,glOffset); - glOffset++; - } - - //Z - if(cropFractions[4] >=MIN_CROP_FRACTION) - { - doClip(pAAB[0],z,glOffset); - glOffset++; - } - if(cropFractions[5] >=MIN_CROP_FRACTION) - { - doClip(pAAB[1],-z,glOffset++); - glOffset++; - } - } - else - { - pAAB[0] = pCentre + Point3D(0.5-cropFractions[0], - 0.5-cropFractions[2],0.5-cropFractions[4])*(pAAB[0]-pCentre)*2.0; - pAAB[1] = pCentre + Point3D(0.5-cropFractions[1], - 0.5-cropFractions[3],0.5-cropFractions[5])*(pAAB[1]-pCentre)*2.0; - - for(unsigned int ui=0;ui<6;ui++) - { - Point3D normal; - - //Don't update minimum crop fractions - if(cropFractions[ui] < MIN_CROP_FRACTION) - continue; - //Set up the normal & origin (use rectangular prism vertex as origin) - normal=Point3D(0,0,0); - normal.setValue(ui/2,1); - if(ui&1) - { - normal=-normal; - doClip(pAAB[1],normal,glOffset); - } - else - doClip(pAAB[0],normal,glOffset); - - glOffset++; - } - } -} - -void BoxCropEffect::doClip(const Point3D &origin, const Point3D &normal, unsigned int glOffset) const -{ - double array[4]; - //Ax + By + Cz + D =0. Prove from - //n.dot(v-p_0)=0 - array[0]=normal[0]; - array[1]=normal[1]; - array[2]=normal[2]; - array[3] = -normal.dotProd(origin); - - - glMatrixMode(GL_MODELVIEW); - - //Set up the effect - glClipPlane(GL_CLIP_PLANE0 +glOffset, - array); - glEnable(GL_CLIP_PLANE0+glOffset); - - -} - -void BoxCropEffect::disable() const -{ - unsigned int startId=openGLIdStart; - - for(unsigned int ui=0; ui<6;ui++) - { - if(cropFractions[ui]>= MIN_CROP_FRACTION) - { - glDisable(GL_CLIP_PLANE0+startId); - startId++; - } - } -} - -bool BoxCropEffect::willDoSomething() const -{ - for(unsigned int ui=0;ui<6;ui++) - { - if(cropFractions[ui]>=MIN_CROP_FRACTION) - return true; - } - - return false; -} - -void BoxCropEffect::setFractions(const float *frac) -{ - for(unsigned int ui=0;ui<6;ui++) - cropFractions[ui]=frac[ui]; -} - - -void BoxCropEffect::getCroppedBounds(BoundCube &b) const -{ - Point3D pLow,pHi; - b.getBounds(pLow,pHi); - - Point3D pCentre = (pLow+pHi)*0.5; - pLow = pCentre + Point3D(0.5-cropFractions[0], - 0.5-cropFractions[2],0.5-cropFractions[4])*(pLow-pCentre)*2.0; - pHi = pCentre + Point3D(0.5-cropFractions[1], - 0.5-cropFractions[3],0.5-cropFractions[5])*(pHi-pCentre)*2.0; - - b.setBounds(pLow,pHi); -} - -bool BoxCropEffect::writeState(std::ofstream &f, unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+2) << "" << endl; - for(unsigned int ui=0;ui<6;ui++) - { - f << tabs(depth+3) << "" << endl; - } - - f << tabs(depth+2) << "" << endl; - - - f << tabs(depth+2) << "" << endl; - f << tabs(depth+1) << "" << endl; - break; - - default: - ASSERT(false); - return false; - - } - - return true; -} - - -bool BoxCropEffect::readState(xmlNodePtr nodePtr) -{ - using std::string; - - nodePtr=nodePtr->xmlChildrenNode; - xmlNodePtr scalars; - if(XMLHelpFwdToElem(nodePtr,"cropvalues")) - return false; - - scalars=nodePtr->xmlChildrenNode; - - for(unsigned int ui=0;ui<6;ui++) - { - if(!XMLGetNextElemAttrib(scalars,cropFractions[ui],"scalar","value")) - return false; - } - - string s; - if(!XMLGetNextElemAttrib(nodePtr,s,"usecamcoordinates","value")) - return false; - - if(s=="0") - useCamCoordinates=false; - else if (s == "1") - useCamCoordinates=true; - else - return false; - - - return true; -} -AnaglyphEffect::AnaglyphEffect() : colourMode(ANAGLYPH_REDBLUE), eyeFlip(false), - oldCam(0),baseShift(0.01f) -{ - effectType=EFFECT_ANAGLYPH; -} - -void AnaglyphEffect::enable(unsigned int passNumber) const -{ - if(passNumber >1 || curCam->type() !=CAM_LOOKAT) - return; - - if(passNumber==0) - { - oldCam=curCam->clone(); - //Translate both the target, and the origin - curCam->translate(baseShift,0); - //Apply the frustum offset to restore the shifted focal plane - ((CameraLookAt*)curCam)->setFrustumDistort(baseShift); - - } - else - { - *curCam=*oldCam; - //this time, in the reverse direction; - //Translate both the target, and the origin - curCam->translate(-baseShift,0); - //Apply the frustum offset to restore the shifted focal plane - ((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); - - - //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); - } - 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); - - 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); - } - - } - - - -} - -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); - } - - - ASSERT(oldCam); - *curCam=*oldCam; - delete oldCam; -} - -bool AnaglyphEffect::writeState(std::ofstream &f, unsigned int format,unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - f << tabs(depth+1) << "" << endl; - f << tabs(depth+2) << "" << endl; - - f << tabs(depth+2) << "" << endl; - f << tabs(depth+2) << "" << endl; - f << tabs(depth+1) << "" << endl; - break; - - default: - ASSERT(false); - return false; - - } - - return true; -} - - -bool AnaglyphEffect::readState(xmlNodePtr nodePtr) -{ - using std::string; - - if(!XMLGetNextElemAttrib(nodePtr,colourMode,"colourmode","value")) - return false; - if(colourMode >= ANAGLYPH_HALF_COLOUR) - return false; - - - string s; - if(!XMLGetNextElemAttrib(nodePtr,s,"eyeflip","value")) - return false; - - - if(s == "0") - eyeFlip=false; - else if(s == "1") - eyeFlip=true; - else - return false; - - if(!XMLGetNextElemAttrib(nodePtr,baseShift,"baseshift","value")) - return false; - - return true; -} - - diff -Nru 3depict-0.0.12/src/effect.h 3depict-0.0.13/src/effect.h --- 3depict-0.0.12/src/effect.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/effect.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,200 +0,0 @@ -/* - * effect.h - opengl 3D effects header - * Copyright (C) 2012, 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 . -*/ - -#ifndef EFFECT_H -#define EFFECT_H - -#include - -#undef ATTRIBUTE_PRINTF -#include -#undef ATTRIBUTE_PRINTF - -//OpenGL includes -//MacOS is "special" and puts it elsewhere -#ifdef __APPLE__ - #include -#else - #include -#endif - -#include "cameras.h" - - -//opengl allows up to 6 clipping planes -const unsigned int MAX_OPENGL_CLIPPLANES=6; - - - -//Effect IDs -enum -{ - EFFECT_BOX_CROP=0, - EFFECT_ANAGLYPH, - EFFECT_ENUM_END -}; - - -enum{ - //Colour mask methods - ANAGLYPH_REDBLUE, - ANAGLYPH_REDGREEN, - ANAGLYPH_REDCYAN, - ANAGLYPH_GREENMAGENTA, - //Colour matrix +accumulation buffer methods - ANAGLYPH_HALF_COLOUR, - ANAGLYPH_MIXED, - ANAGLYPH_ENUM_END //Not a method. end of enum -}; - -class Effect -{ - protected: - static Camera *curCam; - static BoundCube bc; - unsigned int effectType; - public: - Effect(); - virtual ~Effect() {}; - virtual void enable(unsigned int pass=0) const =0; - virtual void disable() const=0; - std::string getName() const; - - - //Write the effect's state information to file - virtual bool writeState(std::ofstream &f, - unsigned int format, unsigned int depth) const=0; - //read the effects state information from an XML file - virtual bool readState(xmlNodePtr n)=0; - - virtual bool needCamUpdate() const { return false;} - - //!Returns true if the effect has any influence on the output - virtual bool willDoSomething() const=0; - - virtual unsigned int numPassesNeeded() const { return 1;} - - virtual unsigned int getType() const { return effectType;}; - static void setCurCam(Camera *c) {curCam=c;} - static void setBoundingCube(const BoundCube &c) {bc=c;} - -}; - - -class BoxCropEffect : public Effect -{ - private: - //controlling ID values for gl plane. No more than MAX_OPENGL_CLIPPLANES allowed - unsigned int openGLIdStart,openGLIdEnd; - //Cropping margins (Fraction from edge towards opposite edge (complete)). 0->1. - //Opposing edges must sum to 0->1. (xLo,xHi,yLo...) - float cropFractions[6]; - //!True if we should transform to camera coordinates before applying crop - bool useCamCoordinates; - - //!Aspect ratio of output image - float outputAspect; - - void doClip(const Point3D &origin, const Point3D & normal,unsigned int glOffset) const; - public: - BoxCropEffect(); - virtual ~BoxCropEffect(){}; - - //!Enable the clipping plane. Values *must* be set before calling - void enable(unsigned int pass) const; - - //!DIsable the clipping plane - void disable() const; - - - - //Write the effect's state information to file - bool writeState(std::ofstream &f, unsigned int format, - unsigned int depth) const; - //read the effects state information from an XML file - bool readState(xmlNodePtr n); - - //!Returns true if the effect has any influence on the output - bool willDoSomething() const; - - //!Set the fractions of cube from margin - //-- there should be 6 floats (x,y,z)_(low,high) (x_lo, x_hi....) - // each low/hi should form a sum between 0 and 1. - void setFractions(const float *fractionArray); - - void useCamCoords(bool enable){useCamCoordinates=enable;}; - - //!Alters the input box to generate cropping bounding box - //note the box may be inside out if the cropping limits - //exceed themselves.. - void getCroppedBounds(BoundCube &b) const; - - float getCropValue(unsigned int pos) const {ASSERT(pos<6); return cropFractions[pos];} -}; - -class AnaglyphEffect : public Effect -{ - private: - unsigned int colourMode; - bool eyeFlip; - - mutable Camera *oldCam; - float baseShift; - - public: - AnaglyphEffect(); - ~AnaglyphEffect(){}; - - //!Enable the clipping plane. Values *must* be set before calling - void enable(unsigned int pass) const; - - //!DIsable the clipping plane - void disable() const; - - //Write the effect's state information to file - bool writeState(std::ofstream &f, unsigned int format, - unsigned int depth) const; - //read the effects state information from an XML file - bool readState(xmlNodePtr n); - - //!Whether we should be flipping the lens from its hard-coded left-right - void setFlip(bool shouldFlip) {eyeFlip=shouldFlip;}; - - void setMode(unsigned int mode){ASSERT(colourMode. -*/ - -#ifndef _ENDIAN_TEST_H_ -#define _ENDIAN_TEST_H_ -#if defined (_WIN32) || defined(_WIN64) || defined(__CYGWIN__) -#define __LITTLE_ENDIAN__ -#else -#ifdef __linux__ -#include -#endif -#endif - -#ifdef __BYTE_ORDER -//if both are not defined it is TRUE! -#if __BYTE_ORDER == __BIG_ENDIAN -#ifndef __BIG_ENDIAN__ -#define __BIG_ENDIAN__ -#endif -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#ifndef __LITTLE_ENDIAN__ -#define __LITTLE_ENDIAN__ -#endif -#elif __BYTE_ORDER == __PDP_ENDIAN -#ifndef __ARM_ENDIAN__ -#define __ARM_ENDIAN__ -#endif -#else -#error "Endian determination failed" -#endif -#endif - -const int ENDIAN_TEST=1; -//Run-time detection -inline int is_bigendian() { return (*(char*)&ENDIAN_TEST) == 0 ;} - -inline int is_littleendian() { return (*(char*)&ENDIAN_TEST) == 1 ;} - - -inline void floatSwapBytes(float *inFloat) -{ - //Use a union to avoid strict-aliasing error - union FloatSwapUnion{ - float f; - char c[4]; - } ; - FloatSwapUnion fa,fb; - fa.f = *inFloat; - - fb.c[0] = fa.c[3]; - fb.c[1] = fa.c[2]; - fb.c[2] = fa.c[1]; - fb.c[3] = fa.c[0]; - - *inFloat=fb.f; -} - -#endif diff -Nru 3depict-0.0.12/src/eventlogger.cpp 3depict-0.0.13/src/eventlogger.cpp --- 3depict-0.0.12/src/eventlogger.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/eventlogger.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,233 +0,0 @@ -/* - * eventlogger.cpp - Program event logger - * Copyright (C) 2012 A Ceguerra - * - * 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 . - */ - -#ifdef DEBUG - -#include "eventlogger.h" - -#include -#include -#include - -#include "wxcommon.h" - -using std::pair; -using std::make_pair; - -EventLogger::EventLogger(int b, std::ostream *s) -: bitshift(b), eventcount(0), prevevt(-1), ringbuffermax(1 << bitshift), stream(s) -{ - // events to ignore in the logger - ignoreEvents.insert(wxEVT_HIBERNATE); - ignoreEvents.insert(wxEVT_IDLE); - ignoreEvents.insert(wxEVT_PAINT); - ignoreEvents.insert(wxEVT_ERASE_BACKGROUND); - ignoreEvents.insert(wxEVT_NC_PAINT); - ignoreEvents.insert(wxEVT_UPDATE_UI); - ignoreEvents.insert(wxEVT_SIZE); - - //Causes window name retrieval to crash - //--- - ignoreEvents.insert(10215); - ignoreEvents.insert(wxEVT_SET_CURSOR); - //--- - - - // ignoreEvents.insert(wxEVT_MOTION);//this removed all events - - ringbuffer = new std::string[ringbuffermax]; - - mask = 1; - for (size_t i = 0; i < bitshift - 1; i++) { - mask <<= 1; - mask++; - } - pair allEvents [] = { - make_pair(wxEVT_COMMAND_BUTTON_CLICKED, "wxEVT_COMMAND_BUTTON_CLICKED") - ,make_pair(wxEVT_COMMAND_CHECKBOX_CLICKED, "wxEVT_COMMAND_CHECKBOX_CLICKED") - ,make_pair(wxEVT_COMMAND_CHOICE_SELECTED, "wxEVT_COMMAND_CHOICE_SELECTED") - ,make_pair(wxEVT_COMMAND_LISTBOX_SELECTED, "wxEVT_COMMAND_LISTBOX_SELECTED") - ,make_pair(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, "wxEVT_COMMAND_LISTBOX_DOUBLECLICKED") - ,make_pair(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, "wxEVT_COMMAND_CHECKLISTBOX_TOGGLED") - ,make_pair(wxEVT_COMMAND_MENU_SELECTED, "wxEVT_COMMAND_MENU_SELECTED") - ,make_pair(wxEVT_COMMAND_SLIDER_UPDATED, "wxEVT_COMMAND_SLIDER_UPDATED") - ,make_pair(wxEVT_COMMAND_RADIOBOX_SELECTED, "wxEVT_COMMAND_RADIOBOX_SELECTED") - ,make_pair(wxEVT_COMMAND_RADIOBUTTON_SELECTED, "wxEVT_COMMAND_RADIOBUTTON_SELECTED") - ,make_pair(wxEVT_COMMAND_SCROLLBAR_UPDATED, "wxEVT_COMMAND_SCROLLBAR_UPDATED") - ,make_pair(wxEVT_COMMAND_VLBOX_SELECTED, "wxEVT_COMMAND_VLBOX_SELECTED") - ,make_pair(wxEVT_COMMAND_COMBOBOX_SELECTED, "wxEVT_COMMAND_COMBOBOX_SELECTED") - ,make_pair(wxEVT_COMMAND_TOOL_RCLICKED, "wxEVT_COMMAND_TOOL_RCLICKED") - //,make_pair(wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, "wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED") - ,make_pair(wxEVT_COMMAND_TOOL_ENTER, "wxEVT_COMMAND_TOOL_ENTER") - //,make_pair(wxEVT_COMMAND_COMBOBOX_DROPDOWN, "wxEVT_COMMAND_COMBOBOX_DROPDOWN") - //,make_pair(wxEVT_COMMAND_COMBOBOX_CLOSEUP, "wxEVT_COMMAND_COMBOBOX_CLOSEUP") - //,make_pair(wxEVT_THREAD, "wxEVT_THREAD") - ,make_pair(wxEVT_LEFT_DOWN, "wxEVT_LEFT_DOWN") - ,make_pair(wxEVT_LEFT_UP, "wxEVT_LEFT_UP") - ,make_pair(wxEVT_MIDDLE_DOWN, "wxEVT_MIDDLE_DOWN") - ,make_pair(wxEVT_MIDDLE_UP, "wxEVT_MIDDLE_UP") - ,make_pair(wxEVT_RIGHT_DOWN, "wxEVT_RIGHT_DOWN") - ,make_pair(wxEVT_RIGHT_UP, "wxEVT_RIGHT_UP") - ,make_pair(wxEVT_MOTION, "wxEVT_MOTION") - ,make_pair(wxEVT_ENTER_WINDOW, "wxEVT_ENTER_WINDOW") - ,make_pair(wxEVT_LEAVE_WINDOW, "wxEVT_LEAVE_WINDOW") - ,make_pair(wxEVT_LEFT_DCLICK, "wxEVT_LEFT_DCLICK") - ,make_pair(wxEVT_MIDDLE_DCLICK, "wxEVT_MIDDLE_DCLICK") - ,make_pair(wxEVT_RIGHT_DCLICK, "wxEVT_RIGHT_DCLICK") - ,make_pair(wxEVT_SET_FOCUS, "wxEVT_SET_FOCUS") - ,make_pair(wxEVT_KILL_FOCUS, "wxEVT_KILL_FOCUS") - ,make_pair(wxEVT_CHILD_FOCUS, "wxEVT_CHILD_FOCUS") - ,make_pair(wxEVT_MOUSEWHEEL, "wxEVT_MOUSEWHEEL") - //,make_pair(wxEVT_AUX1_DOWN, "wxEVT_AUX1_DOWN") - //,make_pair(wxEVT_AUX1_UP, "wxEVT_AUX1_UP") - //,make_pair(wxEVT_AUX1_DCLICK, "wxEVT_AUX1_DCLICK") - //,make_pair(wxEVT_AUX2_DOWN, "wxEVT_AUX2_DOWN") - //,make_pair(wxEVT_AUX2_UP, "wxEVT_AUX2_UP") - //,make_pair(wxEVT_AUX2_DCLICK, "wxEVT_AUX2_DCLICK") - ,make_pair(wxEVT_CHAR, "wxEVT_CHAR") - ,make_pair(wxEVT_CHAR_HOOK, "wxEVT_CHAR_HOOK") - ,make_pair(wxEVT_NAVIGATION_KEY, "wxEVT_NAVIGATION_KEY") - ,make_pair(wxEVT_KEY_DOWN, "wxEVT_KEY_DOWN") - ,make_pair(wxEVT_KEY_UP, "wxEVT_KEY_UP") - //,make_pair(wxEVT_HOTKEY, "wxEVT_HOTKEY") - ,make_pair(wxEVT_SET_CURSOR, "wxEVT_SET_CURSOR") - ,make_pair(wxEVT_SCROLL_TOP, "wxEVT_SCROLL_TOP") - ,make_pair(wxEVT_SCROLL_BOTTOM, "wxEVT_SCROLL_BOTTOM") - ,make_pair(wxEVT_SCROLL_LINEUP, "wxEVT_SCROLL_LINEUP") - ,make_pair(wxEVT_SCROLL_LINEDOWN, "wxEVT_SCROLL_LINEDOWN") - ,make_pair(wxEVT_SCROLL_PAGEUP, "wxEVT_SCROLL_PAGEUP") - ,make_pair(wxEVT_SCROLL_PAGEDOWN, "wxEVT_SCROLL_PAGEDOWN") - ,make_pair(wxEVT_SCROLL_THUMBTRACK, "wxEVT_SCROLL_THUMBTRACK") - ,make_pair(wxEVT_SCROLL_THUMBRELEASE, "wxEVT_SCROLL_THUMBRELEASE") - ,make_pair(wxEVT_SCROLL_CHANGED, "wxEVT_SCROLL_CHANGED") - //,make_pair(wxEVT_SPIN_UP, "wxEVT_SPIN_UP") - //,make_pair(wxEVT_SPIN_DOWN, "wxEVT_SPIN_DOWN") - //,make_pair(wxEVT_SPIN, "wxEVT_SPIN") - ,make_pair(wxEVT_SCROLLWIN_TOP, "wxEVT_SCROLLWIN_TOP") - ,make_pair(wxEVT_SCROLLWIN_BOTTOM, "wxEVT_SCROLLWIN_BOTTOM") - ,make_pair(wxEVT_SCROLLWIN_LINEUP, "wxEVT_SCROLLWIN_LINEUP") - ,make_pair(wxEVT_SCROLLWIN_LINEDOWN, "wxEVT_SCROLLWIN_LINEDOWN") - ,make_pair(wxEVT_SCROLLWIN_PAGEUP, "wxEVT_SCROLLWIN_PAGEUP") - ,make_pair(wxEVT_SCROLLWIN_PAGEDOWN, "wxEVT_SCROLLWIN_PAGEDOWN") - ,make_pair(wxEVT_SCROLLWIN_THUMBTRACK, "wxEVT_SCROLLWIN_THUMBTRACK") - ,make_pair(wxEVT_SCROLLWIN_THUMBRELEASE, "wxEVT_SCROLLWIN_THUMBRELEASE") - ,make_pair(wxEVT_SIZE, "wxEVT_SIZE") - ,make_pair(wxEVT_MOVE, "wxEVT_MOVE") - ,make_pair(wxEVT_CLOSE_WINDOW, "wxEVT_CLOSE_WINDOW") - ,make_pair(wxEVT_END_SESSION, "wxEVT_END_SESSION") - ,make_pair(wxEVT_QUERY_END_SESSION, "wxEVT_QUERY_END_SESSION") - ,make_pair(wxEVT_ACTIVATE_APP, "wxEVT_ACTIVATE_APP") - ,make_pair(wxEVT_ACTIVATE, "wxEVT_ACTIVATE") - ,make_pair(wxEVT_CREATE, "wxEVT_CREATE") - ,make_pair(wxEVT_DESTROY, "wxEVT_DESTROY") - ,make_pair(wxEVT_SHOW, "wxEVT_SHOW") - ,make_pair(wxEVT_ICONIZE, "wxEVT_ICONIZE") - ,make_pair(wxEVT_MAXIMIZE, "wxEVT_MAXIMIZE") - ,make_pair(wxEVT_MOUSE_CAPTURE_CHANGED, "wxEVT_MOUSE_CAPTURE_CHANGED") - ,make_pair(wxEVT_MOUSE_CAPTURE_LOST, "wxEVT_MOUSE_CAPTURE_LOST") - ,make_pair(wxEVT_PAINT, "wxEVT_PAINT") - ,make_pair(wxEVT_ERASE_BACKGROUND, "wxEVT_ERASE_BACKGROUND") - ,make_pair(wxEVT_NC_PAINT, "wxEVT_NC_PAINT") - ,make_pair(wxEVT_MENU_OPEN, "wxEVT_MENU_OPEN") - ,make_pair(wxEVT_MENU_CLOSE, "wxEVT_MENU_CLOSE") - ,make_pair(wxEVT_MENU_HIGHLIGHT, "wxEVT_MENU_HIGHLIGHT") - ,make_pair(wxEVT_CONTEXT_MENU, "wxEVT_CONTEXT_MENU") - ,make_pair(wxEVT_SYS_COLOUR_CHANGED, "wxEVT_SYS_COLOUR_CHANGED") - ,make_pair(wxEVT_DISPLAY_CHANGED, "wxEVT_DISPLAY_CHANGED") - ,make_pair(wxEVT_QUERY_NEW_PALETTE, "wxEVT_QUERY_NEW_PALETTE") - ,make_pair(wxEVT_PALETTE_CHANGED, "wxEVT_PALETTE_CHANGED") - ,make_pair(wxEVT_JOY_BUTTON_DOWN, "wxEVT_JOY_BUTTON_DOWN") - ,make_pair(wxEVT_JOY_BUTTON_UP, "wxEVT_JOY_BUTTON_UP") - ,make_pair(wxEVT_JOY_MOVE, "wxEVT_JOY_MOVE") - ,make_pair(wxEVT_JOY_ZMOVE, "wxEVT_JOY_ZMOVE") - ,make_pair(wxEVT_DROP_FILES, "wxEVT_DROP_FILES") - ,make_pair(wxEVT_INIT_DIALOG, "wxEVT_INIT_DIALOG") - ,make_pair(wxEVT_IDLE, "wxEVT_IDLE") - ,make_pair(wxEVT_UPDATE_UI, "wxEVT_UPDATE_UI") - ,make_pair(wxEVT_SIZING, "wxEVT_SIZING") - ,make_pair(wxEVT_MOVING, "wxEVT_MOVING") - //,make_pair(wxEVT_MOVE_START, "wxEVT_MOVE_START") - //,make_pair(wxEVT_MOVE_END, "wxEVT_MOVE_END") - ,make_pair(wxEVT_HIBERNATE, "wxEVT_HIBERNATE") - ,make_pair(wxEVT_COMMAND_TEXT_COPY, "wxEVT_COMMAND_TEXT_COPY") - ,make_pair(wxEVT_COMMAND_TEXT_CUT, "wxEVT_COMMAND_TEXT_CUT") - ,make_pair(wxEVT_COMMAND_TEXT_PASTE, "wxEVT_COMMAND_TEXT_PASTE") - ,make_pair(wxEVT_COMMAND_LEFT_CLICK, "wxEVT_COMMAND_LEFT_CLICK") - ,make_pair(wxEVT_COMMAND_LEFT_DCLICK, "wxEVT_COMMAND_LEFT_DCLICK") - ,make_pair(wxEVT_COMMAND_RIGHT_CLICK, "wxEVT_COMMAND_RIGHT_CLICK") - ,make_pair(wxEVT_COMMAND_RIGHT_DCLICK, "wxEVT_COMMAND_RIGHT_DCLICK") - ,make_pair(wxEVT_COMMAND_SET_FOCUS, "wxEVT_COMMAND_SET_FOCUS") - ,make_pair(wxEVT_COMMAND_KILL_FOCUS, "wxEVT_COMMAND_KILL_FOCUS") - ,make_pair(wxEVT_COMMAND_ENTER, "wxEVT_COMMAND_ENTER") - ,make_pair(wxEVT_HELP, "wxEVT_HELP") - ,make_pair(wxEVT_DETAILED_HELP, "wxEVT_DETAILED_HELP") - ,make_pair(wxEVT_COMMAND_TEXT_UPDATED, "wxEVT_COMMAND_TEXT_UPDATED") - //,make_pair(wxEVT_COMMAND_TEXT_ENTER, "wxEVT_COMMAND_TEXT_ENTER") - ,make_pair(wxEVT_COMMAND_TOOL_CLICKED, "wxEVT_COMMAND_TOOL_CLICKED") - //,make_pair(wxEVT_WINDOW_MODAL_DIALOG_CLOSED, "wxEVT_WINDOW_MODAL_DIALOG_CLOSED") - ,make_pair((wxEventType)wxID_ANY, "wxID_ANY") - }; - - for (int i = 0; allEvents[i].first != wxID_ANY; i++) { - eventmap[allEvents[i].first]= allEvents[i].second; - } - -} - -EventLogger::~EventLogger() -{ - delete [] ringbuffer; -} - -void EventLogger::insert(wxEvent& event) -{ - if (ignoreEvents.count(event.GetEventType())) - return; - - std::stringstream ss; - ss << "evt"<< eventcount<< ":"<< " " << event.GetEventType() - <<" " << eventmap[event.GetEventType()] << " : "; - - //Obtain the window data - wxObject *wxObj = event.GetEventObject(); - if(wxObj && wxObj->IsKindOf(CLASSINFO(wxWindow))) - ss<< stlStr(((wxWindow *)wxObj)->GetName()); - - ringbuffer[eventcount] = ss.str(); - eventcount++; - eventcount&=mask; -} - -void EventLogger::dump() -{ - size_t i = eventcount; - do { - *stream << ringbuffer[i&mask] <. - */ - -#ifndef EVENTLOGGER_H -#define EVENTLOGGER_H - -#ifdef DEBUG - -#include -#include -#include -#include - -class EventLogger { -public: - EventLogger(int b, std::ostream *s); - ~EventLogger(); - void insert(wxEvent& event); - void dump(); - void setostream(std::ostream *s); -private: - EventLogger(EventLogger &e); - - int bitshift; - size_t mask; - size_t eventcount; - long prevevt; - size_t ringbuffermax; - std::string *ringbuffer; - std::ostream *stream; - std::map eventmap; - - // events to ignore in the logger - std::set ignoreEvents; -}; - -#endif -#endif diff -Nru 3depict-0.0.12/src/filter.cpp 3depict-0.0.13/src/filter.cpp --- 3depict-0.0.12/src/filter.cpp 2012-11-18 00:43:41.000000000 +0000 +++ 3depict-0.0.13/src/filter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,737 +0,0 @@ -/* - * filter.h - modular data filter implementation - * Copyright (C) 2012, 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 . -*/ - -#include "filter.h" -#include "K3DTree.h" -#include "xmlHelper.h" - -#include "colourmap.h" -#include "mathfuncs.h" - -#include "translation.h" - -#include -#include -#include -#include - -#ifdef _OPENMP -#include -#endif - -using std::list; -using std::vector; -using std::string; -using std::pair; -using std::make_pair; - - - - -bool Filter::strongRandom= false; - -const char *STREAM_NAMES[] = { NTRANS("Ion"), - NTRANS("Plot"), - NTRANS("Draw"), - NTRANS("Range"), - NTRANS("Voxel")}; - -//Internal names for each filter -const char *FILTER_NAMES[] = { "posload", - "iondownsample", - "rangefile", - "spectrumplot", - "ionclip", - "ioncolour", - "compositionprofile", - "boundingbox", - "transform", - "externalprog", - "spatialanalysis", - "clusteranalysis", - "voxelise", - "ioninfo", - "annotation" - }; - -void updateFilterPropertyGrid(wxPropertyGrid *g, const Filter *f) -{ - - ASSERT(f); - ASSERT(g); - - FilterPropGroup p; - f->getProperties(p); -#ifdef DEBUG - //If debugging, test self consistency - p.checkConsistent(); -#endif - g->clearKeys(); - g->setNumGroups(p.numGroups()); - - - //Create the keys to add to the grid - for(size_t ui=0;ui propGrouping; - p.getGroup(ui,propGrouping); - - for(size_t uj=0;ujaddKey(propGrouping[uj].name,ui, - propGrouping[uj].key, - propGrouping[uj].type, - propGrouping[uj].data, - propGrouping[uj].helpText); - } - - //Set the name that is to be displayed for this grouping - // of properties - std::string title; - p.getGroupTitle(ui,title); - g->setGroupName(ui,title); - } - - //Let the property grid layout what it needs to - g->propertyLayout(); -} - -bool parseXMLColour(xmlNodePtr &nodePtr, float &r,float&g,float&b,float&a) -{ - xmlChar *xmlString; - std::string tmpStr; - //--red-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"r"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(r,tmpStr)) - return false; - - //disallow negative or values gt 1. - if(r < 0.0f || r > 1.0f) - return false; - xmlFree(xmlString); - - - //--green-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"g"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(g,tmpStr)) - { - xmlFree(xmlString); - return false; - } - - xmlFree(xmlString); - - //disallow negative or values gt 1. - if(g < 0.0f || g > 1.0f) - return false; - - //--blue-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"b"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(b,tmpStr)) - { - xmlFree(xmlString); - return false; - } - xmlFree(xmlString); - - //disallow negative or values gt 1. - if(b < 0.0f || b > 1.0f) - return false; - - //--Alpha-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"a"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(a,tmpStr)) - { - xmlFree(xmlString); - return false; - } - xmlFree(xmlString); - - //disallow negative or values gt 1. - if(a < 0.0f || a > 1.0f) - return false; - - return true; -} - -size_t numElements(const vector &v, unsigned int mask) -{ - size_t nE=0; - for(unsigned int ui=0;uigetStreamType() & mask)) - nE+=v[ui]->getNumBasicObjects(); - } - - return nE; -} - - -const RangeFile *getRangeFile(const std::vector &dataIn) -{ - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - return ((const RangeStreamData*)(dataIn[ui]))->rangeFile; - } - - ASSERT(false); -} - -unsigned int getIonstreamIonID(const IonStreamData *d, const RangeFile *r) -{ - if(d->data.empty()) - return (unsigned int)-1; - - unsigned int tentativeRange; - - tentativeRange=r->getIonID(d->data[0].getMassToCharge()); - - - //TODO: Currently, we have no choice but to brute force it. - //In the future, it might be worth storing some data inside the IonStreamData itself - //and to use that first, rather than try to brute force the result -#ifdef _OPENMP - bool spin=false; - #pragma omp parallel for shared(spin) - for(size_t ui=1;uidata.size();ui++) - { - if(spin) - continue; - if(r->getIonID(d->data[ui].getMassToCharge()) !=tentativeRange) - spin=true; - } - - //Not a range - if(spin) - return (unsigned int)-1; - -#else - for(size_t ui=1;uidata.size();ui++) - { - if(r->getIonID(d->data[ui].getMassToCharge()) !=tentativeRange) - return (unsigned int)-1; - } -#endif - - return tentativeRange; -} - - -//!Extend a point data vector using some ion data -unsigned int extendPointVector(std::vector &dest, const std::vector &vIonData, - bool (*callback)(bool),unsigned int &progress, size_t offset) -{ - unsigned int curProg=NUM_CALLBACK; - unsigned int n =offset; -#ifdef _OPENMP - //Parallel version - bool spin=false; - #pragma omp parallel for shared(spin) - for(size_t ui=0;ui=groupCount) - { -#ifdef DEBUG - WARN(!(group > (groupCount+1)),"Appeared to add multiple groups in one go - not wrong, just unusual."); -#endif - groupCount=std::max(group+1,groupCount); - groupNames.resize(groupCount,string("")); - } - - keyGroupings.push_back(make_pair(prop.key,group)); - properties.push_back(prop); -} - -void FilterPropGroup::setGroupTitle(size_t group, const std::string &str) -{ - ASSERT(group &vec) const -{ - ASSERT(targetGroup s; - - //Check that each key is unique in the keyGroupings list - for(size_t ui=0;ui::max(); - hardMaxX=hardMaxY=std::numeric_limits::max(); -} - -void PlotStreamData::autoSetHardBounds() -{ - if(xyData.size()) - { - hardMinX=std::numeric_limits::max(); - hardMinY=std::numeric_limits::max(); - hardMaxX=-std::numeric_limits::max(); - hardMaxY=-std::numeric_limits::max(); - - for(size_t ui=0;ui=0 - ASSERT(!(logarithmic && hardMinY < 0) ); - - //hardMin should be <=hardMax - //-- - ASSERT(hardMinX<=hardMaxX); - - ASSERT(hardMinY<=hardMaxY); - //-- - - //If we have regions that can be interacted with, need to have parent - ASSERT(!(regionID.size() && !regionParent)); - - //Must have valid trace style - ASSERT(plotStylegetNumIons() == enabledIons.size()); - - ASSERT(rangeFile->getNumRanges() == enabledIons.size()); - -} -#endif - -FilterStreamData::FilterStreamData() : parent(0),cached((unsigned int)-1) -{ -} - -IonStreamData::IonStreamData() : representationType(ION_REPRESENT_POINTS), - r(1.0f), g(0.0f), b(0.0f), a(1.0f), - ionSize(2.0f), valueType("Mass-to-Charge (amu/e)") -{ - streamType=STREAM_TYPE_IONS; -} - -VoxelStreamData::VoxelStreamData() : representationType(VOXEL_REPRESENT_POINTCLOUD), - r(1.0f),g(0.0f),b(0.0f),a(0.3f), splatSize(2.0f),isoLevel(0.5f) -{ - streamType=STREAM_TYPE_VOXEL; -} - -RangeStreamData::RangeStreamData() : rangeFile(0) -{ - streamType = STREAM_TYPE_RANGE; -} - -bool RangeStreamData::save(const char *filename, size_t format) const -{ - return !rangeFile->write(filename,format); -} - -Filter::Filter() : cache(true), cacheOK(false) -{ - for(unsigned int ui=0;uicached); - delete filterOutputs[ui]; - } - - filterOutputs.clear(); -} - -bool Filter::haveCache() const -{ - return cacheOK; -} - -void Filter::getSelectionDevices(vector *> &outD) -{ - outD.resize(devices.size()); - - std::copy(devices.begin(),devices.end(),outD.begin()); - -#ifdef DEBUG - for(unsigned int ui=0;ui > tmp; - outD[ui]->getModifiedBindings(tmp); - tmp.clear(); - } -#endif -} - -void Filter::updateOutputInfo(const std::vector &dataOut) -{ - //Reset the number ouf output streams to zero - for(unsigned int ui=0;uigetStreamType()) < NUM_STREAM_TYPES); - numStreamsLastRefresh[getBitNum(dataOut[ui]->getStreamType())]++; - } -} - -unsigned int Filter::getNumOutput(unsigned int streamType) const -{ - ASSERT(streamType < NUM_STREAM_TYPES); - return numStreamsLastRefresh[streamType]; -} - -std::string Filter::getUserString() const -{ - if(userString.size()) - return userString; - else - return typeString(); -} - -void Filter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - dataOut.resize(dataIn.size()); - std::copy(dataIn.begin(),dataIn.end(),dataOut.begin()); -} - - - diff -Nru 3depict-0.0.12/src/filter.h 3depict-0.0.13/src/filter.h --- 3depict-0.0.12/src/filter.h 2012-11-18 11:40:16.000000000 +0000 +++ 3depict-0.0.13/src/filter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,619 +0,0 @@ -/* - * filter.h - Data filter header file. - * Copyright (C) 2012, 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 . -*/ -#ifndef FILTER_H -#define FILTER_H -class Filter; -class FilterStreamData; -class ProgressData; -class RangeFileFilter; - - -#include -#include -#include -#include -#include - -#include "drawables.h" -#include "basics.h" -#include "APTClasses.h" -#include "mathfuncs.h" - -#include "select.h" -#include "voxels.h" - -//ifdef inclusion as there is some kind of symbol clash... -#ifdef ATTRIBUTE_PRINTF - #pragma push_macro("ATTRIBUTE_PRINTF") - #include - #pragma pop_macro(" ATTRIBUTE_PRINTF") -#else - #include - #undef ATTRIBUTE_PRINTF -#endif - - -#include "wxcomponents.h" - - -const unsigned int NUM_CALLBACK=50000; - -const unsigned int IONDATA_SIZE=4; - -//!Filter types -- must match array FILTER_NAMES -enum -{ - FILTER_TYPE_DATALOAD, - FILTER_TYPE_IONDOWNSAMPLE, - FILTER_TYPE_RANGEFILE, - FILTER_TYPE_SPECTRUMPLOT, - FILTER_TYPE_IONCLIP, - FILTER_TYPE_IONCOLOURFILTER, - FILTER_TYPE_COMPOSITION, - FILTER_TYPE_BOUNDBOX, - FILTER_TYPE_TRANSFORM, - FILTER_TYPE_EXTERNALPROC, - FILTER_TYPE_SPATIAL_ANALYSIS, - FILTER_TYPE_CLUSTER_ANALYSIS, - FILTER_TYPE_VOXELS, - FILTER_TYPE_IONINFO, - FILTER_TYPE_ANNOTATION, - FILTER_TYPE_ENUM_END // not a filter. just end of enum -}; - -extern const char *FILTER_NAMES[]; - - - -//Stream data types. note that bitmasks are occasionally used, so we are limited in -//the number of stream types that we can have. -//Current bitmask using functions are -// VisController::safeDeleteFilterList -const unsigned int NUM_STREAM_TYPES=5; -const unsigned int STREAMTYPE_MASK_ALL= (1<<(NUM_STREAM_TYPES)) -1; -enum -{ - STREAM_TYPE_IONS=1, - STREAM_TYPE_PLOT=2, - STREAM_TYPE_DRAW=4, - STREAM_TYPE_RANGE=8, - STREAM_TYPE_VOXEL=16 -}; - - -//Keys for binding IDs -enum -{ - BINDING_CYLINDER_RADIUS=1, - BINDING_SPHERE_RADIUS, - BINDING_CYLINDER_ORIGIN, - BINDING_SPHERE_ORIGIN, - BINDING_PLANE_ORIGIN, - BINDING_CYLINDER_DIRECTION, - BINDING_PLANE_DIRECTION, - BINDING_RECT_TRANSLATE, - BINDING_RECT_CORNER_MOVE -}; - -extern const char *STREAM_NAMES[]; - -//Representations -enum -{ - //IonStreamData - ION_REPRESENT_POINTS - -}; - -//Representations -enum -{ - //VoxelStreamData - VOXEL_REPRESENT_POINTCLOUD, - VOXEL_REPRESENT_ISOSURF, - VOXEL_REPRESENT_END -}; - -//Error codes for each of the filters. -//These can be passed to the getErrString() function for -//a human readable error message -//--- - -enum -{ - FILE_TYPE_NULL, - FILE_TYPE_XML, - FILE_TYPE_POS -}; - -//--- -// - -//Forward dec. -class FilterStreamData; - -//!Return the number of elements in a vector of filter data -size_t numElements(const vector &vm, unsigned int mask=STREAMTYPE_MASK_ALL); - -bool parseXMLColour(xmlNodePtr &nodePtr, float &r, float&g, float&b, float&a); - -void updateFilterPropertyGrid(wxPropertyGrid *g, const Filter *f); - - - //!Abstract base class for data types that can propagate through filter system -class FilterStreamData -{ - protected: - unsigned int streamType; - public: - //!Parent filter pointer - const Filter *parent; - - //!Tells us if the filter has cacehd this data for later use. - //this is a boolean value, but not declared as such, as there - //are debug traps to tell us if this is not set by looking for non-boolean values. - unsigned int cached; - - FilterStreamData(); - virtual ~FilterStreamData() {}; - virtual size_t getNumBasicObjects() const =0; - //!Returns an integer unique to the clas to identify type (yes rttid...) - virtual unsigned int getStreamType() const {return streamType;} ; - //!Free mem held by objects - virtual void clear()=0; - -#ifdef DEBUG - //Cross-checks fields to determine if (best guess) - ///data structure has a sane combination of values - virtual void checkSelfConsistent() const {} -#endif - -}; - -class FilterProperty -{ - public: - //!Human readable short help (tooltip) for each of the keys - std::string helpText; - //!Data type for this element - unsigned int type; - //!Unique key value for this element - size_t key; - //!Property data - std::string data; - //!name of property - std::string name; - - bool checkSelfConsistent() const; -}; - -class FilterPropGroup -{ - private: - //!The groupings for the keys in contained properties. - // First entry is the key ID, second is he group that it belongs to - std::vector > keyGroupings; - //!Names for each group of keys. - std::vector groupNames; - //!Key information - std::vector properties; - - size_t groupCount; - public: - FilterPropGroup() { groupCount=0;} - //!Add a property to a grouping - void addProperty(const FilterProperty &prop, size_t group); - - - //!Set the title text for a particular group - void setGroupTitle(size_t group, const std::string &str); - - //!Obtain the title of the nth group - void getGroupTitle(size_t group, std::string &str) const ; - - //Obtain a property by its key - const FilterProperty &getPropValue(size_t key) const; - - //Retrieve the number of groups - size_t numGroups() const { return groupCount;}; - - bool hasProp(size_t key) const; - //Get number of keys - size_t numProps() const { return properties.size(); } - //Erase all stored information - void clear() - { groupNames.clear();keyGroupings.clear(); properties.clear(); - groupCount=0;} - - //!Grab all properties from the specified group - void getGroup(size_t group, vector &groupVec) const; - //!Get the nth key - const FilterProperty &getNthProp(size_t nthProp) const { return properties[nthProp];}; - -#ifdef DEBUG - void checkConsistent() const; -#endif - -}; - -//!Point with m-t-c value data -class IonStreamData : public FilterStreamData -{ -public: - IonStreamData(); - void clear(); - size_t getNumBasicObjects() const { return data.size();}; - - unsigned int representationType; - float r,g,b,a; - float ionSize; - - //!The name for the type of data -- nominally "mass-to-charge" - std::string valueType; - - //!Apply filter to input data stream - std::vector data; -}; - -//!Point with m-t-c value data -class VoxelStreamData : public FilterStreamData -{ -public: - VoxelStreamData(); - size_t getNumBasicObjects() const { return data.getSize();}; - void clear(); - - unsigned int representationType; - float r,g,b,a; - float splatSize; - float isoLevel; - //!Apply filter to input data stream - Voxels data; - -}; - -//!Plotting data -class PlotStreamData : public FilterStreamData -{ - public: - PlotStreamData(); - - bool save(const char *filename) const; - - //erase plot contents - void clear() {xyData.clear();}; - //Get data size - size_t getNumBasicObjects() const { return xyData.size();}; - - //Use the contained XY data to set hard plot bounds - void autoSetHardBounds(); - //plot colour - float r,g,b,a; - //plot trace mode - enum PLOT_TRACE - unsigned int plotStyle; - //plot mode - enum PLOT_MODE - unsigned int plotMode; - - //use logarithmic mode? - bool logarithmic; - //title for data - std::string dataLabel; - //Label for X, Y axes - std::string xLabel,yLabel; - - //!When showing raw XY data, is the data - // label a better descriptor of Y than the y-label? - bool useDataLabelAsYDescriptor; - - //!XY data pairs for plotting curve - std::vector > xyData; - //!Rectangular marked regions - vector > regions; - //!Region colours - vector regionR,regionB,regionG; - - //!Region indicies from parent region - vector regionID; - - //!Region parent filter pointer, used for matching interaction - // with region to parent property - Filter *regionParent; - //!Parent filter index - unsigned int index; - //!Error bar mode - PLOT_ERROR errDat; - - //!Hard bounds that cannot be exceeded when drawing plot - float hardMinX,hardMaxX,hardMinY,hardMaxY; - -#ifdef DEBUG - //Cross-checks fields to determine if (best guess) - ///data structure has a sane combination of values - virtual void checkSelfConsistent() const; -#endif - -}; - -//!Drawable objects, for 3D decoration. -class DrawStreamData: public FilterStreamData -{ - public: - //!Vector of 3D objects to draw. - vector drawables; - //!constructor - DrawStreamData(){ streamType=STREAM_TYPE_DRAW;}; - //!Destructor - ~DrawStreamData(); - //!Returns 0, as this does not store basic object types -- i.e. is not for data storage per se. - size_t getNumBasicObjects() const { return 0; } - - //!Erase the drawing vector, deleting its componets - void clear(); -#ifdef DEBUG - //Cross-checks fields to determine if (best guess) - ///data structure has a sane combination of values - void checkSelfConsistent() const; -#endif -}; - -//!Range file propagation -class RangeStreamData : public FilterStreamData -{ - public: - //!range file filter from whence this propagated. Do not delete[] pointer at all, this class does not OWN the range data - //it merely provides access to existing data. - RangeFile *rangeFile; - //Enabled ranges from source filter - vector enabledRanges; - //Enabled ions from source filter - vector enabledIons; - - - //!constructor - RangeStreamData(); - //!Destructor - ~RangeStreamData() {}; - //!save the range data to a file - bool save(const char *filename, size_t format) const; - //!Returns 0, as this does not store basic object types -- i.e. is not for data storage per se. - size_t getNumBasicObjects() const { return 0; } - - //!Unlink the pointer - void clear() { rangeFile=0;enabledRanges.clear();enabledIons.clear();}; - -#ifdef DEBUG - void checkSelfConsistent() const ; -#endif -}; - -//FIXME: Lookup how to use static members. cant remember of top of my head. no interwebs. -//float Filter::drawScale; -const float drawScale=10.0f; //Use const for now. - -//!Abstract base filter class. -class Filter -{ - protected: - - bool cache, cacheOK; - static bool strongRandom; - - bool wantMonitor; - - //!Array of the number of streams propagated on last refresh - //THis is initialised to -1, which is considered invalid - unsigned int numStreamsLastRefresh[NUM_STREAM_TYPES]; - - - //!temporary console output. Should be only nonzero size immediately after refresh - vector consoleOutput; - //!User settable labelling string (human readable ID, etc etc) - std::string userString; - //Filter output cache - std::vector filterOutputs; - //!User interaction "Devices" associated with this filter - std::vector *> devices; - public: - Filter() ; - virtual ~Filter(); - - //Pure virtual functions - //==== - //!Duplicate filter contents, excluding cache. - virtual Filter *cloneUncached() const = 0; - - //!Apply filter to new data, updating cache as needed. Vector of returned pointers must be deleted manually, first checking ->cached. - virtual unsigned int refresh(const std::vector &dataIn, - std::vector &dataOut, - ProgressData &progress, bool (*callback)(bool)) =0; - //!Erase cache - virtual void clearCache(); - - //!Erase any active devices - virtual void clearDevices(); - - //!Get (approx) number of bytes required for cache - virtual size_t numBytesForCache(size_t nObjects) const =0; - - //!return type ID - virtual unsigned int getType() const=0; - - //!Return filter type as std::string - virtual std::string typeString()const =0; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - virtual void getProperties(FilterPropGroup &propertyList) const =0; - - //!Set the properties for the nth filter, - //!needUpdate tells us if filter output changes due to property set - //NOte that if you modify a result without clearing the cache, - //then any downstream decision based upon that may not be noted in an update - //Take care. - virtual bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate) = 0; - - //!Get the human readable error string associated with a particular error code during refresh(...) - virtual std::string getErrString(unsigned int code) const =0; - - //!Dump state to output stream, using specified format - /* Current supported formats are STATE_FORMAT_XML - */ - virtual bool writeState(std::ostream &f, unsigned int format, - unsigned int depth=0) const = 0; - - //!Read state from XML stream, using xml format - /* Current supported formats are STATE_FORMAT_XML - */ - virtual bool readState(xmlNodePtr& n, const std::string &packDir="") = 0; - - //!Get the bitmask encoded list of filterStreams that this filter blocks from propagation. - // i.e. if this filterstream is passed to refresh, it is not emitted. - // This MUST always be consistent with ::refresh for filters current state. - virtual unsigned int getRefreshBlockMask() const =0; - - //!Get the bitmask encoded list of filterstreams that this filter emits from ::refresh. - // This MUST always be consistent with ::refresh for filters current state. - virtual unsigned int getRefreshEmitMask() const = 0; - - - //!Mask of filter streams that will not examined by the filter in its computation. - // note that these *may* be emitted as a pass-through - check emitmask if needed - virtual unsigned int getRefreshUseMask() const =0; - - //==== - - //!Return the unique name for a given filter -- DO NOT TRANSLATE - string trueName() const { return FILTER_NAMES[getType()];}; - - - - //!Initialise the filter's internal state using limited filter stream data propagation - //NOTE: CONTENTS MAY NOT BE CACHED. - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - - - //!Return the XML elements that refer to external entities (i.e. files) which do not move with the XML file - //Each element is to be referred to using "/" as entity separator, for the first pair element, and the attribute name for the second. - virtual void getStateOverrides(std::vector &overrides) const {}; - - //!Enable/disable caching for this filter - void setCaching(bool enableCache) {cache=enableCache;}; - - //!Have cached output data? - bool haveCache() const; - - - //!Return a user-specified string, or just the typestring if user set string not active - virtual std::string getUserString() const ; - //!Set a user-specified string return value is - virtual void setUserString(const std::string &str) { userString=str;}; - - - //!Modified version of writeState for packaging. By default simply calls writeState. - //value overrides override the values returned by getStateOverrides. In order. - virtual bool writePackageState(std::ostream &f, unsigned int format, - const std::vector &valueOverrides,unsigned int depth=0) const {return writeState(f,format,depth);}; - - - - //!Get the selection devices for this filter. MUST be called after refresh() - /*No checking is done that the selection devices will not interfere with one - * 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 *> &devices); - - - //!Update the output statistics for this filter (num items of streams of each type output) - void updateOutputInfo(const std::vector &dataOut); - - //!Set the binding value for a float - virtual void setPropFromBinding(const SelectionBinding &b)=0; - - //!Set a region update - virtual void setPropFromRegion(unsigned int method, unsigned int regionID, float newPos){ASSERT(false);}; - - //!Can this filter perform actions that are potentially a security concern? - virtual bool canBeHazardous() const {return false;} ; - - //!Get the number of outputs for the specified type during the filter's last refresh - unsigned int getNumOutput(unsigned int streamType) const; - - //!Get the filter messages from the console -- also deletes the - // console messages as a side-effect - void getConsoleStrings(std::vector &v) { v.resize(consoleOutput.size());std::copy(consoleOutput.begin(),consoleOutput.end(),v.begin()); consoleOutput.clear();}; - - //!Should filters use strong randomisation (where applicable) or not? - static void setStrongRandom(bool strongRand) {strongRandom=strongRand;}; - - //Check to see if the filter needs to be refreshed - virtual bool monitorNeedsRefresh() const { return false;}; - - //Are we a pure data source - i.e. can function with no input - virtual bool isPureDataSource() const { return false;}; - - //Can we be a useful filter, even if given no input specified by the Use mask? - virtual bool isUsefulAsAppend() const { return false;} -#ifdef DEBUG - //!Run all the registered unit tests for this filter - virtual bool runUnitTests() { cerr << "No test for " << typeString() << endl; return true;} ; - //!Is the filter caching? - bool cacheEnabled() const {return cache;}; -#endif - -}; - - -//!Class that tracks the progress of scene updates -class ProgressData -{ - public: - //!Progress of filter (out of 100) for current filter - unsigned int filterProgress; - //!Number of filters (n) that we have proccessed (n out of m filters) - unsigned int totalProgress; - - //!number of filters which need processing for this update - unsigned int totalNumFilters; - - //!Current step - unsigned int step; - //!Maximum steps - unsigned int maxStep; - - //!Pointer to the current filter that is being updated. Only valid during an update callback - const Filter *curFilter; - - //!Name of current operation, if specified - std::string stepName; - - void reset() { filterProgress=totalProgress=step=maxStep=0;curFilter=0; stepName.clear();}; - void clock() { filterProgress=step=maxStep=0;curFilter=0;totalProgress++; stepName.clear();}; -}; - - -unsigned int getIonstreamIonID(const IonStreamData *d, const RangeFile *r); - -//!Extend a point data vector using some ion data -unsigned int extendPointVector(std::vector &dest, const std::vector &vIonData, - bool (*callback)(bool),unsigned int &progress, size_t offset); - -const RangeFile *getRangeFile(const std::vector &dataIn); - -#endif diff -Nru 3depict-0.0.12/src/filters/allFilter.cpp 3depict-0.0.13/src/filters/allFilter.cpp --- 3depict-0.0.12/src/filters/allFilter.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/allFilter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -#include "allFilter.h" - - -//Filter "factory" type function. If this gets too big, -//we could use a pre-populated hashtable in -//a static class to speed things up. -//returns null pointer if string is invalid -Filter *makeFilter(const std::string &s) -{ - Filter *f; - unsigned int type=(unsigned int)-1; - for(unsigned int ui=0;uitrueName() == s); -#endif - return f; -} - -Filter *makeFilter(unsigned int ui) -{ - Filter *f; - - switch(ui) - { - case FILTER_TYPE_DATALOAD: - f=new DataLoadFilter; - break; - case FILTER_TYPE_IONDOWNSAMPLE: - f=new IonDownsampleFilter; - break; - case FILTER_TYPE_RANGEFILE: - f=new RangeFileFilter; - break; - case FILTER_TYPE_SPECTRUMPLOT: - f=new SpectrumPlotFilter; - break; - case FILTER_TYPE_IONCLIP: - f=new IonClipFilter; - break; - case FILTER_TYPE_IONCOLOURFILTER: - f=new IonColourFilter; - break; - case FILTER_TYPE_IONINFO: - f=new IonInfoFilter; - break; - case FILTER_TYPE_COMPOSITION: - f=new CompositionProfileFilter; - break; - case FILTER_TYPE_BOUNDBOX: - f = new BoundingBoxFilter; - break; - case FILTER_TYPE_TRANSFORM: - f= new TransformFilter; - break; - case FILTER_TYPE_EXTERNALPROC: - f= new ExternalProgramFilter; - break; - case FILTER_TYPE_SPATIAL_ANALYSIS: - f = new SpatialAnalysisFilter; - break; - case FILTER_TYPE_CLUSTER_ANALYSIS: - f = new ClusterAnalysisFilter; - break; - case FILTER_TYPE_VOXELS: - f = new VoxeliseFilter; - break; - case FILTER_TYPE_ANNOTATION: - f = new AnnotateFilter; - break; - default: - ASSERT(false); - } - - return f; -} - -Filter *makeFilterFromDefUserString(const std::string &s) -{ - //This is a bit of a hack. Build each object, then retrieve its string. - //Could probably use static functions and type casts to improve this - for(unsigned int ui=0;uitypeString()) - return t; - - delete t; - } - - ASSERT(false); -} diff -Nru 3depict-0.0.12/src/filters/allFilter.h 3depict-0.0.13/src/filters/allFilter.h --- 3depict-0.0.12/src/filters/allFilter.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/allFilter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#ifndef ALLFILTER_H -#define ALLFILTER_H -#include "boundingBox.h" -#include "ionDownsample.h" -#include "dataLoad.h" -#include "compositionProfile.h" -#include "externalProgram.h" -#include "ionClip.h" -#include "ionColour.h" -#include "rangeFile.h" -#include "clusterAnalysis.h" -#include "spatialAnalysis.h" -#include "spectrumPlot.h" -#include "transform.h" -#include "voxelise.h" -#include "ionInfo.h" -#include "annotation.h" - -//!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_* -Filter *makeFilter(unsigned int ui) ; - -//!Create a true default filter from its type string -Filter *makeFilterFromDefUserString(const string &s) ; - -#endif diff -Nru 3depict-0.0.12/src/filters/annotation.cpp 3depict-0.0.13/src/filters/annotation.cpp --- 3depict-0.0.12/src/filters/annotation.cpp 2012-11-18 10:54:19.000000000 +0000 +++ 3depict-0.0.13/src/filters/annotation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1843 +0,0 @@ -#include "annotation.h" - -#include "../xmlHelper.h" - -//grab size when doing convex hull calculations -const unsigned int HULL_GRAB_SIZE=4096; - -enum -{ - KEY_POSITION=1, - KEY_MODE, - KEY_UPVEC, - KEY_ACROSSVEC, - KEY_ANNOTATE_TEXT, - KEY_TARGET, - KEY_COLOUR, - KEY_ARROW_SIZE, - KEY_TEXTSIZE, - KEY_LINESIZE, - KEY_REFLEXIVE, - KEY_SPHERE_ANGLE_SIZE, - KEY_ANGLE_TEXT_VISIBLE, - KEY_ANGLE_FORMAT_STRING, - KEY_LINEAR_FONTSIZE, - KEY_LINEAR_NUMTICKS, - KEY_LINEAR_FIXED_TICKS, - KEY_LINEAR_TICKSPACING, - KEY_ANGLE_POS_ZERO, - KEY_ANGLE_POS_ONE, - KEY_ANGLE_POS_TWO -}; - -enum -{ - BINDING_TEXT_ORIGIN=1, - BINDING_ARROW_ORIGIN, - BINDING_ARROW_VECTOR, - BINDING_ANGLE_ORIGIN, - BINDING_ANGLE_FIRST, - BINDING_ANGLE_SECOND, - BINDING_ANGLE_SPHERERADIUS, - BINDING_LINEAR_ORIGIN, - BINDING_LINEAR_TARGET, - BINDING_LINEAR_SPHERERADIUS -}; - - -const char *annotationModeStrings[] = -{ - NTRANS("Arrow"), - NTRANS("Text"), - NTRANS("Arrow+Text"), - NTRANS("Angle"), - NTRANS("Ruler") -}; - - -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), - reflexAngle(true), angleFormatPreDecimal(0),angleFormatPostDecimal(0), - linearFixedTicks(true),linearMeasureTicks(10),linearMeasureSpacing(10.0f), - fontSizeLinearMeasure(5),linearMeasureMarkerSize(3) -{ - COMPILE_ASSERT(ARRAYSIZE(annotationModeStrings) == ANNOTATION_MODE_END); - - annotationMode=ANNOTATION_TEXT; - - anglePos[0]=Point3D(0,0,0); - anglePos[1]=Point3D(0,5,5); - anglePos[2]=Point3D(0,-5,5); - - textSize=1; - annotateSize=1; - sphereAngleSize=1.5; - - //Set the colour to default blue - r=g=0;b=a=1.0; - - active=true; - showAngleText=true; - - reflexAngle=false; - fontSizeLinearMeasure=5; - linearMeasureTicks=10; - linearFixedTicks=true; - linearMeasureSpacing=10.0f; - linearMeasureMarkerSize=3.0f; - lineSize=1.0f; - angleFormatPreDecimal=angleFormatPostDecimal=0; - - cacheOK=false; - cache=true; //By default, we should cache, but decision is made higher up -} - -Filter *AnnotateFilter::cloneUncached() const -{ - AnnotateFilter *p=new AnnotateFilter(); - - p->annotationMode=annotationMode; - p->position=position; - p->target=target; - p->upVec=upVec; - p->acrossVec=acrossVec; - - for(unsigned int ui=0;ui<3; ui++) - p->anglePos[ui]=anglePos[ui]; - - p->textSize=textSize; - p->annotateSize=annotateSize; - p->sphereAngleSize=sphereAngleSize; - - p->r=r; - p->g=g; - p->b=b; - p->a=a; - - p->active=active; - p->showAngleText=showAngleText; - - p->reflexAngle=reflexAngle; - - p->angleFormatPreDecimal=angleFormatPreDecimal; - p->angleFormatPostDecimal=angleFormatPostDecimal; - - - p->fontSizeLinearMeasure=fontSizeLinearMeasure; - p->linearFixedTicks=linearFixedTicks; - p->linearMeasureSpacing=linearMeasureSpacing; - p->linearMeasureTicks=linearMeasureTicks; - p->linearMeasureMarkerSize=linearMeasureMarkerSize; - p->lineSize=lineSize; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -unsigned int AnnotateFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - - //Clear selection devices, first deleting any we have - clearDevices(); - - //Pipe everything through - getOut.resize(dataIn.size()); - for(size_t ui=0;uiparent=this; - - //Draw text output as needed - if( annotationMode == ANNOTATION_TEXT || - annotationMode== ANNOTATION_TEXT_WITH_ARROW) - { - DrawGLText *dt; - dt = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); - - dt->setString(annotateText); - dt->setOrigin(position); - dt->setUp(upVec); - dt->setColour(r,g,b,a); - dt->setTextDir(acrossVec); - dt->setSize((unsigned int)textSize); - - dt->setAlignment(DRAWTEXT_ALIGN_CENTRE); - - dt->canSelect=true; - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding bind[1]; - - bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_TEXT_BIND_ORIGIN, - BINDING_TEXT_ORIGIN,dt->getOrigin(),dt); - bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(bind[0]); - - - devices.push_back(s); - d->drawables.push_back(dt); - } - - //Draw annnotation mode as needed - if(annotationMode==ANNOTATION_ARROW || - annotationMode==ANNOTATION_TEXT_WITH_ARROW) - { - DrawVector *dv; - dv = new DrawVector; - - dv->setOrigin(position); - dv->setVector(target-position); - dv->setArrowSize(annotateSize); - dv->setColour(r,g,b,a); - dv->setLineSize(lineSize); - - dv->canSelect=true; - dv->wantsLight=true; - - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding bind[2]; - - bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_VECTOR_BIND_TARGET, - BINDING_ARROW_VECTOR,dv->getVector(),dv); - bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(bind[0]); - - - bind[1].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_VECTOR_BIND_ORIGIN, - BINDING_ARROW_ORIGIN,dv->getOrigin(),dv); - bind[1].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(bind[1]); - - - devices.push_back(s); - d->drawables.push_back(dv); - } - - if(annotationMode == ANNOTATION_ANGLE_MEASURE) - { - //Draw the three spheres that are the handles - //for the angle motion - for(unsigned int ui=0;ui<3;ui++) - { - DrawSphere *dS; - SelectionDevice *s= new SelectionDevice(this); - SelectionBinding bind[2]; - - dS=new DrawSphere; - dS->setOrigin(anglePos[ui]); - dS->setRadius(sphereAngleSize); - dS->setColour(r,g,b,a); - - dS->canSelect=true; - dS->wantsLight=true; - - //Create binding for sphere translation. - //Note that each binding is a bit different, as it - //affects each sphere separately. - bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, - BINDING_ANGLE_ORIGIN+ui,anglePos[ui],dS); - bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(bind[0]); - - //Create binding for sphere scaling, each binding is the same - bind[1].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_SPHERE_BIND_RADIUS, - BINDING_ANGLE_SPHERERADIUS,dS->getRadius(),dS); - bind[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); - bind[1].setFloatLimits(0,std::numeric_limits::max()); - - s->addBinding(bind[1]); - - devices.push_back(s); - d->drawables.push_back(dS); - } - - //Now draw the two lines that form the angle - DrawVector *dv; - dv=new DrawVector; - dv->setOrigin(anglePos[0]); - dv->setVector(anglePos[1]-anglePos[0]); - dv->setColour(r,g,b,a); - dv->setDrawArrow(false); - d->drawables.push_back(dv); - - dv=new DrawVector; - dv->setOrigin(anglePos[0]); - dv->setVector(anglePos[2]-anglePos[0]); - dv->setColour(r,g,b,a); - dv->setDrawArrow(false); - d->drawables.push_back(dv); - - - //If required, - //show the text that - //indicates the included or reflexive angle - if(showAngleText) - { - std::string angleString; - - Point3D d1,d2; - float angleVal=0; - - d1=anglePos[1]-anglePos[0]; - d2=anglePos[2]-anglePos[0]; - - //Work out the angle if there is a non-degenerate vector. - //otherwise set it to the "undefined" value of zero - if(fabs(d1.dotProd(d2)) > sqrt(std::numeric_limits::epsilon())) - angleVal =d1.angle(d2); - - if(reflexAngle) - angleVal=2.0*M_PI-angleVal; - angleVal=180.0f/M_PI*angleVal; - angleVal=fmod(angleVal,360.0f); - - //FIXME: print specifier computation is still a bit off - if(angleFormatPreDecimal+angleFormatPostDecimal) - { - //One space for the decimal, one for the null - //and the rest for the actual integer - size_t num; - num = angleFormatPreDecimal+angleFormatPostDecimal+1; - char *buf = new char[num+1]; - - std::string tmp,formatStr; - formatStr="%"; - if(angleFormatPreDecimal) - { - - stream_cast(tmp,angleFormatPreDecimal + angleFormatPostDecimal+2); - formatStr+=std::string("0") + tmp; - } - - if(angleFormatPostDecimal) - { - - stream_cast(tmp,angleFormatPostDecimal); - formatStr+="."; - formatStr+=tmp; - } - formatStr+="f"; - - snprintf(buf,num,formatStr.c_str(),angleVal); - angleString=buf; - delete[] buf; - - } - else - stream_cast(angleString, angleVal); - - //Place the string appropriately - DrawGLText *dt; - dt = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); - - dt->setString(angleString); - dt->setAlignment(DRAWTEXT_ALIGN_CENTRE); - //Place the text using - //a factor of the text size in - //the direction of the average - //of the two vector components - Point3D averageVec(1,0,0); - if(averageVec.sqrMag() > std::numeric_limits::epsilon()) - { - averageVec = (d1+d2)*0.5f; - averageVec.normalise(); - averageVec*=textSize*1.1; - if(reflexAngle) - averageVec.negate(); - } - dt->setOrigin(anglePos[0]+averageVec); - //Use user-specifications for colour, - //size and orientation - dt->setUp(upVec); - dt->setColour(r,g,b,a); - dt->setTextDir(acrossVec); - dt->setSize((unsigned int)textSize); - - - d->drawables.push_back(dt); - } - } - - if(annotationMode == ANNOTATION_LINEAR_MEASURE) - { - DrawVector *dv; - dv = new DrawVector; - - dv->setOrigin(position); - dv->setColour(r,g,b,a); - dv->setVector(target-position); - dv->setDrawArrow(false); - - d->drawables.push_back(dv); - - //Compute the tick spacings - vector tickSpacings; - if(linearFixedTicks) - { - tickSpacingsFromFixedNum(0,sqrt(target.sqrDist(position)), - linearMeasureTicks,tickSpacings); - } - else - { - tickSpacingsFromInterspace(0,sqrt(target.sqrDist(position)), - linearMeasureSpacing,tickSpacings); - } - - if(tickSpacings.size()) - { - - Point3D measureNormal; - measureNormal = target-position; - measureNormal.normalise(); - - //Construct the drawable text object - DrawGLText *dT; - for(unsigned int ui=0;uisetColour(r,g,b,a); - dT->setOrigin(measureNormal*tickSpacings[ui] + position); - dT->setUp(upVec); - dT->setTextDir(acrossVec); - dT->setSize((unsigned int)fontSizeLinearMeasure); - - string s; - stream_cast(s,tickSpacings[ui]); - - dT->setString(s); - - d->drawables.push_back(dT); - } - - - //Now draw the end markers - - //Start marker - DrawSphere *dS; - dS = new DrawSphere; - dS->setRadius(linearMeasureMarkerSize); - dS->setOrigin(position); - dS->setColour(r,g,b,a); - - dS->canSelect=true; - dS->wantsLight=true; - - SelectionDevice *s= new SelectionDevice(this); - SelectionBinding bind[4]; - //Create binding for sphere translation. - //Note that each binding is a bit different, as it - //affects each sphere separately. - bind[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, - BINDING_LINEAR_ORIGIN,position,dS); - bind[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(bind[0]); - - //Create binding for sphere scaling, each binding is the same - bind[1].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_SPHERE_BIND_RADIUS, - BINDING_LINEAR_SPHERERADIUS,dS->getRadius(),dS); - bind[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); - bind[1].setFloatLimits(0,std::numeric_limits::max()); - - s->addBinding(bind[1]); - - devices.push_back(s); - d->drawables.push_back(dS); - - - //Now do the second sphere (end marker) - s= new SelectionDevice(this); - dS = new DrawSphere; - - dS->setRadius(linearMeasureMarkerSize); - dS->setOrigin(target); - dS->setColour(r,g,b,a); - - dS->canSelect=true; - dS->wantsLight=true; - - bind[2].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, - BINDING_LINEAR_TARGET,target,dS); - bind[2].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(bind[2]); - - //Create binding for sphere scaling, each binding is the same - bind[3].setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_SPHERE_BIND_RADIUS, - BINDING_LINEAR_SPHERERADIUS,dS->getRadius(),dS); - bind[3].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); - bind[3].setFloatLimits(0,std::numeric_limits::max()); - s->addBinding(bind[3]); - - - devices.push_back(s); - d->drawables.push_back(dS); - - - } - } - - d->cached=0; - getOut.push_back(d); - - return 0; -} - -size_t AnnotateFilter::numBytesForCache(size_t nObjects) const -{ - return 0; -} - -void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const -{ - string str; - FilterProperty p; - size_t curGroup=0; - - vector > choices; - string tmpStr; - - for(unsigned int ui=0;ui::epsilon()) - return false; - - acrossVec=normVec.crossProd(newPt); - - ASSERT(acrossVec.sqrMag() > std::numeric_limits::epsilon()); - - if(!(upVec == newPt)) - { - upVec=newPt; - needUpdate=true; - } - - break; - } - case KEY_ACROSSVEC: - { - //This sets the up direction - //which must be normal to the - //across direction for the text. - // - //Compute the normal component of acrossVec. - //and override that. - // - //Be careful not to "invert" the text, so it - //does not show. - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - newPt.normalise(); - - //Use double-cross-product method - //to orthogonalise the two vectors - Point3D normVec; - normVec=newPt.crossProd(upVec); - - if(normVec.sqrMag() < std::numeric_limits::epsilon()) - return false; - - upVec=normVec.crossProd(newPt); - - ASSERT(upVec.sqrMag() > std::numeric_limits::epsilon()); - - if(!(acrossVec == newPt)) - { - acrossVec=newPt; - needUpdate=true; - } - - break; - } - case KEY_POSITION: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(acrossVec == newPt)) - { - position=newPt; - needUpdate=true; - } - - break; - } - case KEY_TARGET: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(target== newPt)) - { - target=newPt; - needUpdate=true; - } - - break; - } - case KEY_ANGLE_POS_ZERO: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(anglePos[0]== newPt)) - { - anglePos[0]=newPt; - needUpdate=true; - } - break; - } - case KEY_ANGLE_POS_ONE: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(anglePos[1]== newPt)) - { - anglePos[1]=newPt; - needUpdate=true; - } - break; - } - case KEY_ANGLE_POS_TWO: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(anglePos[2]== newPt)) - { - anglePos[2]=newPt; - needUpdate=true; - } - break; - } - case KEY_ARROW_SIZE: - { - float tmp; - if(stream_cast(tmp,value)) - return false; - - if(tmp!=annotateSize) - { - annotateSize=tmp; - needUpdate=true; - } - - break; - } - case KEY_ANNOTATE_TEXT: - { - if(value!=annotateText) - { - needUpdate=true; - annotateText=value; - } - - break; - } - case KEY_COLOUR: - { - unsigned char newR,newG,newB,newA; - - parseColString(value,newR,newG,newB,newA); - - if(newB != b || newR != r || - newG !=g || newA != a) - { - r=(float)newR/255.0; - g=(float)newG/255.0; - b=(float)newB/255.0; - a=(float)newA/255.0; - - needUpdate=true; - } - else - needUpdate=false; - break; - } - case KEY_TEXTSIZE: - { - float tmp; - stream_cast(tmp,value); - if(fabs(tmp-textSize) > std::numeric_limits::epsilon() - && tmp > sqrt(std::numeric_limits::epsilon())) - { - needUpdate=true; - textSize=tmp; - } - - break; - } - case KEY_REFLEXIVE: - { - bool tmp; - tmp=(value=="1"); - - if(tmp==reflexAngle) - return false; - - reflexAngle=tmp; - - needUpdate=true; - break; - } - case KEY_SPHERE_ANGLE_SIZE: - { - float tmp; - stream_cast(tmp,value); - - if(tmp == sphereAngleSize) - return false; - - sphereAngleSize=tmp; - needUpdate=true; - - break; - } - case KEY_ANGLE_TEXT_VISIBLE: - { - bool tmp; - tmp=(value=="1"); - - if(tmp == showAngleText) - return false; - - showAngleText=tmp; - needUpdate=true; - - break; - } - - case KEY_ANGLE_FORMAT_STRING: - { - //Must contain only #,[0-9] - if(value.find_first_not_of("#,.0123456789")!=std::string::npos) - return false; - - if(value.size()) - { - //Must contain 0 or 1 separator. - size_t sepCount; - sepCount=std::count(value.begin(),value.end(),','); - sepCount+=std::count(value.begin(),value.end(),'.'); - if(sepCount > 1) - return false; - - //If we have a separator, - //split into two parts - if(sepCount) - { - size_t decPos; - decPos=value.find_first_of(",."); - angleFormatPreDecimal=decPos; - angleFormatPostDecimal=value.size()-(decPos+1); - } - else - angleFormatPreDecimal=value.size(); - - } - else - angleFormatPreDecimal=angleFormatPostDecimal=0; - - needUpdate=true; - break; - } - - case KEY_LINEAR_FONTSIZE: - { - unsigned int tmp; - stream_cast(tmp,value); - - if(tmp == fontSizeLinearMeasure) - return false; - - fontSizeLinearMeasure=tmp; - needUpdate=true; - break; - } - case KEY_LINEAR_FIXED_TICKS: - { - bool tmpTicks; - - if(value == "0") - tmpTicks=false; - else if(value =="1") - tmpTicks=true; - else - return false; - - if(tmpTicks == linearFixedTicks) - return false; - - needUpdate=true; - linearFixedTicks=tmpTicks; - break; - - } - case KEY_LINEAR_NUMTICKS: - { - unsigned int tmp; - stream_cast(tmp,value); - - if(tmp == linearMeasureTicks) - return false; - - linearMeasureTicks=tmp; - needUpdate=true; - - break; - } - case KEY_LINEAR_TICKSPACING: - { - float tmp; - stream_cast(tmp,value); - - if(tmp == linearMeasureSpacing) - return false; - - linearMeasureSpacing=tmp; - needUpdate=true; - - break; - } - case KEY_LINESIZE: - { - float tmp; - stream_cast(tmp,value); - - if(tmp == lineSize || tmp <0) - return false; - - lineSize=tmp; - needUpdate=true; - break; - } - - default: - ASSERT(false); - } - - return true; -} - -std::string AnnotateFilter::getErrString(unsigned int code) const -{ - ASSERT(false); -} - -bool AnnotateFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0;ui<3;ui++) - f << tabs(depth+2) << "" << endl; - f << tabs(depth+1) << "" << endl; - - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - std::string colourString; - genColString((unsigned char)(r*255),(unsigned char)(g*255), - (unsigned char)(b*255),(unsigned char)(a*255),colourString); - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool AnnotateFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - using std::string; - string tmpStr; - - xmlChar *xmlString; - - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - //Annotation mode - if(!XMLGetNextElemAttrib(nodePtr,annotationMode,"annotationmode","value")) - return false; - - if(annotationMode >=ANNOTATION_MODE_END) - return false; - - //position - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"position","value")) - return false; - - if(!parsePointStr(tmpStr,position)) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"target","value")) - return false; - - if(!parsePointStr(tmpStr,target)) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"upvec","value")) - return false; - - if(!parsePointStr(tmpStr,upVec)) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"acrossvec","value")) - return false; - - if(!parsePointStr(tmpStr,acrossVec)) - return false; - - //Ensure acrossVec/upvec orthogonal - if(!upVec.orthogonalise(acrossVec)) - return false; - - xmlNodePtr tmpPtr; - tmpPtr=nodePtr; - - if(XMLHelpFwdToElem(nodePtr,"anglepos")) - return false; - - if(!nodePtr->xmlChildrenNode) - return false; - - nodePtr=nodePtr->xmlChildrenNode; - - for(unsigned int ui=0;ui<3;ui++) - { - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"position","value")) - return false; - - if(!parsePointStr(tmpStr,anglePos[ui])) - return false; - } - - nodePtr=tmpPtr; - - //If it fails, thats OK, just use the empty string. - if(!XMLGetNextElemAttrib(nodePtr,annotateText,"annotatetext","value")) - annotateText=""; - - if(!XMLGetNextElemAttrib(nodePtr,textSize,"textsize","value")) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,annotateSize,"annotatesize","value")) - return false; - - if(annotateSize <0.0f) - return false; - - - if(!XMLGetNextElemAttrib(nodePtr,sphereAngleSize,"sphereanglesize","value")) - return false; - if(sphereAngleSize<0.0f) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,lineSize,"linesize","value")) - return false; - if(lineSize<0.0f) - return false; - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"colour","value")) - return false; - - unsigned char rc,gc,bc,ac; - if(!parseColString(tmpStr,rc,gc,bc,ac)) - return false; - r=(float)(rc)/255.0f; - g=(float)(gc)/255.0f; - b=(float)(bc)/255.0f; - a=(float)(ac)/255.0f; - - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"active","value")) - return false; - - if(!(tmpStr=="0" || tmpStr=="1")) - return false; - - active = (tmpStr=="1"); - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"showangletext","value")) - return false; - - if(!(tmpStr=="0" || tmpStr=="1")) - return false; - - showAngleText = (tmpStr=="1"); - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"reflexangle","value")) - return false; - - if(!(tmpStr=="0" || tmpStr=="1")) - return false; - - reflexAngle = (tmpStr=="1"); - - if(!XMLGetNextElemAttrib(nodePtr,angleFormatPreDecimal,"angleformat","predecimal")) - return false; - - if(!XMLGetAttrib(nodePtr,angleFormatPostDecimal,"predecimal")) - return false; - - - return true; -} - -unsigned int AnnotateFilter::getRefreshBlockMask() const -{ - return 0; -} - -unsigned int AnnotateFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_DRAW; -} - -unsigned int AnnotateFilter::getRefreshUseMask() const -{ - //annotate only adds to the ignore mask, so - // we now essentially ignore all inputs, other than pass-through - return 0; -} - -void AnnotateFilter::setPropFromBinding(const SelectionBinding &b) -{ - switch(b.getID()) - { - case BINDING_ARROW_ORIGIN: - { - Point3D dv; - dv=target-position; - b.getValue(position); - target=position+dv; - break; - } - case BINDING_LINEAR_ORIGIN: - case BINDING_TEXT_ORIGIN: - { - b.getValue(position); - break; - } - case BINDING_LINEAR_TARGET: - case BINDING_ARROW_VECTOR: - { - b.getValue(target); - break; - } - case BINDING_ANGLE_ORIGIN: - b.getValue(anglePos[0]); - break; - case BINDING_ANGLE_FIRST: - b.getValue(anglePos[1]); - break; - case BINDING_ANGLE_SECOND: - b.getValue(anglePos[2]); - break; - case BINDING_ANGLE_SPHERERADIUS: - b.getValue(sphereAngleSize); - break; - default: - ASSERT(false); - } -} - - -#ifdef DEBUG - -//Test the ruler functionality -bool rulerTest(); -//Test the angle measurement tool -bool angleTest(); -//Test the pointing arrow annotation -bool arrowTest(); -//Test the text+arrow functionality -bool textArrowTest(); - - -bool AnnotateFilter::runUnitTests() -{ - if(!rulerTest()) - return false; - - if(!angleTest()) - return false; - - if(!arrowTest()) - return false; - - if(!textArrowTest()) - return false; - - return true; -} - - -bool rulerTest() -{ - vector streamIn,streamOut; - AnnotateFilter*f=new AnnotateFilter; - f->setCaching(false); - - bool needUp; std::string s; - //Set linear ruler mode - f->setProperty(KEY_MODE,annotationModeStrings[ANNOTATION_LINEAR_MEASURE],needUp); - //Set ruler position & length - stream_cast(s,Point3D(0,0,0)); - f->setProperty(KEY_POSITION,s,needUp); - stream_cast(s,Point3D(1,1,1)); - f->setProperty(KEY_TARGET,s,needUp); - stream_cast(s,sqrt(2)/10); - f->setProperty(KEY_LINEAR_TICKSPACING,s,needUp); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - - delete f; - - - TEST(streamOut.size(),"stream size"); - - //Count the number of text object types - size_t textCount,vecCount,otherDrawCount; - textCount=vecCount=otherDrawCount=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_DRAW: - { - const DrawStreamData* d; - d= (const DrawStreamData*)streamOut[ui]; - for(unsigned int ui=0;uidrawables.size();ui++) - { - switch(d->drawables[ui]->getType()) - { - case DRAW_TYPE_GLTEXT: - textCount++; - break; - case DRAW_TYPE_VECTOR: - vecCount++; - break; - default: - otherDrawCount++; - break; - } - - } - break; - } - default: - ; - } - - } - - //We should have a line, one would hope - TEST(vecCount>0,"Number of lines in ruler test"); - //Floating pt errors, and not setting the zero could alter this - //so it should be close to, but not exactly 10 - TEST(textCount == 10 || textCount == 9 || textCount == 11, - "Number of lines in ruler test"); - - for(unsigned int ui=0;ui streamIn,streamOut; - AnnotateFilter*f=new AnnotateFilter; - f->setCaching(false); - - bool needUp; std::string s; - //Set arrow annotation mode - f->setProperty(KEY_MODE,annotationModeStrings[ANNOTATION_ANGLE_MEASURE],needUp); - //Set position & target for arrow - const Point3D ANGLE_ORIGIN(0,0,0); - const Point3D ANGLE_A(0,0,1); - const Point3D ANGLE_B(0,1,0); - stream_cast(s,ANGLE_ORIGIN); - f->setProperty(KEY_ANGLE_POS_ONE,s,needUp); - stream_cast(s,ANGLE_A); - f->setProperty(KEY_ANGLE_POS_ZERO,s,needUp); - stream_cast(s,ANGLE_B); - f->setProperty(KEY_ANGLE_POS_TWO,s,needUp); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - - delete f; - - - - TEST(streamOut.size(),"stream size"); - - //Count the number of text object types - size_t vecCount,otherDrawCount,textDrawCount,sphereDrawCount; - vecCount=otherDrawCount=textDrawCount=sphereDrawCount=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_DRAW: - { - const DrawStreamData* d; - d= (const DrawStreamData*)streamOut[ui]; - for(unsigned int ui=0;uidrawables.size();ui++) - { - switch(d->drawables[ui]->getType()) - { - case DRAW_TYPE_VECTOR: - vecCount++; - break; - case DRAW_TYPE_GLTEXT: - textDrawCount++; - break; - case DRAW_TYPE_SPHERE: - sphereDrawCount++; - break; - default: - otherDrawCount++; - break; - } - - } - break; - } - default: - ; - } - } - - - TEST(textDrawCount,"angle text drawable"); - TEST(vecCount,"angle arms drawable"); - TEST(sphereDrawCount,"sphere marker drawable"); - TEST(!otherDrawCount,"unexpected drawable in angle measure"); - - for(unsigned int ui=0;ui streamIn,streamOut; - AnnotateFilter*f=new AnnotateFilter; - f->setCaching(false); - - bool needUp; std::string s; - //Set arrow annotation mode - f->setProperty(KEY_MODE,annotationModeStrings[ANNOTATION_ARROW],needUp); - //Set position & target for arrow - const Point3D ARROW_ORIGIN(-1,-1,-1); - const Point3D ARROW_TARGET(1,1,1); - stream_cast(s,ARROW_ORIGIN); - f->setProperty(KEY_POSITION,s,needUp); - stream_cast(s,ARROW_TARGET); - f->setProperty(KEY_TARGET,s,needUp); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - - delete f; - - - TEST(streamOut.size(),"stream size"); - - //Count the number of text object types - size_t vecCount,otherDrawCount; - vecCount=otherDrawCount=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_DRAW: - { - const DrawStreamData* d; - d= (const DrawStreamData*)streamOut[ui]; - for(unsigned int ui=0;uidrawables.size();ui++) - { - switch(d->drawables[ui]->getType()) - { - case DRAW_TYPE_VECTOR: - { - vecCount++; - const DrawVector *dv; - dv= (const DrawVector*)d->drawables[ui]; - bool testV; - testV=(dv->getOrigin() == ARROW_ORIGIN); - TEST(testV,"Origin test"); - break; - } - default: - otherDrawCount++; - break; - } - - } - break; - } - default: - ; - } - - } - - //We should have a line, one would hope - TEST(vecCount==1,"Number of lines"); - TEST(otherDrawCount==0,"Draw count"); - - for(unsigned int ui=0;ui streamIn,streamOut; - AnnotateFilter*f=new AnnotateFilter; - f->setCaching(false); - - bool needUp; std::string s; - //Set linear ruler mode - f->setProperty(KEY_MODE,annotationModeStrings[ANNOTATION_TEXT_WITH_ARROW],needUp); - //Set ruler position & length - const Point3D ARROW_ORIGIN(-1,-1,-1); - const Point3D ARROW_TARGET(1,1,1); - stream_cast(s,ARROW_ORIGIN); - f->setProperty(KEY_POSITION,s,needUp); - stream_cast(s,ARROW_TARGET); - f->setProperty(KEY_TARGET,s,needUp); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - - delete f; - - - TEST(streamOut.size(),"stream size"); - - //Count the number of text object types - size_t vecCount,textCount,otherDrawCount; - vecCount=textCount=otherDrawCount=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_DRAW: - { - const DrawStreamData* d; - d= (const DrawStreamData*)streamOut[ui]; - for(unsigned int ui=0;uidrawables.size();ui++) - { - switch(d->drawables[ui]->getType()) - { - case DRAW_TYPE_VECTOR: - { - vecCount++; - const DrawVector *dv; - dv= (const DrawVector*)d->drawables[ui]; - bool testV; - testV=(dv->getOrigin() == ARROW_ORIGIN); - TEST(testV,"Origin test"); - break; - } - case DRAW_TYPE_GLTEXT: - textCount++; - break; - default: - otherDrawCount++; - break; - } - - } - break; - } - default: - ; - } - - } - - //We should have a line, one would hope - TEST(vecCount==1,"Number of lines"); - TEST(textCount==1,"Number of text objects"); - TEST(otherDrawCount==0,"No other draw items"); - - for(unsigned int ui=0;uicached. - unsigned int refresh(const std::vector &dataIn, - std::vector &dataOut, - ProgressData &progress, bool (*callback)(bool)); - //!Get (approx) number of bytes required for cache - size_t numBytesForCache(size_t nObjects) const; - - //!return type ID - unsigned int getType() const { return FILTER_TYPE_ANNOTATION;} - - //!Return filter type as std::string - std::string typeString() const { return std::string(TRANS("Annotation"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter, - //!needUpdate tells us if filter output changes due to property set - bool setProperty( unsigned int key, - const std::string &value, bool &needUpdate); - - - void setPropFromBinding( const SelectionBinding &b) ; - - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - /* Current supported formats are STATE_FORMAT_XML - */ - bool writeState(std::ostream &f, unsigned int format, - unsigned int depth) const; - - //!Read state from XML stream, using xml format - /* Current supported formats are STATE_FORMAT_XML - */ - bool readState(xmlNodePtr& n, const std::string &packDir=""); - - //!Get the bitmask encoded list of filterStreams that this filter blocks from propagation. - // i.e. if this filterstream is passed to refresh, it is not emitted. - // This MUST always be consistent with ::refresh for filters current state. - unsigned int getRefreshBlockMask() const; - - //!Get the bitmask encoded list of filterstreams that this filter emits from ::refresh. - // This MUST always be consistent with ::refresh for filters current state. - unsigned int getRefreshEmitMask() const; - - //!Get the refresh's ignore mask - filter streams that will not be considered - // as part of the computation - unsigned int getRefreshUseMask() const; - - //Can we be a useful filter, even if given no input specified by the Use mask? - virtual bool isUsefulAsAppend() const { return true;} -#ifdef DEBUG - bool runUnitTests(); -#endif -}; - - -#endif diff -Nru 3depict-0.0.12/src/filters/boundingBox.cpp 3depict-0.0.13/src/filters/boundingBox.cpp --- 3depict-0.0.12/src/filters/boundingBox.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/boundingBox.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1142 +0,0 @@ -#include "boundingBox.h" -#include "../xmlHelper.h" - -#include "../translation.h" - -enum -{ - KEY_VISIBLE=1, - KEY_COUNT_X, - KEY_COUNT_Y, - KEY_COUNT_Z, - KEY_FONTSIZE, - KEY_FONTCOLOUR, - KEY_FIXEDOUT, - KEY_LINECOLOUR, - KEY_LINEWIDTH, - KEY_SPACING_X, - KEY_SPACING_Y, - KEY_SPACING_Z, - KEY_STYLE -}; - -enum -{ - BOUNDINGBOX_ABORT_ERR, -}; - - -enum -{ - BOUND_STYLE_BOX_ONLY, - BOUND_STYLE_TICKS, - BOUND_STYLE_DIMENSION, - BOUND_STYLE_ENUM_END -}; - -const char *BOUND_STYLE[] = -{ - NTRANS("Box only"), - NTRANS("Tick"), - NTRANS("Dimension") -}; - - -//=== Bounding box filter == - - -BoundingBoxFilter::BoundingBoxFilter() : isVisible(true), boundStyle(BOUND_STYLE_TICKS), - fixedNumTicks(true), fontSize(5), rLine(0.0f), gLine(0.0f), bLine(1.0f), aLine(1.0f), - lineWidth(2.0f), threeDText(true) -{ - for(unsigned int ui=0;ui<3;ui++) - { - numTicks[ui]=12; - tickSpacing[ui]=5.0f; - } - - - cacheOK=false; - cache=false; -} - -Filter *BoundingBoxFilter::cloneUncached() const -{ - BoundingBoxFilter *p=new BoundingBoxFilter(); - p->fixedNumTicks=fixedNumTicks; - for(unsigned int ui=0;ui<3;ui++) - { - p->numTicks[ui]=numTicks[ui]; - p->tickSpacing[ui]=tickSpacing[ui]; - } - - p->isVisible=isVisible; - p->boundStyle=boundStyle; - - - p->rLine=rLine; - p->gLine=gLine; - p->bLine=bLine; - p->aLine=aLine; - p->threeDText=threeDText; - - p->lineWidth=lineWidth; - p->fontSize=fontSize; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -size_t BoundingBoxFilter::numBytesForCache(size_t nObjects) const -{ - //Say we don't know, we are not going to cache anyway. - return (size_t)-1; -} - -void BoundingBoxFilter::drawTicks(const BoundCube &bTotal, DrawStreamData *d) const -{ - - //Add the rectangle drawable - DrawRectPrism *dP = new DrawRectPrism; - dP->setAxisAligned(bTotal); - dP->setColour(rLine,gLine,bLine,aLine); - dP->setLineWidth(lineWidth); - d->drawables.push_back(dP); - - //Add the tick drawables - Point3D tickOrigin,tickEnd; - bTotal.getBounds(tickOrigin,tickEnd); - - float tmpTickSpacing[3]; - float tmpTickCount[3]; - if(fixedNumTicks) - { - for(unsigned int ui=0; ui<3;ui++) - { - ASSERT(numTicks[ui]); - tmpTickSpacing[ui]=( (tickEnd[ui] - tickOrigin[ui])/(float)(numTicks[ui]-1)); - tmpTickCount[ui]=numTicks[ui]; - } - } - else - { - for(unsigned int ui=0; ui<3;ui++) - { - ASSERT(numTicks[ui]); - tmpTickSpacing[ui]= tickSpacing[ui]; - tmpTickCount[ui]=(unsigned int)((tickEnd[ui] - tickOrigin[ui])/tickSpacing[ui])+1; - } - } - - //Draw the ticks on the box perimeter. - for(unsigned int ui=0;ui<3;ui++) - { - Point3D tickVector; - Point3D tickPosition; - Point3D textVector,upVector; - - tickPosition=tickOrigin; - switch(ui) - { - case 0: - tickVector=Point3D(0,-1,-1); - textVector=Point3D(0,1,0); - break; - case 1: - tickVector=Point3D(-1,0,-1); - textVector=Point3D(1,0,0); - break; - case 2: - tickVector=Point3D(-1,-1,0); - textVector=Point3D(1,1,0); - break; - } - - //TODO: This would be more efficient if we made some kind of - //"comb" class? - DrawVector *dV; - DrawGLText *dT; - //Allow up to 128 chars - char buffer[128]; - for(unsigned int uj=0;ujsetDrawArrow(false); - dV->setOrigin(tickPosition); - dV->setVector(tickVector); - dV->setColour(rLine,gLine,bLine,aLine); - - d->drawables.push_back(dV); - - - //Don't draw the 0 value, as this gets repeated. - //we will handle this separately - if(uj) - { - //Draw the tick text - if( threeDText) - dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); - else - dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_BITMAP); - float f; - f = tmpTickSpacing[ui]*uj; - snprintf(buffer,127,"%2.0f",f); - dT->setString(buffer); - dT->setSize(fontSize); - - dT->setColour(rLine,gLine,bLine,aLine); - dT->setOrigin(tickPosition + tickVector*2); - dT->setUp(Point3D(0,0,1)); - dT->setTextDir(textVector); - dT->setAlignment(DRAWTEXT_ALIGN_RIGHT); - - d->drawables.push_back(dT); - } - } - - } - - DrawGLText *dT; - if(threeDText) - dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); - else - dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_BITMAP); - //Handle "0" text value - dT->setString("0"); - - dT->setColour(rLine,gLine,bLine,aLine); - dT->setSize(fontSize); - dT->setOrigin(tickOrigin+ Point3D(-1,-1,-1)); - dT->setAlignment(DRAWTEXT_ALIGN_RIGHT); - dT->setUp(Point3D(0,0,1)); - dT->setTextDir(Point3D(-1,-1,0)); - d->drawables.push_back(dT); - -} - -void BoundingBoxFilter::drawDimension(const BoundCube &bTotal, DrawStreamData *d) const -{ - //Add the rectangle drawable - DrawRectPrism *dP = new DrawRectPrism; - dP->setAxisAligned(bTotal); - dP->setColour(rLine,gLine,bLine,aLine); - dP->setLineWidth(lineWidth); - d->drawables.push_back(dP); - - - - //Add the arrows from the start ot the end - //Create the position from which to draw the tick origins - Point3D tickOrigin,tickEnd; - bTotal.getBounds(tickOrigin,tickEnd); - - - - const float ARROW_SCALE_FACTOR =0.03f; - const float OFFSET=0.07f; - - Point3D halfPt; - halfPt=(tickEnd-tickOrigin)*0.5f + tickOrigin; - - - float maxLen; - { - Point3D delta; - delta=tickEnd-tickOrigin; - maxLen=std::max(std::max(delta[0],delta[1]),delta[2]); - } - - float offset; - offset=maxLen*OFFSET; - - Point3D centrePt[3]; - - centrePt[0] = Point3D(halfPt[0],tickOrigin[1]-offset,tickOrigin[2]-OFFSET); - centrePt[1] = Point3D(tickOrigin[0]-offset,halfPt[1],tickOrigin[2]-OFFSET); - centrePt[2] = Point3D(tickOrigin[0]-offset,tickOrigin[1] -OFFSET , halfPt[2]); - - - //Draw the arrows around the edge of the box - for(size_t ui=0;ui<3;ui++) - { - float len; - len=(tickEnd[ui]-tickOrigin[ui])*0.5f; - - for(unsigned int uj=0;uj<2;uj++) - { - DrawVector *dV; - dV= new DrawVector; - - dV->setColour(rLine,gLine,bLine,aLine); - dV->wantsLight=true; - dV->setOrigin(centrePt[ui]); - - switch(ui) - { - case 0: - dV->setVector(Point3D(2.0*len*(float)(uj-0.5f),0,0)); - break; - case 1: - dV->setVector(Point3D(0,2.0*len*(float)(uj-0.5f),0)); - break; - case 2: - dV->setVector(Point3D(0,0,2.0*len*(float)(uj-0.5f))); - break; - } - - - dV->setArrowSize(maxLen*ARROW_SCALE_FACTOR); - - d->drawables.push_back(dV); - } - - } - - - - - //Draw the values for the box dimensions, as text - char *buffer=new char[128]; - for(size_t ui=0;ui<3;ui++) - { - BoundCube textCube; - DrawGLText *dT; - dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON); - - float len; - len=(tickEnd[ui]-tickOrigin[ui]); - - snprintf(buffer,127,"%5.1f",len); - dT->setString(buffer); - dT->setSize(fontSize); - - dT->setColour(rLine,gLine,bLine,aLine); - dT->setOrigin(centrePt[ui]); - switch(ui) - { - case 0: - - dT->setUp(Point3D(0,0,1)); - dT->setTextDir(Point3D(1,0,0)); - break; - case 1: - dT->setUp(Point3D(1,0,0)); - dT->setTextDir(Point3D(0,-1,0)); - break; - case 2: - dT->setUp(Point3D(0,1,0)); - dT->setTextDir(Point3D(0,0,1)); - break; - } - - dT->setAlignment(DRAWTEXT_ALIGN_CENTRE); - - d->drawables.push_back(dT); - } - - - -} - -unsigned int BoundingBoxFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - - //Compute the bounding box of the incoming streams - BoundCube bTotal,bThis; - bTotal.setInverseLimits(); - - size_t totalSize=numElements(dataIn); - size_t n=0; - Point3D p[4]; - unsigned int ptCount=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - bThis=bTotal; - //Grab the first four points to define a volume. - //then expand that volume using the boundcube functions. - const IonStreamData *d =(const IonStreamData *) dataIn[ui]; - size_t dataPos=0; - unsigned int curProg=NUM_CALLBACK; - while(ptCount < 4 && dataPos < d->data.size()) - { - for(unsigned int ui=0; uidata.size();ui++) - { - p[ptCount]=d->data[ui].getPosRef(); - ptCount++; - dataPos=ui; - if(ptCount >=4) - break; - } - } - - //Ptcount will be 4 if we have >=4 points in dataset - if(ptCount == 4) - { - bThis.setBounds(p,4); - //Expand the bounding volume -#ifdef _OPENMP - //Parallel version - unsigned int nT =omp_get_max_threads(); - - BoundCube *newBounds= new BoundCube[nT]; - for(unsigned int ui=0;uidata.size();ui++) - { - unsigned int thisT=omp_get_thread_num(); - //OpenMP does not allow exiting. Use spin instead - if(spin) - continue; - - if(!curProg--) - { - #pragma omp critical - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - } - - - if(thisT == 0) - { - if(!(*callback)(false)) - spin=true; - } - } - - newBounds[thisT].expand(d->data[ui].getPosRef()); - } - if(spin) - { - delete d; - delete[] newBounds; - return BOUNDINGBOX_ABORT_ERR; - } - - for(unsigned int ui=0;uidata.size();ui++) - { - bThis.expand(d->data[ui].getPosRef()); - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return BOUNDINGBOX_ABORT_ERR; - } - } - } -#endif - bTotal.expand(bThis); - } - - break; - } - default: - break; - } - - //Copy the input data to the output - getOut.push_back(dataIn[ui]); - } - - //Append the bounding box if it is valid - if(bTotal.isValid() && isVisible) - { - - - DrawStreamData *d = new DrawStreamData; - d->parent=this; - - switch(boundStyle) - { - case BOUND_STYLE_BOX_ONLY: - { - //Add the rectangle drawable - DrawRectPrism *dP = new DrawRectPrism; - dP->setAxisAligned(bTotal); - dP->setColour(rLine,gLine,bLine,aLine); - dP->setLineWidth(lineWidth); - d->drawables.push_back(dP); - break; - } - case BOUND_STYLE_TICKS: - drawTicks(bTotal,d); - break; - case BOUND_STYLE_DIMENSION: - drawDimension(bTotal,d); - break; - default: - ASSERT(false); - } - d->cached=0; - - getOut.push_back(d); - } - return 0; -} - - -void BoundingBoxFilter::getProperties(FilterPropGroup &propertyList) const -{ - FilterProperty p; - size_t curGroup=0; - - string tmpStr; - stream_cast(tmpStr,isVisible); - p.name=TRANS("Visible"); - p.data= tmpStr; - p.key=KEY_VISIBLE; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("If true, show box, otherwise hide box"); - propertyList.addProperty(p,curGroup); - - if(isVisible) - { - vector > choices; - for(size_t ui=0;ui=BOUND_STYLE_ENUM_END) - return false; - - if(ltmp == boundStyle) - needUpdate=false; - else - { - boundStyle=ltmp; - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_FIXEDOUT: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=fixedNumTicks; - fixedNumTicks=(stripped=="1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=fixedNumTicks) - needUpdate=true; - break; - } - case KEY_COUNT_X: - case KEY_COUNT_Y: - case KEY_COUNT_Z: - { - ASSERT(fixedNumTicks); - unsigned int newCount; - if(stream_cast(newCount,value)) - return false; - - //there is a start and an end tick, at least - if(newCount < 2) - return false; - - numTicks[key-KEY_COUNT_X]=newCount; - needUpdate=true; - break; - } - case KEY_LINECOLOUR: - { - unsigned char newR,newG,newB,newA; - - parseColString(value,newR,newG,newB,newA); - - if(newB != bLine || newR != rLine || - newG !=gLine || newA != aLine) - needUpdate=true; - - rLine=newR/255.0; - gLine=newG/255.0; - bLine=newB/255.0; - aLine=newA/255.0; - needUpdate=true; - break; - } - case KEY_LINEWIDTH: - { - float newWidth; - if(stream_cast(newWidth,value)) - return false; - - if(newWidth <= 0.0f) - return false; - - lineWidth=newWidth; - needUpdate=true; - break; - } - case KEY_SPACING_X: - case KEY_SPACING_Y: - case KEY_SPACING_Z: - { - ASSERT(!fixedNumTicks); - float newSpacing; - if(stream_cast(newSpacing,value)) - return false; - - if(newSpacing <= 0.0f) - return false; - - tickSpacing[key-KEY_SPACING_X]=newSpacing; - needUpdate=true; - break; - } - case KEY_FONTSIZE: - { - unsigned int newCount; - if(stream_cast(newCount,value)) - return false; - - fontSize=newCount; - needUpdate=true; - break; - } - default: - ASSERT(false); - } - return true; -} - - -std::string BoundingBoxFilter::getErrString(unsigned int code) const -{ - - //Currently the only error is aborting - return std::string("Aborted"); -} - -bool BoundingBoxFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << ""<"<" <" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool BoundingBoxFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - std::string tmpStr; - - //Retrieve visiblity - //==== - if(XMLHelpFwdToElem(nodePtr,"visible")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - isVisible=false; - else if(tmpStr == "1") - isVisible=true; - else - return false; - - xmlFree(xmlString); - //==== - - //Retrieve box style - //==== - if(XMLHelpFwdToElem(nodePtr,"boundstyle")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(boundStyle,tmpStr)) - return false; - - xmlFree(xmlString); - //==== - - - //Retrieve fixed tick num - //==== - if(XMLHelpFwdToElem(nodePtr,"fixedticks")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - fixedNumTicks=false; - else if(tmpStr == "1") - fixedNumTicks=true; - else - return false; - - xmlFree(xmlString); - //==== - - //Retrieve num ticks - //==== - if(XMLHelpFwdToElem(nodePtr,"ticknum")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(numTicks[0],tmpStr)) - return false; - - xmlFree(xmlString); - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(numTicks[1],tmpStr)) - return false; - - xmlFree(xmlString); - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(numTicks[2],tmpStr)) - return false; - - xmlFree(xmlString); - //==== - - //Retrieve spacing - //==== - if(XMLHelpFwdToElem(nodePtr,"tickspacing")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(tickSpacing[0],tmpStr)) - return false; - - if(tickSpacing[0] < 0.0f) - return false; - - xmlFree(xmlString); - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(tickSpacing[1],tmpStr)) - return false; - if(tickSpacing[1] < 0.0f) - return false; - - xmlFree(xmlString); - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(tickSpacing[2],tmpStr)) - return false; - - if(tickSpacing[2] < 0.0f) - return false; - xmlFree(xmlString); - //==== - - //Retrieve line width - //==== - if(XMLHelpFwdToElem(nodePtr,"linewidth")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(lineWidth,tmpStr)) - return false; - - if(lineWidth < 0) - return false; - xmlFree(xmlString); - //==== - - //Retrieve font size - //==== - if(XMLHelpFwdToElem(nodePtr,"fontsize")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(fontSize,tmpStr)) - return false; - - xmlFree(xmlString); - //==== - - //Retrieve colour - //==== - if(XMLHelpFwdToElem(nodePtr,"colour")) - return false; - - if(!parseXMLColour(nodePtr,rLine,gLine,bLine,aLine)) - return false; - //==== - - return true; -} - -unsigned int BoundingBoxFilter::getRefreshBlockMask() const -{ - //Everything goes through this filter - return 0; -} - -unsigned int BoundingBoxFilter::getRefreshEmitMask() const -{ - if(isVisible) - return STREAM_TYPE_DRAW; - else - return 0; -} - -unsigned int BoundingBoxFilter::getRefreshUseMask() const -{ - if(isVisible) - return STREAM_TYPE_IONS; - else - return 0; -} - -#ifdef DEBUG -#include - -bool boxVolumeTest(); - -bool BoundingBoxFilter::runUnitTests() -{ - if(!boxVolumeTest()) - return false; - - return true; -} - - -bool boxVolumeTest() -{ - //Synthesise data - //--- - IonStreamData *d = new IonStreamData; - - vector streamIn,streamOut; - - IonHit h; - h.setMassToCharge(1); - - h.setPos(Point3D(0,0,1)); - d->data.push_back(h); - h.setPos(Point3D(0,1,0)); - d->data.push_back(h); - h.setPos(Point3D(1,0,0)); - d->data.push_back(h); - h.setPos(Point3D(0,0,0)); - d->data.push_back(h); - - streamIn.push_back(d); - //--- - - - //Set up and run filter - //--- - BoundingBoxFilter *b = new BoundingBoxFilter; - b->setCaching(false); - - bool needUp; - b->setProperty(KEY_VISIBLE,"1",needUp); - - - ProgressData p; - TEST(!b->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - //--- - - //Run tests - //--- - BoundCube bc; - bool havePrismDrawable=false; - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_DRAW) - continue; - - DrawStreamData *drawData; - drawData=(DrawStreamData*)streamOut[ui]; - - for(unsigned int uj=0;ujdrawables.size(); uj++) - { - DrawableObj *draw; - draw= drawData->drawables[uj]; - - if(draw->getType() == DRAW_TYPE_RECTPRISM) - { - draw->getBoundingBox(bc); - - havePrismDrawable=true; - break; - } - } - - if(havePrismDrawable) - break; - - } - - - TEST(havePrismDrawable, "bounding box existance test"); - - TEST(fabs(bc.volume() - 1.0f) - < sqrt(std::numeric_limits::epsilon()), - "Bounding volume test"); - - //Cleanup the emitted pointers - for(unsigned int ui=0;ui &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - //!Force a re-read of the rangefile Return value is range file reading error code - unsigned int updateRng(); - virtual std::string typeString() const { return std::string(TRANS("Bound box"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Refresh ignore mask, for filter streams that will not be utilised in the computation (except for pass-through) - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - -#ifdef DEBUG - bool runUnitTests() ; -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/clusterAnalysis.cpp 3depict-0.0.13/src/filters/clusterAnalysis.cpp --- 3depict-0.0.12/src/filters/clusterAnalysis.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/clusterAnalysis.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,3323 +0,0 @@ -#include "clusterAnalysis.h" -#include "../xmlHelper.h" - -#include "../translation.h" - -#include -#include -#include - -#include - -#include "../K3DTree-mk2.h" - - -enum -{ - KEY_CLUSTERANALYSIS_ALGORITHM, - KEY_CORECLASSIFYDIST, - KEY_CORECLASSIFYKNN, - KEY_LINKDIST, - KEY_BULKLINK, - KEY_ERODEDIST, - KEY_WANT_CLUSTERSIZEDIST, - KEY_WANT_LOGSIZEDIST, - KEY_WANT_COMPOSITIONDIST, - KEY_WANT_CLUSTERMORPHOLOGY, - KEY_NORMALISE_COMPOSITION, - KEY_CROP_SIZE, - KEY_SIZE_COUNT_BULK, - KEY_CROP_NMIN, - KEY_CROP_NMAX, - KEY_CORE_OFFSET=100000, - KEY_BULK_OFFSET=200000 -}; - -enum -{ - ABORT_ERR=1, - NOCORE_ERR, - NOBULK_ERR -}; - -enum -{ - CLUSTER_LINK_ERODE, - CLUSTER_ALGORITHM_ENUM_END, -}; - - -enum -{ - COMPOSITION_NONE, - COMPOSITION_UNNORMALISED, - COMPOSITION_NORMALISED -}; - -const char SIZE_DIST_DATALABEL[] =NTRANS("Size Distribution"); -const char CHEM_DIST_DATALABEL[] =NTRANS("Chemistry Distribution"); - -using std::vector; - -//Optimisation tuning value; -// number of points to expect in a KD query sphere before the bulk query pays off -// in terms of algorithm speed -const float SPHERE_PRESEARCH_CUTOFF = 75; - - -void makeFrequencyTable(const IonStreamData *i ,const RangeFile *r, - std::vector > &freqTable) -{ - ASSERT(r); - ASSERT(i); - - unsigned int numThreads; -#ifdef _OPENMP - numThreads=omp_get_max_threads(); -#else - numThreads=1; -#endif - vector ionHist; - ionHist.resize(numThreads); - - for(size_t ui=0;uigetNumIons()]; - for(size_t uj=0;ujgetNumIons();uj++) - ionHist[ui][uj]=0; - } - - -#pragma omp parallel for - for(size_t ui=0;uidata.size();ui++) - { -#ifdef _OPENMP - unsigned int threadNum=omp_get_thread_num(); -#endif - unsigned int rangeId; - rangeId= r->getIonID(i->data[ui].getMassToCharge()); - - if(rangeId!=(unsigned int)-1) - { -#ifdef _OPENMP - ionHist[threadNum][rangeId]++; -#else - ionHist[0][rangeId]++; -#endif - } - } - - - //we have to re-count the total, and tally the different threads - //in the histogram - for(size_t uj=0;ujgetNumIons();uj++) - { - for(size_t ui=1;uigetNumIons();uj++) - freqTable.push_back(make_pair(r->getName(uj),ionHist[0][uj])); - -} - -void makeCompositionTable(const IonStreamData *i ,const RangeFile *r, - std::vector > &compTable) -{ - std::vector > tab; - makeFrequencyTable(i,r,tab); - - compTable.resize(tab.size()); - size_t total=0; - for(unsigned int ui=0;ui &resultValues, vector &resultVectors) -{ - - //Although this function *mostly* works on arbitrary datasizes, the vector is of course - //fixed to being 3D.. - ASSERT(numCols == 3); - - gsl_matrix *m=gsl_matrix_alloc(numRows,numCols); - for(unsigned int ui=0;ui=0.0f); - resultValues.push_back(v); - } - - //Copy out the decomposed V matrix - resultVectors.resize(numCols); - for(size_t ui=0;ui &rangeEnabledMap) -{ - - //should be empty... - ASSERT(rangeEnabledMap.empty()); - - //"Lagging" counter to track the mapping from ionID->enabled Ion ID. - size_t count=0; - for(size_t ui=0;uirangeFile->getNumIons();ui++) - { - if(r->enabledIons[ui]) - { - //Create map entry - rangeEnabledMap[ui]=count; - count++; - } - } - - -} - -ClusterAnalysisFilter::ClusterAnalysisFilter() : algorithm(CLUSTER_LINK_ERODE), - coreDist(0.0f), coreKNN(1), linkDist(0.5f), bulkLink(1), dErosion(0.25), - wantCropSize(false), nMin(0),nMax(std::numeric_limits::max()), - sizeCountBulk(true),wantClusterSizeDist(false),logClusterSize(false), - wantClusterComposition(true),normaliseComposition(true), - wantClusterMorphology(false), haveRangeParent(false) - -{ - //haveRangeParent=false; //Initialiser sets this to false, as required by ::initFilter - - cacheOK=false; - - //By default, we should cache, but final decision is made higher up - cache=true; -#ifdef DEBUG - wantParanoidDebug=false; -#endif -} - - -Filter *ClusterAnalysisFilter::cloneUncached() const -{ - ClusterAnalysisFilter *p=new ClusterAnalysisFilter; - - p->algorithm=algorithm; - - p->coreDist=coreDist; - p->bulkLink=bulkLink; - p->linkDist=linkDist; - p->dErosion=dErosion; - - p->wantCropSize=wantCropSize; - p->nMin=nMin; - p->nMax=nMax; - p->sizeCountBulk=sizeCountBulk; - - p->wantClusterSizeDist = wantClusterSizeDist; - p->logClusterSize= logClusterSize; - - p->wantClusterComposition=wantClusterComposition; - p->normaliseComposition = normaliseComposition; - - p->haveRangeParent=false; //lets assume not, and this will be reset at ::initFilter time - - p->ionNames.resize(ionNames.size()); - std::copy(ionNames.begin(),ionNames.end(),p->ionNames.begin()); - p->ionCoreEnabled.resize(ionCoreEnabled.size()); - std::copy(ionCoreEnabled.begin(),ionCoreEnabled.end(),p->ionCoreEnabled.begin()); - p->ionBulkEnabled.resize(ionBulkEnabled.size()); - std::copy(ionBulkEnabled.begin(),ionBulkEnabled.end(),p->ionBulkEnabled.begin()); - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -void ClusterAnalysisFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - //Check for range file parent - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - { - const RangeStreamData *r; - r = (const RangeStreamData *)dataIn[ui]; - - bool different=false; - if(!haveRangeParent) - { - //well, things have may have changed, we didn't have a - //range parent before. Or, we could have been loaded in from - //a file. - - if(ionCoreEnabled.size() != r->rangeFile->getNumIons() || - ionBulkEnabled.size() != r->rangeFile->getNumIons()) - different=true; - else - { - //The ion lengths are the same; if so, we can just fill in the gaps - // -- the file does not store names; just sequence IDs. - ionNames.clear(); - ionNames.reserve(r->rangeFile->getNumRanges()); - for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) - { - if(r->enabledIons[uj]) - ionNames.push_back(r->rangeFile->getName(uj)); - } - } - } - else - { - //OK, last time we had a range parent. Check to see - //if the ion names are the same. If they are, keep the - //current bools, iff the ion names are all the same - unsigned int numEnabled=std::count(r->enabledIons.begin(), - r->enabledIons.end(),1); - if(ionNames.size() == numEnabled) - { - unsigned int pos=0; - for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) - { - //Only look at parent-enabled ranges - if(r->enabledIons[uj]) - { - if(r->rangeFile->getName(uj) != ionNames[pos]) - { - different=true; - break; - } - pos++; - } - } - } - else - different=true; - } - haveRangeParent=true; - - if(different) - { - //OK, its different. we will have to re-assign, - //but only allow the ranges enabled in the parent filter - // - - - vector oldIonNames; - oldIonNames.swap(ionNames); - - ionNames.reserve(r->rangeFile->getNumRanges()); - for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) - { - - if(r->enabledIons[uj]) - ionNames.push_back(r->rangeFile->getName(uj)); - } - - //Create new Core enabled/size enabled maps - //try to preserve selection using ion naming, if possible - //--- - vector oldCoreEnable,oldBulkEnable; - oldCoreEnable.swap(ionCoreEnabled); - oldBulkEnable.swap(ionBulkEnabled); - - ionCoreEnabled.resize(ionNames.size(),false); - ionBulkEnabled.resize(ionNames.size(),true); - - //TODO: Could replace double-search with keyed sort & match - for(size_t ui=0;ui &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - //By default, copy inputs to output, unless it is an ion or range stream type. - for(unsigned int ui=0;uigetStreamType(); - //Block ions moving through filter; we modify them. - // and also rangefiles, as we don't propagate these - if(type != STREAM_TYPE_IONS && type!=STREAM_TYPE_RANGE) - getOut.push_back(dataIn[ui]); - - } - - //use the cached copy if we have it. - if(cacheOK) - { - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - totalDataSize+=d->data.size(); - } - break; - default: - break; - } - } - - //Nothing to do. - if(!totalDataSize) - return 0; - - if(!haveRangeParent) - { - consoleOutput.push_back(string(TRANS("No range data. Can't cluster."))); - return 0; - } - - - bool haveABulk,haveACore; - checkIonEnabled(haveACore,haveABulk); - //Check that the user has enabled something as core - if(!haveACore) - { - consoleOutput.push_back( - string(TRANS("No ranges selected for cluster \"core\". Cannot continue with clustering."))); - return NOCORE_ERR; - } - - - //Check that the user has enabled something as matrix/bulk. - if(!haveABulk ) - { - //TODO: Refactor - we are really asking if algorithm needs bulk - if(bulkLink >std::numeric_limits::epsilon()) - { - consoleOutput.push_back( - string(TRANS("No ranges selected for cluster \"bulk\". Cannot continue with clustering."))); - return NOBULK_ERR; - } - } - -#ifdef DEBUG - for(unsigned int ui=0;ui > clusteredCore,clusteredBulk; - - switch(algorithm) - { - case CLUSTER_LINK_ERODE: - { - unsigned int errCode; - errCode=refreshLinkClustering(dataIn,clusteredCore, - clusteredBulk,progress,callback); - - if(errCode) - return errCode; - break; - } - default: - ASSERT(false); - } - -#ifdef DEBUG - /* If you are paranoid about the quality of the output, - * This will enable running some sanity checks that do - * not use the data structure involved in the clustering; - * ie a secondary check. - * However this is far too slow to enable by default, even in debug mode - */ - if(wantParanoidDebug) - paranoidDebugAssert(clusteredCore,clusteredBulk); -#endif - if(wantCropSize) - stripClusterBySize(clusteredCore,clusteredBulk,callback,progress); - - bool haveBulk,haveCore; - haveBulk=clusteredBulk.size(); - haveCore=clusteredCore.size(); - - - if(!haveBulk && !haveCore) - return 0; - - //we can't have bulk, but no core... - ASSERT(!(haveBulk && !haveCore)); - - //------------- - - - //Report the results back to the user - //------------ - //Cluster reporting. - const RangeStreamData *r=0; - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - { - r = (const RangeStreamData *)dataIn[ui]; - break; - } - } - - size_t curPlotIndex=0; - //Generate size distribution if we need it. - if(wantClusterSizeDist) - { - PlotStreamData *d; - d=clusterSizeDistribution(clusteredCore,clusteredBulk); - - if(d) - { - d->index=curPlotIndex; - curPlotIndex++; - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - } - else - d->cached=0; - - getOut.push_back(d); - - } - - } - - //Generate composition distribution if we requested it - if(wantClusterComposition) - { - vector plots; - genCompositionVersusSize(clusteredCore,clusteredBulk,r->rangeFile,plots); - - for(unsigned int ui=0;uiindex=curPlotIndex; - curPlotIndex++; - - if(cache) - { - plots[ui]->cached=1; - filterOutputs.push_back(plots[ui]); - } - else - plots[ui]->cached=0; - - getOut.push_back(plots[ui]); - } - } - - if(wantClusterMorphology) - { - //Compute the singular values for each cluster - //which describe the cluster morphology, their basis vectors, and - //the mass centre for the clusters - - //The premise of this analysis technique is outlined in Sudbrack,2004 - to some extent. - // In that work, they have several methods of doing morphology analysis, including where they - // use a PCA which wraps up the SVD to do the calculations. - // Here we use the SVD, which is faster & more space efficient, as we don't form the covariance - // matrix, but work directly on our data. - - // Aside from a sqrt, we should get the same answer for the ellipsoidal fit. - // - // Showing SVD & PCA to be equivalent enough for our use: - // SVD : X=USV', PCA: XX'=WDW' ; - // - //PCA, sub-ing Xs SVD representation: - // XX' = (USV')(USV')' - // XX' = (USV')(VSU') - // XX' = US(V'V)SU' - // V is orthogonal, thus V'V =I - // as transpose of orthogonal is its own inverse. - // XX' = US^2U' - // - // In our case, X_i=P_i-P_bar, where P_i is the i-th point in the cluster - // - // Thus D=S^2 and, D, being diagonal implies S=D^0.5 - //Sudbrack, C. : Decomposition behavior in model Ni-Al-Cr-X superalloys: - // emporal evolution and compositional pathways on a nanoscale (Ph.D. Thesis, 2004) - //http://arc.nucapt.northwestern.edu/refbase/files/Sudbrack_Ph.D._thesis_2004_6MB.pdf - - //Singular values, - //Mass centres of clusters & Singular vectors - vector > singularVals; - vector > > singularVectors; - getSingularValues(clusteredCore,clusteredBulk, - singularVals,singularVectors); - - ASSERT(singularVals.size() == clusteredCore.size()); - ASSERT(singularVectors.size() == clusteredCore.size()); - - //Ok, so we have the singular values, now create a - //plot with the values in it - PlotStreamData *p = new PlotStreamData; - p->parent=this; - - p->plotMode=PLOT_MODE_1D; - p->plotStyle=PLOT_TRACE_POINTS; - p->dataLabel=TRANS("Morphology Plot"); - p->xLabel=TRANS("\\lambda_1:\\lambda_2 ratio"); - p->yLabel=TRANS("\\lambda_2:\\lambda_3 ratio"); - p->xyData.reserve(singularVals.size()); - //the Y label makes more sense than the plot label here. - p->useDataLabelAsYDescriptor=false; - - -#pragma omp parallel for - for(unsigned int ui=0; ui std::numeric_limits::epsilon()) - { - p->xyData.push_back(make_pair(singularVals[ui][0]/singularVals[ui][1], - singularVals[ui][1]/singularVals[ui][2])); - - } - } - - if(p->xyData.size()) - { - p->index=curPlotIndex; - curPlotIndex++; - p->autoSetHardBounds(); - - if(cache) - { - p->cached=1; - filterOutputs.push_back(p); - } - else - p->cached=0; - - getOut.push_back(p); - - } - else - { - consoleOutput.push_back(TRANS("No clusters had sufficient dimensionality to compute singular values")); - delete p; - } - - - DrawStreamData *singularVectorDraw = new DrawStreamData; - singularVectorDraw->parent=this; - singularVectorDraw->drawables.reserve(singularVectors.size()*3); - - //So the next thing we do, is create mini Axes for them at their respective coordinates - //the length of each part of the axis shows the primary directions - //for that part of the cluster - for(unsigned int ui=0;ui=singularVectors[ui].second.size()) - break; - - DrawVector *d; - d= new DrawVector; - d->setColour(uj ==0, uj == 1, uj ==2,1); - Point3D start,singVector; - - //make a little cross in free space - singVector=singularVectors[ui].second[uj]*singularVals[ui][uj]; - start=singularVectors[ui].first-singVector*0.5f; - - - //First in current singular pair is cluster origin - d->setOrigin(start); - //Second contains each individual thing - d->setVector(singVector*0.5f); - singularVectorDraw->drawables.push_back(d); - } - } - - if(cache) - { - WARN(false,"Drawable caching is broken now. Refusing to cache!"); - singularVectorDraw->cached=0; - } - else - singularVectorDraw->cached=0; - - getOut.push_back(singularVectorDraw); - } - - //Construct the output clustered data. - IonStreamData *i = new IonStreamData; - i->parent =this; - std::string sDebugConsole,stmp; - stream_cast(stmp,clusteredCore.size()); - - sDebugConsole=TRANS("Found :"); - sDebugConsole+=stmp; - sDebugConsole+= TRANS(" clusters"); - consoleOutput.push_back(sDebugConsole); - - size_t totalSize=0; - - #pragma omp parallel for reduction(+:totalSize) - for(size_t ui=0;uidata.resize(totalSize); - - - //copy across the core and bulk ions - //into the output - size_t copyPos=0; - for(size_t ui=0;uidata[copyPos]=clusteredCore[ui][uj]; - copyPos++; - } - } - clusteredCore.clear(); - - for(size_t ui=0;uidata[copyPos]=clusteredBulk[ui][uj]; - copyPos++; - } - } - clusteredBulk.clear(); - - //The result data is drawn grey... - i->r=0.5f; - i->g=0.5f; - i->b=0.5f; - i->a=1.0f; - - //Save the ion stream data. - if(cache) - { - i->cached=1; - filterOutputs.push_back(i); - cacheOK=true; - } - else - i->cached=0; - - getOut.push_back(i); - - - if(wantClusterComposition) - { - ASSERT(r); - - if(normaliseComposition) - { - vector > compTable; - makeCompositionTable(i,r->rangeFile,compTable); - - - if(haveBulk) - consoleOutput.push_back(TRANS("Compositions (fractional, core+bulk)")); - else if(haveCore) - consoleOutput.push_back(TRANS("Compositions (fractional, core only)")); - - std::string compString,tmp; - for(unsigned int ui=0;ui > freqTable; - makeFrequencyTable(i,r->rangeFile,freqTable); - - consoleOutput.push_back(TRANS("Frequencies (core+bulk)")); - - std::string freqString,tmp; - for(unsigned int ui=0;ui > choices; - tmpStr=TRANS("Core Link + Erode"); - choices.push_back(make_pair((unsigned int)CLUSTER_LINK_ERODE,tmpStr)); - - tmpStr= choiceString(choices,algorithm); - p.name=TRANS("Algorithm"); - p.data=tmpStr; - choices.clear(); - p.type=PROPERTY_TYPE_CHOICE; - p.helpText=TRANS("Cluster algorithm mode"); - p.key=KEY_CLUSTERANALYSIS_ALGORITHM; - propertyList.addProperty(p,curGroup); - - curGroup++; - - if(algorithm == CLUSTER_LINK_ERODE) - { - stream_cast(tmpStr,coreDist); - p.name=TRANS("Core Classify Dist"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Restrict only atoms by distance to be cluster sources"); - p.key=KEY_CORECLASSIFYDIST; - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,coreKNN); - p.name=TRANS("Classify Knn Max"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_INTEGER; - p.helpText=TRANS("Require that the kth NN (this number) is within the classify distance, to be a cluster source"); - p.key=KEY_CORECLASSIFYKNN; - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,linkDist); - p.name=TRANS("Core Link Dist"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Distance between clusters to allow linking"); - p.key=KEY_LINKDIST; - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,bulkLink); - p.name=TRANS("Bulk Link (Envelope) Dist"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Distance from core points that form cluster that is used to grab surrounding bulk points"); - p.key=KEY_BULKLINK; - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,dErosion); - p.name=TRANS("Erode Dist"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Distance from unclustered material in which bulk points are eroded from cluster"); - p.key=KEY_ERODEDIST; - propertyList.addProperty(p,curGroup); - } - - propertyList.setGroupTitle(curGroup,TRANS("Clustering Params")); - - curGroup++; - - if(bulkLink > 0.0f) - { - tmpStr=boolStrEnc(sizeCountBulk); - p.name=TRANS("Count bulk"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Include bulk ions in size distribution."); - p.key=KEY_SIZE_COUNT_BULK; - propertyList.addProperty(p,curGroup); - } - - tmpStr=boolStrEnc(wantCropSize); - p.name=TRANS("Size Cropping"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Perform removal of clusters based upon size distribution"); - p.key=KEY_CROP_SIZE; - propertyList.addProperty(p,curGroup); - - if(wantCropSize) - { - stream_cast(tmpStr,nMin); - p.name=TRANS("Min Size"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_INTEGER; - p.helpText=TRANS("Remove clusters below this size"); - p.key=KEY_CROP_NMIN; - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,nMax); - p.name=TRANS("Max Size"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_INTEGER; - p.helpText=TRANS("Remove clusters above this size"); - p.key=KEY_CROP_NMAX; - propertyList.addProperty(p,curGroup); - } - - tmpStr=boolStrEnc(wantClusterSizeDist); - p.name=TRANS("Size Distribution"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Show number of clusters as a function of cluster size"); - p.key=KEY_WANT_CLUSTERSIZEDIST; - if(wantClusterSizeDist) - { - tmpStr=boolStrEnc(logClusterSize); - p.name=TRANS("Log Scale"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Use logarithmic scale for size distribution"); - p.key=KEY_WANT_LOGSIZEDIST; - } - - - tmpStr=boolStrEnc(wantClusterMorphology); - p.name=TRANS("Morphology Dist."); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Create a plot showing cluster aspect ratio data"); - p.key=KEY_WANT_CLUSTERMORPHOLOGY; - - tmpStr=boolStrEnc(wantClusterComposition); - p.name=TRANS("Chemistry Dist."); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Create a plot showing chemistry for each cluster size"); - p.key=KEY_WANT_COMPOSITIONDIST; - - - if(wantClusterComposition) - { - tmpStr=boolStrEnc(normaliseComposition); - p.name=TRANS("Normalise"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Convert cluster counts to composition"); - p.key=KEY_NORMALISE_COMPOSITION; - propertyList.addProperty(p,curGroup); - } - - - propertyList.setGroupTitle(curGroup,TRANS("Postprocess")); - - curGroup++; - - if(haveRangeParent) - { - //Offset markers are used elsewhere. Must be in sync with - //this code - ASSERT(ionCoreEnabled.size() == ionBulkEnabled.size()); - ASSERT(ionCoreEnabled.size() == ionNames.size()) - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - //OK, is this the plot? - //We should match the title we used to generate it - PlotStreamData *p; - p=(PlotStreamData*)filterOutputs[ui]; - - if(p->dataLabel.substr(strlen(SIZE_DIST_DATALABEL)) ==SIZE_DIST_DATALABEL ) - { - //Yup, this is it.kill the distribution - std::swap(filterOutputs[ui],filterOutputs.back()); - filterOutputs.pop_back(); - - //Now, note we DONT break - //here; as there is more than one - } - - } - } - } - else - { - //OK, we don't have one and we would like one. - // We have to compute this. Wipe cache and start over - clearCache(); - } - needUpdate=true; - } - break; - } - case KEY_WANT_LOGSIZEDIST: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=logClusterSize; - - logClusterSize=(stripped == "1"); - - //If the result is different - //we need to alter the output - if(lastVal!=logClusterSize) - { - //Scan through the cached output, and modify - //the size distribution. Having to recalc this - //just for a log/non-log change - //is a real pain -- so lets be smart and avoid this! - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - //OK, is this the plot? - //We should match the title we used to generate it - PlotStreamData *p; - p=(PlotStreamData*)filterOutputs[ui]; - - if(p->dataLabel ==SIZE_DIST_DATALABEL ) - { - //Yup, this is it. Set the log status - //and finish up - p->logarithmic=logClusterSize; - break; - } - - } - } - - - - needUpdate=true; - } - - break; - } - case KEY_WANT_COMPOSITIONDIST: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=wantClusterComposition; - wantClusterComposition=(stripped=="1"); - - //if the result is different, e - //remove the filter elements we no longer want. - if(lastVal!=wantClusterComposition) - { - //If we don't want the cluster composition - //just kill it from the cache and request an update - if(!wantClusterComposition) - { - for(size_t ui=filterOutputs.size();ui;) - { - ui--; - if(filterOutputs[ui]->getStreamType() == STREAM_TYPE_PLOT) - { - //OK, is this the plot? - //We should match the title we used to generate it - PlotStreamData *p; - p=(PlotStreamData*)filterOutputs[ui]; - - if(p->dataLabel.substr(0,strlen(CHEM_DIST_DATALABEL)) ==CHEM_DIST_DATALABEL ) - { - //Yup, this is it.kill the distribution - std::swap(filterOutputs[ui],filterOutputs.back()); - filterOutputs.pop_back(); - - //Now, note we DONT break - //here; as there is more than one - } - - } - } - } - else - { - //OK, we don't have one and we would like one. - // We have to compute this. Wipe cache and start over - clearCache(); - } - needUpdate=true; - } - - break; - } - case KEY_NORMALISE_COMPOSITION: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=normaliseComposition; - normaliseComposition=(stripped == "1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=normaliseComposition) - { - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_CROP_SIZE: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=wantCropSize; - wantCropSize=(stripped == "1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=wantCropSize) - { - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_CROP_NMIN: - { - size_t ltmp; - if(stream_cast(ltmp,value)) - return false; - - if( ltmp > nMax) - return false; - - nMin=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_CROP_NMAX: - { - size_t ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp == 0) - ltmp = std::numeric_limits::max(); - - if( ltmp < nMin) - return false; - - nMax=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_SIZE_COUNT_BULK: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=sizeCountBulk; - if(stripped=="1") - sizeCountBulk=true; - else - sizeCountBulk=false; - - //if the result is different, the - //cache should be invalidated - if(lastVal!=sizeCountBulk) - { - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_WANT_CLUSTERMORPHOLOGY: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=wantClusterMorphology; - wantClusterMorphology=(stripped=="1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=wantClusterMorphology) - { - needUpdate=true; - clearCache(); - } - - break; - } - default: - { - ASSERT( key >=KEY_CORE_OFFSET); - //Set value is dictated by getProperties routine - //and is the vector push back value - if(key =KEY_CORE_OFFSET) - { - bool b; - if(stream_cast(b,value)) - return false; - //Core ions; convert key value to array offset - key-=KEY_CORE_OFFSET; - - //no need to update - if(ionCoreEnabled[key] == b) - return false; - - ionCoreEnabled[key]=b; - - //Check if we need to also need to disable - //ion bulk to preserve mutual exclusiveness. - if(ionBulkEnabled[key] == b && b) - ionBulkEnabled[key]=0; - - clearCache(); - needUpdate=true; - } - else if(key >=KEY_BULK_OFFSET) - { - bool b; - if(stream_cast(b,value)) - return false; - //Core ions; convert key value to array offset - key-=KEY_BULK_OFFSET; - - //no need to update - if(ionBulkEnabled[key] == b) - return false; - - ionBulkEnabled[key]=b; - - //Check if we need to also need to disable - //ion core to preserve mutual exclusiveness - if(ionCoreEnabled[key] == b && b) - ionCoreEnabled[key]=0; - - clearCache(); - needUpdate=true; - - } - else - { - ASSERT(false); - } - } - } - - - return true; -} - -bool ClusterAnalysisFilter::writeState(std::ostream &f,unsigned int format, - unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - //Core-linkage algorithm parameters - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - //Cropping control - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - //Postprocessing - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+2) << "" << endl; - for(size_t ui=0;ui" << std::endl; - } - f << tabs(depth+2) << "" << endl; - f << tabs(depth+2) << "" << endl; - for(size_t ui=0;ui" << std::endl; - } - f << tabs(depth+2) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -size_t ClusterAnalysisFilter::numBytesForCache(size_t nObjects) const -{ - return (size_t)nObjects*IONDATA_SIZE; -} - -bool ClusterAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &packDir) -{ - using std::string; - - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - //Retrieve algorithm - //====== - if(!XMLGetNextElemAttrib(nodePtr,algorithm,"algorithm","value")) - return false; - if(algorithm >=CLUSTER_ALGORITHM_ENUM_END) - return false; - //=== - - //Retrieve parameter distances - //=== - switch(algorithm) - { - case CLUSTER_LINK_ERODE: - { - if(!XMLGetNextElemAttrib(nodePtr,coreDist,"coredist","value")) - return false; - if(coreDist<0) - return false; - if(!XMLGetNextElemAttrib(nodePtr,coreKNN,"coringknn","value")) - return false; - if(!coreKNN) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,linkDist,"linkdist","value")) - return false; - if(linkDist<=0) - return false; - if(!XMLGetNextElemAttrib(nodePtr,bulkLink,"bulklink","value")) - return false; - if(bulkLink<0) - return false; - if(!XMLGetNextElemAttrib(nodePtr,dErosion,"derosion","value")) - return false; - if(dErosion<0) - return false; - break; - } - default: - { - ASSERT(false); - return false; - } - } - //=== - - //Retrieve cropping info - //=== - xmlNodePtr tmpPtr; - tmpPtr=nodePtr; - - if(!XMLGetNextElemAttrib(nodePtr,wantCropSize,"wantcropsize","value")) - return false; - nodePtr=tmpPtr; - - if(!XMLGetNextElemAttrib(nodePtr,nMin,"nmin","value")) - return false; - nodePtr=tmpPtr; - if(!XMLGetNextElemAttrib(nodePtr,nMax,"nmax","value")) - return false; - nodePtr=tmpPtr; - - if(!XMLGetNextElemAttrib(nodePtr,wantClusterSizeDist,"wantclustersizedist","value")) - return false; - nodePtr=tmpPtr; - if(!XMLGetNextElemAttrib(nodePtr,logClusterSize,"wantclustersizedist","logarithmic")) - return false; - nodePtr=tmpPtr; - if(!XMLGetNextElemAttrib(nodePtr,sizeCountBulk,"wantclustersizedist","sizecountbulk")) - return false; - - tmpPtr=nodePtr; - if(!XMLGetNextElemAttrib(nodePtr,wantClusterComposition,"wantclustercomposition","value")) - return false; - nodePtr=tmpPtr; - if(!XMLGetNextElemAttrib(nodePtr,normaliseComposition,"wantclustercomposition","normalise")) - return false; - - - nodePtr=tmpPtr; - if(!XMLGetNextElemAttrib(nodePtr,wantClusterMorphology,"wantclustermorphology","value")) - return false; - //=== - - - //erase current enabled list. - ionCoreEnabled.clear(); - ionBulkEnabled.clear(); - - //Retrieve enabled selections - if(XMLHelpFwdToElem(nodePtr,"enabledions")) - return false; - - //Jump to ion sequence (/ level) - nodePtr=nodePtr->xmlChildrenNode; - - if(XMLHelpFwdToElem(nodePtr,"core")) - return false; - //Jump to level - tmpPtr=nodePtr->xmlChildrenNode; - - while(!XMLHelpFwdToElem(tmpPtr,"ion")) - { - int enabled; - if(!XMLGetAttrib(tmpPtr,enabled,"enabled")) - return false; - - ionCoreEnabled.push_back(enabled); - } - - if(XMLHelpFwdToElem(nodePtr,"bulk")) - return false; - tmpPtr=nodePtr->xmlChildrenNode; - - while(!XMLHelpFwdToElem(tmpPtr,"ion")) - { - int enabled; - if(!XMLGetAttrib(tmpPtr,enabled,"enabled")) - return false; - - ionBulkEnabled.push_back(enabled); - } - - return true; -} - -unsigned int ClusterAnalysisFilter::getRefreshBlockMask() const -{ - //Anything but ions can go through this filter. - return STREAM_TYPE_IONS; -} - -unsigned int ClusterAnalysisFilter::getRefreshEmitMask() const -{ - if(wantClusterSizeDist || wantClusterComposition || wantClusterMorphology) - return STREAM_TYPE_IONS | STREAM_TYPE_PLOT | STREAM_TYPE_DRAW; - else - return STREAM_TYPE_IONS; -} - -unsigned int ClusterAnalysisFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; -} - -std::string ClusterAnalysisFilter::getErrString(unsigned int i) const -{ - switch(i) - { - case ABORT_ERR: - return std::string(TRANS("Clustering aborted")); - case NOCORE_ERR: - return std::string(TRANS("No core ions for cluster")); - case NOBULK_ERR: - return std::string(TRANS("No bulk ions for cluster")); - default: - ASSERT(false); - } -} - -unsigned int ClusterAnalysisFilter::refreshLinkClustering(const std::vector &dataIn, - std::vector< std::vector > &clusteredCore, - std::vector > &clusteredBulk,ProgressData &progress, - bool (*callback)(bool)) -{ - - //Clustering algorithm, as per - //Stephenson, L. T.; et al - //Microscopy and Microanalysis, 2007, 13, 448-463 - // - //See also - //Vaumousse & Cerezo, - //Ultramicroscopy 95 (2003) 215–22 - - //Basic steps. Optional steps are denoted with a * - // - //1*) Core classification; work only on core ions (bulk is ignored) - // - Each "core" ion has sphere of specified size placed around it, - // if ion's kth-NN is within a given radius, then it is used as - // core, otherwise it is rejected to "bulk" - // - //2) Cluster Construction: A "backbone" is constructed using - // the core ions (after classification). - // - Each ion has a sphere placed around it of fixed size; if it contacts - // another ion, then these are considered as part of the same cluster. - // - //3*) Bulk inclusion step - // - For each cluster, every ion has a sphere placed around it. Bulk - // ions that lie within this union of spheres are assigned to the cluster - // This assignment is unambigious *iff* this radius is smaller than that - // for the cluster construction step - // - //4*) Bulk Erosion step - // - Each unclustered bulk ion has a sphere placed around it. This sphere - // strips out ions from the cluster. This is only done once (ie, not iterative) - // - // In the implementation, there are more steps, due to data structure construction - // and other computational concerns - - bool needCoring=coreDist> std::numeric_limits::epsilon(); - bool needBulkLink=bulkLink > std::numeric_limits::epsilon(); - bool needErosion=dErosion> std::numeric_limits::epsilon() && needBulkLink; - unsigned int numClusterSteps=4; - if(needBulkLink) - numClusterSteps+=2; - if(needErosion) - numClusterSteps++; - if(needCoring) - numClusterSteps++; - - - - //Quick sanity check - if(needBulkLink) - { - //It is mildly dodgy to use a "bulk" distance larger than your core distance - //with relative dodgyness, depending upon cluster number density. - // - //This is because bulk components can "bridge", and assignment to the core - //clusters will depend upon the order in which the ions are traversed. - //At this point we should warn the user that this is the case, and suggest to them - //that we hope they know what they are doing. - - - if(bulkLink > linkDist/2.0) - { - consoleOutput.push_back(""); - consoleOutput.push_back(TRANS(" --------------------------- Parameter selection notice ------------- ") ); - consoleOutput.push_back(TRANS("You have specified a bulk distance larger than half your link distance.") ); - consoleOutput.push_back(TRANS("You can do this; thats OK, but the output is no longer independent of the computational process;") ); - consoleOutput.push_back(TRANS("This will be a problem in the case where two or more clusters can equally lay claim to a \"bulk\" ion. ") ); - consoleOutput.push_back(TRANS(" If your inter-cluster distance is sufficiently large (larger than your bulk linking distance), then you can get away with this.") ); - consoleOutput.push_back(TRANS(" In theory it is possible to \"join\" the clusters, but this has not been implemented for speed reasons.")); - consoleOutput.push_back(TRANS("If you want this, please contact the author, or just use the source to add this in yourself.") ); - consoleOutput.push_back(TRANS("---------------------------------------------------------------------- ") ); - consoleOutput.push_back(""); - } - - } - - //Collate the ions into "core", and "bulk" ions, based upon our ranging data - //---------- - progress.step=1; - progress.filterProgress=0; - progress.stepName=TRANS("Collate"); - progress.maxStep=numClusterSteps; - if(!(*callback)(true)) - return ABORT_ERR; - - vector coreIons,bulkIons; - createRangedIons(dataIn,coreIons,bulkIons,progress,callback); - - if(coreIons.empty()) - return 0; - //---------- - - K3DTreeMk2 coreTree,bulkTree; - BoundCube bCore,bBulk; - - //Build the core KD tree - //---------- - progress.step++; - progress.filterProgress=0; - progress.stepName=TRANS("Build Core"); - if(!(*callback)(true)) - return ABORT_ERR; - - //Build the core tree (eg, solute ions) - coreTree.setCallback(callback); - coreTree.setProgressPointer(&(progress.filterProgress)); - coreTree.resetPts(coreIons,false); - coreTree.build(); - - coreTree.getBoundCube(bCore); - //---------- - - if(needCoring) - { - //Perform Clustering Stage (1) : clustering classification - //== - progress.step++; - progress.stepName=TRANS("Classify Core"); - if(!(*callback)(true)) - return ABORT_ERR; - - vector coreOK; - ASSERT(coreIons.size() == coreTree.size()); - coreOK.resize(coreTree.size()); - float coreDistSqr=coreDist*coreDist; - - //TODO: the trees internal Tags prevent us from parallelising this. - // :(. If we could pass a tag map to the tree, this would solve the problem - for(size_t ui=0;ui tagsToClear; - - //Don't match ourselves -- to do this we must "tag" this tree node before we start - p=coreTree.getPt(ui); - coreTree.tag(ui); - tagsToClear.push_back(ui); - - k=1; - - //Loop through this ions NNs, seeing if the kth NN is within a given radius - do - { - pNN=coreTree.findNearestUntagged(*p,bCore,true); - tagsToClear.push_back(pNN); - k++; - - }while( pNN !=(size_t)-1 && ksqrDist(*(coreTree.getPt(pNN))); - coreOK[coreTree.getOrigIndex(ui)] = nnSqrDist < coreDistSqr; - } - - - //reset the tags, so we can find near NNs - coreTree.clearTags(tagsToClear); - tagsToClear.clear(); - - if(!(ui%PROGRESS_REDUCE)) - { - progress.filterProgress= (unsigned int)(((float)ui/(float)coreTree.size())*100.0f); - if(!(*callback)(false)) - return ABORT_ERR; - } - } - - - for(size_t ui=coreOK.size();ui;) - { - ui--; - - if(!coreOK[ui]) - { - //We have to convert the core ion to a bulk ion - //as it is rejected. - bulkIons.push_back(coreIons[ui]); - coreIons[ui]=coreIons.back(); - coreIons.pop_back(); - } - } - - //Re-Build the core KD tree - coreTree.setCallback(callback); - coreTree.setProgressPointer(&(progress.filterProgress)); - coreTree.resetPts(coreIons,false); - coreTree.build(); - - coreTree.getBoundCube(bCore); - //== - } - - - //Build the bulk tree (eg matrix ions.), as needed - if(needBulkLink) - { - progress.step++; - progress.stepName=TRANS("Build Bulk"); - if(!(*callback)(true)) - return ABORT_ERR; - bulkTree.setCallback(callback); - bulkTree.setProgressPointer(&(progress.filterProgress)); - bulkTree.resetPts(bulkIons,false); - bulkTree.build(); - } - //---------- - - - //Step 2 in the Process : Cluster Construction - //==== - //Loop over the solutes in the material, - //running searches from each solute. Group them using a queue - //that keeps on adding newly found solutes until it can find no more - //within a given radius. This becomes one cluster. - - //Update progress stuff - progress.step++; - progress.stepName=TRANS("Core"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - - vector > allCoreClusters,allBulkClusters; - const float linkDistSqr=linkDist*linkDist; - - size_t progressCount=0; - - //When this queue is exhausted, move to the next cluster - for(size_t ui=0;ui soluteCluster,dummy; - //Queue for atoms in this cluster waiting to be checked - //for their NNs. - std::queue thisClusterQueue; - - - //This solute is already clustered. move along. - if(coreTree.getTag(ui)) - continue; - coreTree.tag(ui); - - - - size_t clustIdx; - thisClusterQueue.push(ui); - soluteCluster.push_back(ui); - do - { - curPt=thisClusterQueue.front(); - const Point3D *thisPt; - thisPt=coreTree.getPt(curPt); - curDistSqr=0; - - - - //Now loop over this solute's NNs not found by prev. method - while(true) - { - ASSERT(curPt < coreTree.size()); - //Find the next point that we have not yet retreived - //the find will tag the point, so we won't see it again - ASSERT(bCore.isValid()); - clustIdx=coreTree.findNearestUntagged( - *thisPt,bCore, true); - - - ASSERT(clustIdx == (size_t)-1 || coreTree.getTag(clustIdx)); - if(clustIdx != (size_t)-1) - { - curDistSqr=coreTree.getPt(clustIdx)->sqrDist( - *(coreTree.getPt(curPt)) ); - - } - - //Point out of clustering range, or no more points - if(clustIdx == (size_t)-1 || curDistSqr > linkDistSqr) - { - //If the point was not tagged, - //Un-tag the point; as it was too far away - if(clustIdx !=(size_t)-1) - coreTree.tag(clustIdx,false); - - thisClusterQueue.pop(); - break; - } - else - { - //Record it as part of the cluster - thisClusterQueue.push(clustIdx); - soluteCluster.push_back(clustIdx); - } - - - progressCount++; - if(!(progressCount%PROGRESS_REDUCE)) - { - //Progress may be a little non-linear if cluster sizes are not random - progress.filterProgress= (unsigned int)(((float)ui/(float)coreTree.size())*100.0f); - if(!(*callback)(false)) - return ABORT_ERR; - } - } - - - } // Keep looping whilst we have coreTree to cluster. - while(!thisClusterQueue.empty() && clustIdx !=(size_t)-1); - - - if(soluteCluster.size()) - { - //Record the solute cluster in the total array - allCoreClusters.push_back(dummy); - allCoreClusters.back().swap(soluteCluster); - soluteCluster.clear(); - } - } - - //==== - - //update progress - if(!(*callback)(false)) - return ABORT_ERR; - - //NOTE : Speedup trick. If we know the cluster size at this point - // and we know we don't want to count the bulk, we can strip out clusters - // now, as we are going to do that anyway as soon as we return from our cluster - // computation. - // The advantage to doing it now is that we can (potentially) drop lots of clusters - // from or analysis before we do the following steps, saving lots of time - if(!sizeCountBulk && (nMin > 0 || nMax <(size_t)-1) && wantCropSize ) - { - for(size_t ui=0;ui nMax) - { - allCoreClusters.back().swap(allCoreClusters[ui]); - allCoreClusters.pop_back(); - } - else - ui++; - - } - } - -#ifdef DEBUG - size_t coreClusterBeforeCount=allCoreClusters.size(); -#endif - //Step 3 in the Process : Bulk inclusion : AKA envelope - //==== - //If there is no bulk link step, we don't need to do that., - //or any of the following stages - if(needBulkLink) - { - - //Update progress stuff - progress.step++; - progress.stepName=TRANS("Bulk"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - if(bulkTree.size()) - { - bulkTree.getBoundCube(bBulk); - - //Compute the expected number of points that we would encapsulate - //if we were to place a sphere of size bulkLink in the KD domain. - // This allows us to choose whether to use a bulk "grab" approach, or not. - bool expectedPtsInSearchEnough; - expectedPtsInSearchEnough=((float)bulkTree.size())/bBulk.volume()*4.0/3.0*M_PI*pow(bulkLink,3.0f)> SPHERE_PRESEARCH_CUTOFF; - - //So-called "envelope" step. - float bulkLinkSqr=bulkLink*bulkLink; - size_t prog=PROGRESS_REDUCE; - //Now do the same thing with the matrix, but use the clusters as the "seed" - //positions - for(size_t ui=0;ui thisBulkCluster,dummy; - for(size_t uj=0;uj > blocks; - bulkTree.getTreesInSphere(*curPt,bulkLinkSqr,bBulk,blocks); - - for(size_t uj=0; ujsqrDist(*curPt); - } - - //Point out of clustering range, or no more points - if(bulkTreeIdx == (size_t)-1 || curDistSqr > bulkLinkSqr ) - { - //Un-tag the point; as it was too far away - if(bulkTreeIdx !=(size_t)-1) - bulkTree.tag(bulkTreeIdx,false); - break; - } - else - { - //Record it as part of the cluster - thisBulkCluster.push_back(bulkTreeIdx); - } - - prog--; - if(!prog) - { - prog=PROGRESS_REDUCE; - //Progress may be a little non-linear if cluster sizes are not random - progress.filterProgress= (unsigned int)(((float)ui/(float)allCoreClusters.size())*100.0f); - if(!(*callback)(false)) - return ABORT_ERR; - - } - } - - - - } - - - allBulkClusters.push_back(dummy); - allBulkClusters.back().swap(thisBulkCluster); - thisBulkCluster.clear(); - } - } - } - //==== - - -#ifdef DEBUG - size_t bulkClusterBeforeCount=allBulkClusters.size(); -#endif - //Step 4 in the Process : Bulk erosion - //==== - //Check if we need the erosion step - if(needErosion) - { - //Update progress stuff - progress.step++; - progress.stepName=TRANS("Erode"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - //Now perform the "erosion" step, where we strip off previously - //tagged matrix, if it is within a given distance of some untagged - //matrix - size_t numCounted=0; - bool spin=false; - - const float dErosionSqr=dErosion*dErosion; - #pragma omp parallel for - for(size_t ui=0;uisqrDist( - *(bulkTree.getPt(nnId)) ); - if( curDistSqr < dErosionSqr) - { - //Bulk is to be eroded. Swap it with the vector tail - //and pop it into oblivion. - std::swap(allBulkClusters[ui][uj], - allBulkClusters[ui].back()); - allBulkClusters[ui].pop_back(); - //Purposely do NOT advance the iterator, as we have - //new data at our current position (or we have hit end of - //array) - } - else - uj++; - - } - else - uj++; - - } - - if(!(ui%PROGRESS_REDUCE)) - { - #pragma omp critical - { - numCounted+=PROGRESS_REDUCE; - //Progress may be a little non-linear if cluster sizes are not random - progress.filterProgress= (unsigned int)(((float)numCounted/(float)allBulkClusters.size())*100.0f); - if(!(*callback)(false)) - spin=true; - } - - } - - } - - if(spin) - return ABORT_ERR; - } - //=== - - progress.step++; - progress.stepName=TRANS("Re-Collate"); - progress.filterProgress=0; - - //update progress - if(!(*callback)(true)) - return ABORT_ERR; - clusteredCore.resize(allCoreClusters.size()); - clusteredBulk.resize(allBulkClusters.size()); - - ASSERT(coreClusterBeforeCount == allCoreClusters.size()); //Must be equal, independant of erosion/bulk link steps - ASSERT(bulkClusterBeforeCount >= allBulkClusters.size()); //Must be <= after (optional) erosion step - - - //Use a no-barrier construct, to avoid the - //flush wait in the middle - #pragma omp parallel - { - #pragma omp for - for(size_t ui=0;ui > &core, const std::vector > &bulk) const -{ - for(size_t ui=0;ui &dataIn,vector &core, - vector &bulk, ProgressData &p, bool (*callback)(bool)) const -{ - - //TODO: Progress reporting and callback - ASSERT(haveRangeParent); - const RangeStreamData *r=0; - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - { - r = (const RangeStreamData *)dataIn[ui]; - break; - } - } - - ASSERT(r); - ASSERT(r->rangeFile->getNumIons() >=ionCoreEnabled.size()); - ASSERT(r->rangeFile->getNumIons() >=ionBulkEnabled.size()); - - //Maps the ionID for ranges in the PARENT rangeStreamData, to - //array offsets in the ionEnabled vectors. - // For exmaple if ions 1 2 and 4 are enabled in the PARENT - // then this maps to offsets 1 2 and 3 in the ion(Core/Bulk)Enabled vectors - map rangeEnabledMap; - buildRangeEnabledMap(r,rangeEnabledMap); - ASSERT(rangeEnabledMap.size() == ionCoreEnabled.size()); - - bool needBulk = bulkLink > std::numeric_limits::epsilon(); - - if(needBulk) - { - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - const IonStreamData *d; - d=(const IonStreamData *)dataIn[ui]; - #pragma omp parallel for - for(size_t ui=0;uidata.size();ui++) - { - unsigned int ionId; - ionId=r->rangeFile->getIonID(d->data[ui].getMassToCharge()); - if(ionId!=(unsigned int)-1) - { - if( ionCoreEnabled[rangeEnabledMap[ionId]]) - { - #pragma omp critical - core.push_back(d->data[ui]); - } - else if(ionBulkEnabled[rangeEnabledMap[ionId]]) //mutually exclusive with core (both cannot be true) - { - #pragma omp critical - bulk.push_back(d->data[ui]); - } - } - } - } - - - } - } - else - { -#pragma omp parallel for - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - const IonStreamData *d; - d=(const IonStreamData *)dataIn[ui]; - for(size_t ui=0;uidata.size();ui++) - { - unsigned int ionId; - ionId=r->rangeFile->getIonID(d->data[ui].getMassToCharge()); - if(ionId!=(unsigned int)-1 && ionCoreEnabled[rangeEnabledMap[ionId]]) - { - #pragma omp critical - core.push_back(d->data[ui]); - } - } - } - } - } - -} - -PlotStreamData* ClusterAnalysisFilter::clusterSizeDistribution(const vector > &core, - const vector > &bulk) const -{ - //each cluster is represented by one entry in core and bulk - ASSERT(bulk.size() == core.size() || bulk.empty()); - - //Map that maps input number to frequency - map countMap; - size_t maxSize=0; - if(sizeCountBulk && bulk.size()) - { - ASSERT(bulk.size() == core.size()); - for(size_t ui=0;uiparent=this; - dist->r=1; - dist->g=0; - dist->b=0; - - - dist->xLabel=TRANS("Cluster Size"); - dist->yLabel=TRANS("Frequency"); - - dist->dataLabel=SIZE_DIST_DATALABEL; - dist->logarithmic=logClusterSize; - - dist->plotStyle=PLOT_TRACE_STEM; - dist->plotMode=PLOT_MODE_1D; - dist->xyData.resize(countMap.size()); - std::copy(countMap.begin(),countMap.end(),dist->xyData.begin()); - - return dist; -} - - -bool ClusterAnalysisFilter::stripClusterBySize(vector > &clusteredCore, - vector > &clusteredBulk, - bool (*callback)(bool),ProgressData &progress) const - -{ - - //TODO: Parallelise? Could create a vector of bools and then - // spin through, find the ones we want to kill, then do a cull. - // Progress reporting would be a bit more difficult. - - if(clusteredBulk.size() && sizeCountBulk) - { - //should be the same numbers of bulk as core - ASSERT(clusteredBulk.size() == clusteredCore.size()); - for(size_t ui=clusteredCore.size();ui;) - { - ui--; - //Count both bulk and core, and operate on both. - size_t count; - count =clusteredCore[ui].size() + clusteredBulk[ui].size() ; - - if(count < nMin || count > nMax) - { - clusteredCore[ui].swap(clusteredCore.back()); - clusteredCore.pop_back(); - clusteredBulk[ui].swap(clusteredBulk.back()); - clusteredBulk.pop_back(); - } - if(!(ui%PROGRESS_REDUCE) && clusteredCore.size()) - { - progress.filterProgress= (unsigned int)(((float)ui/(float)clusteredCore.size()+1)*100.0f); - - if(!(*callback)(false)) - return ABORT_ERR; - } - } - } - else if(sizeCountBulk) - { - //OK, we don't have any bulk, but we wanted it.. Just work on core. - for(size_t ui=clusteredCore.size();ui;) - { - ui--; - - if(clusteredCore[ui].size() < nMin || clusteredCore[ui].size() > nMax) - { - clusteredCore[ui].swap(clusteredCore.back()); - clusteredCore.pop_back(); - } - if(!(ui%PROGRESS_REDUCE) ) - { - progress.filterProgress= (unsigned int)(((float)ui/(float)clusteredCore.size()+1)*100.0f); - - if(!(*callback)(false)) - return ABORT_ERR; - } - } - } - else - { - //OK, we have bulk, but we just want to count core; - //but operate on both - for(size_t ui=clusteredCore.size();ui;) - { - ui--; - - if(clusteredCore[ui].size() < nMin || clusteredCore[ui].size() > nMax) - { - clusteredCore[ui].swap(clusteredCore.back()); - clusteredCore.pop_back(); - clusteredBulk[ui].swap(clusteredBulk.back()); - clusteredBulk.pop_back(); - } - if(!(ui%PROGRESS_REDUCE) ) - { - progress.filterProgress= (unsigned int)(((float)ui/(float)clusteredCore.size()+1)*100.0f); - - if(!(*callback)(false)) - return ABORT_ERR; - } - } - - } - - return true; -} - -void ClusterAnalysisFilter::genCompositionVersusSize(const vector > &clusteredCore, - const vector > &clusteredBulk, const RangeFile *rng,vector &plots) const -{ - ASSERT(rng && haveRangeParent) - - //Frequency of ions, as a function of composition. - //The inner vector is the the array of frequencies - //for this particular sie for each ion (ie, the array is of size rng->getNumIons) - map > countMap; - - bool needCountBulk=clusteredBulk.size() && sizeCountBulk; - - - vector ionFreq; - ionFreq.resize(rng->getNumIons(),0); - //Create the frequency table, per ion - //------- - //TODO: Below, there is a multi-threaded version. When we are happy with the single-threaded code - // try implementing the multi-threaded routine. - //Count the cluster elements, then increment the frequency table - if(needCountBulk) - { - ASSERT(clusteredBulk.size() == clusteredCore.size()); - - //Create entries of zero vectors for ion counting - for(size_t ui=0;uigetIonID(clusteredCore[ui][uj].getMassToCharge()); - countMap[curSize][offset]++; - } - - for(size_t uj=0;ujgetIonID(clusteredBulk[ui][uj].getMassToCharge()); - countMap[curSize][offset]++; - } - } - } - else - { - //Create entries of zero vectors for ion counting - for(size_t ui=0;uigetIonID(clusteredCore[ui][uj].getMassToCharge()); - - //this should not happen, as to cluster the ion,it must be ranged - ASSERT(offset!=(size_t)-1); - - countMap[curSize][offset]++; - } - } - } - //------- - - //Now that we have the freq table; we need to discard any elements that are not - //completely empty across the map. - // - // A vector that tells us if a given ionID is zero for all map entries. I.e. not in cluster - vector isZero; - isZero.resize(rng->getNumIons(),true); - - for(map >::iterator - it=countMap.begin(); it!=countMap.end();++it) - { - for(size_t ui=0;uisecond.size();ui++) - { - if(it->second[ui]) - isZero[ui]=false; - } - } - - - - //Ok now we know which frequency values are non-zero. Good! - // We need to build the plots, and their respective XY data, - // also we should normalise the compositions (if needed). - plots.reserve(rng->getNumIons()); - for(size_t ui=0;uigetNumIons();ui++) - { - //we don't need to plot this, - //as we didn't have any clustered ions of this type - if(isZero[ui]) - continue; - - //Make a new plot - PlotStreamData *p; - p=new PlotStreamData; - p->parent=this; - p->plotMode=PLOT_MODE_1D; - - RGBf ionColour; - ionColour=rng->getColour(ui); - - //Colour it as per the range file - p->r=ionColour.red; - p->g=ionColour.green; - p->b=ionColour.blue; - - p->xLabel=TRANS("Cluster Size"); - if(normaliseComposition) - p->yLabel=TRANS("Composition"); - else - p->yLabel=TRANS("Frequency"); - - p->dataLabel=string(CHEM_DIST_DATALABEL) + string(":") + rng->getName(ui); - p->logarithmic=logClusterSize && !normaliseComposition; - - p->plotStyle=PLOT_TRACE_STEM; - - p->xyData.resize(countMap.size()); - - size_t offset; - offset=0; - //set the data from our particular ion - for(map > ::iterator it=countMap.begin();it!=countMap.end();++it) - { - p->xyData[offset].first=it->first; - p->xyData[offset].second=it->second[ui]; - - //if we need to normalise compositions, we have to normalise over all - //ion types for this cluster size (ie the sum of this vector) - if(normaliseComposition) - { - size_t sum=0; - for(size_t uk=0; uksecond.size();uk++) - sum+=it->second[uk]; - p->xyData[offset].second /=(float)sum; - } - offset++; - } - - plots.push_back(p); - } - - -} - -void ClusterAnalysisFilter::getSingularValues(const vector > &clusteredCore, - const vector > &clusteredBulk, vector > &singularValues, - vector > > &singularVectors) const -{ - const unsigned int DIMENSION=3; - - float *data=0; - size_t dataSize=0; - if(clusteredBulk.size()) - { - ASSERT(clusteredCore.size() == clusteredBulk.size()); -//#pragma omp parallel for shared(singularValues,clusteredCore,clusteredBulk) private(data,dataSize) - for(unsigned int ui=0;ui curSingularVals; - vector curSingularBases; - - curSingularVals.clear(); - curSingularBases.clear(); - //For this cluster, compute its singular values amplitudes - // (ignore direction) - size_t numEntries = clusteredCore[ui].size() + clusteredBulk[ui].size(); - - - //Check to see if we have sufficient data to compute an SVD - if(numEntries <=DIMENSION ) - { -#pragma omp critical - { - singularValues.push_back(curSingularVals); - singularVectors.push_back(make_pair(Point3D(0,0,0),curSingularBases)); - } - continue; - } - - //Allocate space, by growing as needed - if(numEntries*DIMENSION > dataSize) - { - //TODO: Is it faster to pre-compute the maximum cluster size? - // then determine the cluster backbone from that? - // Should we be using realloc? - if(data) - delete[] data; - data = new float[numEntries*DIMENSION]; - dataSize=numEntries*DIMENSION; - } - - //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]); - - Point3D clusterCentre; - clusterCentre= centroid[0]+centroid[1]; - clusterCentre*=1.0f/(float)(clusteredCore[ui].size()+clusteredBulk[ui].size()); - - //Fill the data array - float *p; - p=data; - for(size_t uj=0;uj curSingularVals; - vector curSingularBases; - - curSingularVals.clear(); - curSingularBases.clear(); - //For this cluster, compute its singular values amplitudes - // (ignore direction) - size_t numEntries = clusteredCore[ui].size(); - - - //Check to see if we have sufficient data to compute an SVD - if(numEntries <=DIMENSION ) - { -#pragma omp critical - { - singularValues.push_back(curSingularVals); - singularVectors.push_back(make_pair(Point3D(0,0,0),curSingularBases)); - } - continue; - } - //Compute the cluster's centre of mass (assuming unit mass per object) - Point3D centroid; - getPointSum(clusteredCore[ui],centroid); - centroid*=1.0f/(float)(clusteredCore[ui].size()); - //Allocate space, by growing as needed - if(numEntries*DIMENSION > dataSize) - { - //TODO: Is it faster to pre-compute the maximum cluster size? - // then determine the cluster backbone from that? - // Should we be using realloc? - if(data) - delete[] data; - data = new float[numEntries*DIMENSION]; - dataSize=numEntries*DIMENSION; - } - - //Fill the data array - for(size_t uj=0;uj - -//Cluster Ids for generating cluster test datasets with genCluster -enum -{ - CLUSTER_UNITTEST_ISOLATED_WITH_BULK, - CLUSTER_UNITTEST_ISOLATED, - CLUSTER_UNITTEST_END -}; - -//Cluster sizes generated by genCluster -const unsigned int CLUSTER_SIZES[]= { 15, 9}; - -//Create a synthetic dataset of points for cluster -IonStreamData *genCluster(unsigned int datasetID); - -//Test several isolated clusters -bool isolatedClusterTest(); - -//Test the core mode of the core-link clustering algorithm -bool coreClusterTest(); - -//Unit tests -bool ClusterAnalysisFilter::runUnitTests() -{ - if(!isolatedClusterTest()) - return false; - - if(!coreClusterTest()) - return false; - return true; -} - - -IonStreamData *genCluster(unsigned int id) -{ - IonStreamData*d = new IonStreamData; - d->parent=0; - - IonHit a; - switch(id) - { - case CLUSTER_UNITTEST_ISOLATED_WITH_BULK: - { - //Create a "cloud" of bulk, isolated from the - // particle - a.setMassToCharge(1); - a.setPos(Point3D(2,2,4)); - d->data.push_back(a); - a.setPos(Point3D(4,0,1)); - d->data.push_back(a); - a.setPos(Point3D(-3,1,1)); - d->data.push_back(a); - a.setPos(Point3D(-2,1,2)); - d->data.push_back(a); - a.setPos(Point3D(-2,-1,2)); - d->data.push_back(a); - a.setPos(Point3D(-2,1,-2)); - d->data.push_back(a); - //Fall through; add in the core - //from the other test - } - case CLUSTER_UNITTEST_ISOLATED: - { - a.setMassToCharge(1); - - //Create a little network of points - //each at most 1 - //unit distance from another - a.setPos(Point3D(0,0,0)); - d->data.push_back(a); - a.setPos(Point3D(0,0,1)); - d->data.push_back(a); - a.setPos(Point3D(0,1,1)); - d->data.push_back(a); - a.setPos(Point3D(0,1,2)); - d->data.push_back(a); - a.setPos(Point3D(1,1,2)); - d->data.push_back(a); - a.setPos(Point3D(2,1,2)); - d->data.push_back(a); - a.setPos(Point3D(2,1,1)); - d->data.push_back(a); - a.setPos(Point3D(2,1,0)); - d->data.push_back(a); - a.setPos(Point3D(2,2,0)); - d->data.push_back(a); - break; - } - default: - ASSERT(false); - } - - ASSERT(CLUSTER_SIZES[id] == d->data.size()); - ASSERT(d->data.size()); - return d; -} - - -IonStreamData *genCoreTestCluster() -{ - IonStreamData* d = new IonStreamData; - d->parent=0; - - IonHit a; - a.setMassToCharge(1); - //Create two small groupings of points, - //with one group of 3 linked by unit distance - // then a second group of two further away - // unit distance apart, - // with one in between, spaced evenly between the two - a.setPos(Point3D(0,0,0)); - d->data.push_back(a); - a.setPos(Point3D(0,1,0)); - d->data.push_back(a); - a.setPos(Point3D(1,0,0)); - d->data.push_back(a); - - a.setPos(Point3D(0,0,2)); - d->data.push_back(a); - - a.setPos(Point3D(0,0,4)); - d->data.push_back(a); - a.setPos(Point3D(0,-1,4)); - d->data.push_back(a); - - return d; -} -//Test the "core-link + erode" algorithm -// - no core classifcation -// -bool isolatedClusterTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - //Create a range file with two - //range datasets, A and B - RangeFile r; - RGBf filler; - filler.red=filler.green=filler.blue=0.5f; - - unsigned int ionA,ionB; - std::string shortName,longName; - shortName="A"; longName="AType"; - ionA=r.addIon(shortName,longName,filler); - shortName="B"; longName="BType"; - ionB=r.addIon(shortName,longName,filler); - - r.addRange(0.5,1.5,ionA); - r.addRange(1.5,2.5,ionB); - - //Build a rangestream data - RangeStreamData *rng = new RangeStreamData; - rng->rangeFile=&r; - rng->parent=0; - rng->enabledIons.resize(r.getNumIons(),1); - rng->enabledRanges.resize(r.getNumRanges(),1); - - //Create a cluster analysis filter - ClusterAnalysisFilter *f=new ClusterAnalysisFilter; - f->setCaching(false); - f->wantParanoidDebug=true; - - - streamIn.push_back(rng); - f->initFilter(streamIn,streamOut); - streamOut.clear(); - - //Enable A as core, and B as bulk - bool needUp; - f->setProperty(KEY_CORE_OFFSET,"1",needUp); - f->setProperty(KEY_BULK_OFFSET+1,"1",needUp); - - f->setProperty(KEY_CORECLASSIFYDIST,"0",needUp); - f->setProperty(KEY_LINKDIST,"1.1",needUp); - f->setProperty(KEY_BULKLINK,"1.1",needUp); - f->setProperty(KEY_ERODEDIST,"0",needUp); - - //stop the plots - f->setProperty(KEY_WANT_CLUSTERSIZEDIST,"0",needUp); - f->setProperty(KEY_WANT_COMPOSITIONDIST,"0",needUp); - - for(unsigned int ui=0;uirefresh(streamIn,streamOut,p,dummyCallback)),"Refresh err code"); - - //Kill the input ion stream, and remove old pointer - delete d; - streamIn.pop_back(); - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - //Use an auto_ptr so if the test fails, we still free ram - { - auto_ptr outD((const IonStreamData*)streamOut[0]); - TEST(outD->data.size() == CLUSTER_SIZES[ui],"Cluster size"); - - switch(ui) - { - case CLUSTER_UNITTEST_ISOLATED: - { - for(unsigned int ui=0;uidata.size();ui++) - { - TEST(r.getIonID(outD->data[ui].getMassToCharge()) - == ionA,"cluster ranging"); - } - break; - } - case CLUSTER_UNITTEST_ISOLATED_WITH_BULK: - { - //Check bulk contains bulk or core - for(unsigned int ui=0;uidata.size();ui++) - { - unsigned int idIon; - idIon=r.getIonID(outD->data[ui].getMassToCharge()); - TEST( idIon== ionB || idIon == ionA,"cluster ranging "); - } - - break; - } - default: - ASSERT(false); - } - - } - - - streamOut.clear(); - - } - - delete rng; - delete f; - return true; -} - -bool coreClusterTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - //Create a range file with two - //range datasets, A and B - RangeFile r; - RGBf filler; - filler.red=filler.green=filler.blue=0.5f; - - unsigned int ionA,ionB; - std::string shortName,longName; - shortName="A"; longName="AType"; - ionA=r.addIon(shortName,longName,filler); - shortName="B"; longName="BType"; - ionB=r.addIon(shortName,longName,filler); - - r.addRange(0.5,1.5,ionA); - r.addRange(1.5,2.5,ionB); - - //Build a rangestream data - RangeStreamData *rng = new RangeStreamData; - rng->rangeFile=&r; - rng->parent=0; - rng->enabledIons.resize(r.getNumIons(),1); - rng->enabledRanges.resize(r.getNumRanges(),1); - - //Create a cluster analysis filter - ClusterAnalysisFilter *f=new ClusterAnalysisFilter; - f->setCaching(false); - f->wantParanoidDebug=true; - - - streamIn.push_back(rng); - f->initFilter(streamIn,streamOut); - streamOut.clear(); - - //Enable A as core - bool needUp; - TEST(f->setProperty(KEY_CORE_OFFSET,"1",needUp),"Set core range"); - - TEST(f->setProperty(KEY_CORECLASSIFYDIST,"1.1",needUp),"Set core classification dist"); - TEST(f->setProperty(KEY_CORECLASSIFYKNN,"1",needUp),"Set core classfication kNN"); - TEST(f->setProperty(KEY_LINKDIST,"2.0",needUp),"set link distance"); - TEST(f->setProperty(KEY_BULKLINK,"0",needUp),"set bulk distance"); - TEST(f->setProperty(KEY_ERODEDIST,"0",needUp),"set erode distance"); - - //stop the plots - f->setProperty(KEY_WANT_CLUSTERSIZEDIST,"0",needUp); - f->setProperty(KEY_WANT_COMPOSITIONDIST,"0",needUp); - - IonStreamData *ionData = genCoreTestCluster(); - - streamIn.push_back(ionData); - - //Do the refresh - ProgressData p; - TEST(!(f->refresh(streamIn,streamOut,p,dummyCallback)),"Refresh err code"); - delete f; - delete ionData; - delete rng; - - TEST(streamOut.size() == 1,"stream count"); - - const IonStreamData *outD=(const IonStreamData*)streamOut[0];; - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - TEST(outD->data.size() == 5,"Total Cluster size"); - - delete outD; - - - return true; -} - - - -#endif diff -Nru 3depict-0.0.12/src/filters/clusterAnalysis.h 3depict-0.0.13/src/filters/clusterAnalysis.h --- 3depict-0.0.12/src/filters/clusterAnalysis.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/clusterAnalysis.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -#ifndef CLUSTERANALYSIS_H -#define CLUSTERANALYSIS_H -#include "../filter.h" -#include "../translation.h" - -//!Cluster analysis filter -class ClusterAnalysisFilter : public Filter -{ - private: - //Clustering algorithm to use - unsigned int algorithm; - - //Algorithm parameters - //--- - //Core-linkage "core" classification distance - float coreDist; - //Coring kNN maximum - unsigned int coreKNN; - //Link distance for core - float linkDist; - //Link distance for bulk - float bulkLink; - //Erosion distance for bulk from nonclustered bulk - float dErosion; - //--- - - //post processing options - //Minimum/max number of "core" entires to qualify as, - //well, a meaningful cluster - bool wantCropSize; - size_t nMin,nMax; - bool sizeCountBulk; - - bool wantClusterSizeDist,logClusterSize; - - //Do we want the composition data for the cluster - bool wantClusterComposition, normaliseComposition; - - //Do we want a morphological analysis - bool wantClusterMorphology; - - //!Do we have range data to use - bool haveRangeParent; - //!The names of the incoming ions - std::vector ionNames; - - //!Which ions are core/builk for a particular incoming range? - std::vector ionCoreEnabled,ionBulkEnabled; - - //Do cluster refresh using Link Algorithm (Core + max sep) - unsigned int refreshLinkClustering(const std::vector &dataIn, - std::vector< std::vector > &clusteredCore, - std::vector > &clusteredBulk,ProgressData &progress, - bool (*callback)(bool)); - - - //Helper function to create core and bulk vectors of ions from input ionstreams - void createRangedIons(const std::vector &dataIn, - std::vector &core,std::vector &bulk, - ProgressData &p,bool (*callback)(bool)) const; - - - //Check to see if there are any core or bulk ions enabled respectively. - void checkIonEnabled(bool &core, bool &bulk) const; - - static void buildRangeEnabledMap(const RangeStreamData *r, - map &rangeEnabledMap); - - //Strip out clusters with a given number of elements - bool stripClusterBySize(vector > &clusteredCore, - vector > &clusteredBulk, - bool (*callback)(bool), ProgressData &p) const; - //Build a plot that is the cluster size distribution as afunction of cluster size - PlotStreamData *clusterSizeDistribution(const vector > &solutes, - const vector > &matrix) const; - - - //Build plots that are the cluster size distribution as - // a function of cluster size, specific to each ion type. - void genCompositionVersusSize(const vector > &clusteredCore, - const vector > &clusteredBulk, const RangeFile *rng, - vector &plots) const; - -#ifdef DEBUG - bool paranoidDebugAssert(const std::vector > &core, - const std::vector > &bulk) const; -#endif -#ifdef DEBUG - public: -#endif - //COmpute the singular values that area associated with each cluster - void getSingularValues(const vector > &clusteredCore, - const vector > &clusteredBulk, vector > &singularValues, - vector > > &singularVectors) const; - public: - ClusterAnalysisFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - - //!Initialise filter prior to tree propagation - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - - //!Returns -1, as range file cache size is dependant upon input. - virtual size_t numBytesForCache(size_t nObjects) const; - //!Returns FILTER_TYPE_SPATIAL_ANALYSIS - unsigned int getType() const { return FILTER_TYPE_CLUSTER_ANALYSIS;}; - //update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - //!Get the type string for this fitler - virtual std::string typeString() const { return std::string(TRANS("Cluster Analysis"));}; - - std::string getErrString(unsigned int i) const; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshUseMask() const; - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - -#ifdef DEBUG - bool wantParanoidDebug; - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/compositionProfile.cpp 3depict-0.0.13/src/filters/compositionProfile.cpp --- 3depict-0.0.12/src/filters/compositionProfile.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/compositionProfile.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1748 +0,0 @@ -#include "compositionProfile.h" -#include "../xmlHelper.h" -#include "../plot.h" - -#include "../translation.h" - - -//!Possible primitive types for composition profiles -enum -{ - PRIMITIVE_CYLINDER, - PRIMITIVE_END, //Not actually a primitive, just end of enum -}; - -//!Error codes -enum -{ - ERR_NUMBINS=1, - ERR_MEMALLOC, - ERR_ABORT -}; - -const char *PRIMITIVE_NAME[]={ - NTRANS("Cylinder") -}; - -CompositionProfileFilter::CompositionProfileFilter() : primitiveType(PRIMITIVE_CYLINDER), - showPrimitive(true), lockAxisMag(false),normalise(true), fixedBins(0), - nBins(1000), binWidth(0.5f), r(0.0f),g(0.0f),b(1.0f),a(1.0f), plotStyle(0) -{ - COMPILE_ASSERT(ARRAYSIZE(PRIMITIVE_NAME) == PRIMITIVE_END); - - errMode.mode=PLOT_ERROR_NONE; - errMode.movingAverageNum=4; - - vectorParams.push_back(Point3D(0.0,0.0,0.0)); - vectorParams.push_back(Point3D(0,20.0,0.0)); - scalarParams.push_back(5.0); - - haveRangeParent=false; -} - - -void CompositionProfileFilter::binIon(unsigned int targetBin, const RangeStreamData* rng, - const map &ionIDMapping, - vector > &frequencyTable, float massToCharge) -{ - //if we have no range data, then simply increment its position in a 1D table - //which will later be used as "count" data (like some kind of density plot) - if(!rng) - { - ASSERT(frequencyTable.size() == 1); - //There is a really annoying numerical boundary case - //that makes the target bin equate to the table size. - //disallow this. - if(targetBin < frequencyTable[0].size()) - frequencyTable[0][targetBin]++; - return; - } - - - //We have range data, we need to use it to classify the ion and then increment - //the appropriate position in the table - unsigned int rangeID = rng->rangeFile->getRangeID(massToCharge); - - if(rangeID != (unsigned int)(-1) && rng->enabledRanges[rangeID]) - { - unsigned int ionID=rng->rangeFile->getIonID(rangeID); - unsigned int pos; - pos = ionIDMapping.find(ionID)->second; - frequencyTable[pos][targetBin]++; - } -} - - -Filter *CompositionProfileFilter::cloneUncached() const -{ - CompositionProfileFilter *p = new CompositionProfileFilter(); - - p->primitiveType=primitiveType; - p->showPrimitive=showPrimitive; - p->vectorParams.resize(vectorParams.size()); - p->scalarParams.resize(scalarParams.size()); - - std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin()); - std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin()); - - p->normalise=normalise; - p->fixedBins=fixedBins; - p->lockAxisMag=lockAxisMag; - - p->binWidth=binWidth; - p->nBins = nBins; - p->r=r; - p->g=g; - p->b=b; - p->a=a; - p->plotStyle=plotStyle; - p->errMode=errMode; - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -void CompositionProfileFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - //Check for range file parent - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - { - haveRangeParent=true; - return; - } - } - haveRangeParent=false; -} - -unsigned int CompositionProfileFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, - bool (*callback)(bool)) -{ - //Clear selection devices - clearDevices(); - - if(showPrimitive) - { - //construct a new primitive, do not cache - DrawStreamData *drawData=new DrawStreamData; - drawData->parent=this; - switch(primitiveType) - { - case PRIMITIVE_CYLINDER: - { - //Origin + normal - ASSERT(vectorParams.size() == 2); - //Add drawable components - DrawCylinder *dC = new DrawCylinder; - dC->setOrigin(vectorParams[0]); - dC->setRadius(scalarParams[0]); - dC->setColour(0.5,0.5,0.5,0.3); - dC->setSlices(40); - dC->setLength(sqrt(vectorParams[1].sqrMag())*2.0f); - dC->setDirection(vectorParams[1]); - dC->wantsLight=true; - drawData->drawables.push_back(dC); - - - //Set up selection "device" for user interaction - //==== - //The object is selectable - dC->canSelect=true; - //Start and end radii must be the same (not a - //tapered cylinder) - dC->lockRadii(); - - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding b; - //Bind the drawable object to the properties we wish - //to be able to modify - - //Bind left + command button to move - b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_CYLINDER_BIND_ORIGIN, - BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); - b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b); - - //Bind left + shift to change orientation - b.setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_CYLINDER_BIND_DIRECTION, - BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); - if(lockAxisMag) - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); - else - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); - s->addBinding(b); - - //Bind right button to changing position - b.setBinding(SELECT_BUTTON_RIGHT,0,DRAW_CYLINDER_BIND_ORIGIN, - BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); - b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b); - - //Bind middle button to changing orientation - b.setBinding(SELECT_BUTTON_MIDDLE,0,DRAW_CYLINDER_BIND_DIRECTION, - BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); - if(lockAxisMag) - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); - else - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); - s->addBinding(b); - - //Bind left button to changing radius - b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_CYLINDER_BIND_RADIUS, - BINDING_CYLINDER_RADIUS,dC->getRadius(),dC); - b.setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); - b.setFloatLimits(0,std::numeric_limits::max()); - s->addBinding(b); - - devices.push_back(s); - //===== - - break; - } - default: - ASSERT(false); - } - drawData->cached=0; - getOut.push_back(drawData); - } - - - //use the cached copy of the data if we have it. - if(cacheOK) - { - //proagate our cached plot data. - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_PLOT); - - //Propagate all the incoming data (including ions) - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) - getOut.push_back(dataIn[ui]); - } - - return 0; - } - - //Ion Frequences (composition specific if rangefile present) - vector > ionFrequencies; - - RangeStreamData *rngData=0; - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - { - rngData =((RangeStreamData *)dataIn[ui]); - break; - } - } - - //Number of bins, having determined if we are using - //fixed bin count or not - unsigned int numBins; - - if(fixedBins) - numBins=nBins; - else - { - switch(primitiveType) - { - case PRIMITIVE_CYLINDER: - { - //length of cylinder (as axis starts in cylinder middle) - float length; - length=sqrt(vectorParams[1].sqrMag())*2.0f; - - ASSERT(binWidth > std::numeric_limits::epsilon()); - - //Check for possible overflow - if(length/binWidth > (float)std::numeric_limits::max()) - return ERR_NUMBINS; - - numBins=(unsigned int)(length/binWidth); - break; - } - default: - ASSERT(false); - } - - } - - //Indirection vector to convert ionFrequencies position to ionID mapping. - //Should only be used in conjunction with rngData == true - std::map ionIDMapping,inverseIDMapping; - //Allocate space for the frequency table - if(rngData) - { - ASSERT(rngData->rangeFile); - unsigned int enabledCount=0; - for(unsigned int ui=0;uirangeFile->getNumIons();ui++) - { - //TODO: Might be nice to detect if an ions ranges - //are all, disabled then if they are, enter this "if" - //anyway - if(rngData->enabledIons[ui]) - { - //Keep the forwards mapping for binning - ionIDMapping.insert(make_pair(ui,enabledCount)); - //Keep the inverse mapping for labelling - inverseIDMapping.insert(make_pair(enabledCount,ui)); - enabledCount++; - } - - - - } - - //Nothing to do. - if(!enabledCount) - return 0; - - try - { - ionFrequencies.resize(enabledCount); - //Allocate and Initialise all elements to zero - #pragma omp parallel for - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - - switch(primitiveType) - { - case PRIMITIVE_CYLINDER: - { - //Origin + axis - ASSERT(vectorParams.size() == 2); - //Radius perp. to axis - ASSERT(scalarParams.size() == 1); - - unsigned int curProg=NUM_CALLBACK; - Point3f rotVec; - //Cross product desired drection with default - //direction to produce rotation vector - Point3D dir(0.0f,0.0f,1.0f),direction; - direction=vectorParams[1]; - direction.normalise(); - - float angle = dir.angle(direction); - - float halfLen=sqrt(vectorParams[1].sqrMag()); - float sqrRad=scalarParams[0]*scalarParams[0]; - - //Check that we actually need to rotate, to avoid numerical singularity - //when cylinder axis is too close to (or is) z-axis - if(angle > sqrt(std::numeric_limits::epsilon())) - { - if(angle < M_PI-sqrt(std::numeric_limits::epsilon())) - { - dir = dir.crossProd(direction); - dir.normalise(); - } - else - { - //Any old nomral in XY will do, due to rotational symmetry - dir=Point3D(1,0,0); - - } - - rotVec.fx=dir[0]; - rotVec.fy=dir[1]; - rotVec.fz=dir[2]; - - Quaternion q1; - - //Generate the rotating quaternions - quat_get_rot_quat(&rotVec,-angle,&q1); - - - - //pre-compute cylinder length and radius^2 - //Loop through each ion in the dataset - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - Point3f p; - //Translate to get position w respect to cylinder centre - Point3D ptmp; - ptmp=it->getPosRef()-vectorParams[0]; - p.fx=ptmp[0]; - p.fy=ptmp[1]; - p.fz=ptmp[2]; - //rotate ion position into cylindrical coordinates - quat_rot_apply_quat(&p,&q1); - - //Keep ion if inside cylinder - if((p.fz < halfLen && p.fz > -halfLen && p.fx*p.fx+p.fy*p.fy < sqrRad)) - { - //Figure out where inside the cylinder the - //data lies. Then push it into the correct bin. - unsigned int targetBin; - targetBin = (unsigned int)((float)numBins*(float)(p.fz + halfLen)/(2.0f*halfLen)); - - binIon(targetBin,rngData,ionIDMapping,ionFrequencies, - it->getMassToCharge()); - } - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - return ERR_ABORT; - } - } - - } - else - { - //Too close to the z-axis, rotation vector is unable to be stably computed, - //and we don't need to rotate anyway - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - Point3D ptmp; - ptmp=it->getPosRef()-vectorParams[0]; - - //Keep ion if inside cylinder - if((ptmp[2] < halfLen && ptmp[2] > -halfLen && ptmp[0]*ptmp[0]+ptmp[1]*ptmp[1] < sqrRad)) - { - //Figure out where inside the cylinder the - //data lies. Then push it into the correct bin. - unsigned int targetBin; - targetBin = (unsigned int)((float)numBins*(float)(ptmp[2]+ halfLen)/(2.0f*halfLen)); - binIon(targetBin,rngData,ionIDMapping,ionFrequencies, - it->getMassToCharge()); - } - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - return ERR_ABORT; - } - } - - } - break; - } - } - break; - } - default: - //Do not propagate other types. - break; - } - - } - - PlotStreamData *plotData[ionFrequencies.size()]; - float length; - length=sqrt(vectorParams[1].sqrMag())*2.0f; - - - float normFactor=1.0f; - for(unsigned int ui=0;uiindex=ui; - plotData[ui]->parent=this; - plotData[ui]->xLabel= TRANS("Distance"); - plotData[ui]->errDat=errMode; - if(normalise) - { - //If we have composition, normalise against - //sum composition = 1 otherwise use volume of bin - //as normalisation factor - if(rngData) - plotData[ui]->yLabel= TRANS("Fraction"); - else - plotData[ui]->yLabel= TRANS("Density (\\#.len^3)"); - } - else - plotData[ui]->yLabel= TRANS("Count"); - - //Give the plot a title like TRANS("Myplot:Mg" (if have range) or "MyPlot") (no range) - if(rngData) - { - unsigned int thisIonID; - thisIonID = inverseIDMapping.find(ui)->second; - plotData[ui]->dataLabel = getUserString() + string(":") - + rngData->rangeFile->getName(thisIonID); - - - //Set the plot colour to the ion colour - RGBf col; - col=rngData->rangeFile->getColour(thisIonID); - - plotData[ui]->r =col.red; - plotData[ui]->g =col.green; - plotData[ui]->b =col.blue; - - } - else - { - //If it only has one component, then - //it's not really a composition profile is it? - plotData[ui]->dataLabel= TRANS("Freq. Profile"); - plotData[ui]->r = r; - plotData[ui]->g = g; - plotData[ui]->b = b; - plotData[ui]->a = a; - } - - plotData[ui]->xyData.resize(ionFrequencies[ui].size()); - - //Density profiles (non-ranged plots) have a fixed normalisation factor - if(!rngData && normalise) - { - if(fixedBins) - normFactor = 1.0/(M_PI*scalarParams[0]*scalarParams[0]*(length/(float)numBins)); - else - normFactor = 1.0/(M_PI*scalarParams[0]*scalarParams[0]*binWidth); - } - - //Go through each bin, then perform the appropriate normalisation - for(unsigned int uj=0;ujxyData[uj] = std::make_pair(xPos,normFactor*(float)ionFrequencies[ui][uj]); - } - else - { - //This is a frequency profile (factor ==1), or density profile (factor computed above). - plotData[ui]->xyData[uj] = std::make_pair( - xPos,normFactor*(float)ionFrequencies[ui][uj]); - - } - } - - if(cache) - { - plotData[ui]->cached=1; - filterOutputs.push_back(plotData[ui]); - } - else - plotData[ui]->cached=0; - - plotData[ui]->plotStyle = plotStyle; - plotData[ui]->plotMode=PLOT_MODE_1D; - getOut.push_back(plotData[ui]); - } - - cacheOK=cache; - return 0; -} - -std::string CompositionProfileFilter::getErrString(unsigned int code) const -{ - switch(code) - { - case ERR_NUMBINS: - return std::string(TRANS("Too many bins in comp. profile.")); - case ERR_MEMALLOC: - return std::string(TRANS("Not enough memory for comp. profile.")); - case ERR_ABORT: - return std::string(TRANS("Aborted composition prof.")); - } - return std::string("BUG: (CompositionProfileFilter::getErrString) Shouldn't see this!"); -} - -bool CompositionProfileFilter::setProperty( unsigned int key, - const std::string &value, bool &needUpdate) -{ - - - switch(key) - { - case COMPOSITION_KEY_BINWIDTH: - { - float newBinWidth; - if(stream_cast(newBinWidth,value)) - return false; - - if(newBinWidth < sqrt(std::numeric_limits::epsilon())) - return false; - - binWidth=newBinWidth; - clearCache(); - needUpdate=true; - break; - } - case COMPOSITION_KEY_FIXEDBINS: - { - unsigned int valueInt; - if(stream_cast(valueInt,value)) - return false; - - if(valueInt ==0 || valueInt == 1) - { - if(fixedBins!= (bool)valueInt) - { - needUpdate=true; - fixedBins=valueInt; - } - else - needUpdate=false; - } - else - return false; - clearCache(); - needUpdate=true; - break; - } - case COMPOSITION_KEY_NORMAL: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(primitiveType == PRIMITIVE_CYLINDER) - { - if(lockAxisMag && - newPt.sqrMag() > sqrt(std::numeric_limits::epsilon())) - { - newPt.normalise(); - newPt*=sqrt(vectorParams[1].sqrMag()); - } - } - - if(!(vectorParams[1] == newPt )) - { - vectorParams[1] = newPt; - needUpdate=true; - clearCache(); - } - return true; - } - case COMPOSITION_KEY_NUMBINS: - { - unsigned int newNumBins; - if(stream_cast(newNumBins,value)) - return false; - - //zero bins disallowed - if(!newNumBins) - return false; - - nBins=newNumBins; - - clearCache(); - needUpdate=true; - break; - } - case COMPOSITION_KEY_ORIGIN: - { - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(vectorParams[0] == newPt )) - { - vectorParams[0] = newPt; - needUpdate=true; - clearCache(); - } - - return true; - } - case COMPOSITION_KEY_PRIMITIVETYPE: - { - unsigned int newPrimitive; - if(stream_cast(newPrimitive,value) || - newPrimitive >= PRIMITIVE_END) - return false; - - - //TODO: Convert the type data as best we can. - primitiveType=newPrimitive; - - //In leiu of covnersion, just reset the primitive - //values to some nominal defaults. - vectorParams.clear(); - scalarParams.clear(); - switch(primitiveType) - { - case PRIMITIVE_CYLINDER: - vectorParams.push_back(Point3D(0,0,0)); - vectorParams.push_back(Point3D(0,20,0)); - scalarParams.push_back(10.0f); - break; - - default: - ASSERT(false); - } - - clearCache(); - needUpdate=true; - return true; - } - case COMPOSITION_KEY_RADIUS: - { - float newRad; - if(stream_cast(newRad,value)) - return false; - - if(scalarParams[0] != newRad ) - { - scalarParams[0] = newRad; - needUpdate=true; - clearCache(); - } - return true; - } - case COMPOSITION_KEY_SHOWPRIMITIVE: - { - unsigned int valueInt; - if(stream_cast(valueInt,value)) - return false; - - if(valueInt ==0 || valueInt == 1) - { - if(showPrimitive!= (bool)valueInt) - { - needUpdate=true; - showPrimitive=valueInt; - } - else - needUpdate=false; - } - else - return false; - break; - } - - case COMPOSITION_KEY_NORMALISE: - { - unsigned int valueInt; - if(stream_cast(valueInt,value)) - return false; - - if(!(valueInt ==0 || valueInt == 1)) - return false; - - if(normalise!= (bool)valueInt) - { - needUpdate=true; - normalise=valueInt; - } - else - needUpdate=false; - - clearCache(); - needUpdate=true; - break; - } - case COMPOSITION_KEY_LOCKAXISMAG: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - lockAxisMag=(stripped=="1"); - - needUpdate=true; - - break; - } - - case COMPOSITION_KEY_PLOTTYPE: - { - unsigned int tmpPlotType; - - tmpPlotType=plotID(value); - - if(tmpPlotType >= PLOT_TRACE_ENDOFENUM) - return false; - - plotStyle = tmpPlotType; - needUpdate=true; - break; - } - case COMPOSITION_KEY_COLOUR: - { - unsigned char newR,newG,newB,newA; - parseColString(value,newR,newG,newB,newA); - - r=((float)newR)/255.0f; - g=((float)newG)/255.0f; - b=((float)newB)/255.0f; - a=1.0; - - needUpdate=true; - break; - } - case COMPOSITION_KEY_ERRMODE: - { - unsigned int tmpMode; - tmpMode=plotErrmodeID(value); - - if(tmpMode >= PLOT_ERROR_ENDOFENUM) - return false; - - errMode.mode= tmpMode; - needUpdate=true; - - break; - } - case COMPOSITION_KEY_AVGWINSIZE: - { - unsigned int tmpNum; - stream_cast(tmpNum,value); - if(tmpNum<=1) - return 1; - - errMode.movingAverageNum=tmpNum; - needUpdate=true; - break; - } - default: - ASSERT(false); - } - - if(needUpdate) - clearCache(); - - return true; -} - -void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) const -{ - string str,tmpStr; - FilterProperty p; - size_t curGroup=0; - - //Allow primitive selection if we have more than one primitive - if(PRIMITIVE_END > 1) - { - //Choices for primitive type - vector > choices; - for(unsigned int ui=0;ui > choices; - - - tmpStr=plotString(PLOT_TRACE_LINES); - choices.push_back(make_pair((unsigned int) PLOT_TRACE_LINES,tmpStr)); - tmpStr=plotString(PLOT_TRACE_BARS); - choices.push_back(make_pair((unsigned int)PLOT_TRACE_BARS,tmpStr)); - tmpStr=plotString(PLOT_TRACE_STEPS); - choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEPS,tmpStr)); - tmpStr=plotString(PLOT_TRACE_STEM); - choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEM,tmpStr)); - - tmpStr= choiceString(choices,plotStyle); - p.name=TRANS("Plot Type"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_CHOICE; - p.helpText=TRANS("Visual style for plot"); - p.key=COMPOSITION_KEY_PLOTTYPE; - propertyList.addProperty(p,curGroup); - //Convert the colour to a hex string - if(!haveRangeParent) - { - string thisCol; - genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0), - (unsigned char)(b*255.0),(unsigned char)(a*255.0),thisCol); - - p.name=TRANS("Colour"); - p.data=thisCol; - p.type=PROPERTY_TYPE_COLOUR; - p.helpText=TRANS("Colour of plot"); - p.key=COMPOSITION_KEY_COLOUR; - propertyList.addProperty(p,curGroup); - } - - - propertyList.setGroupTitle(curGroup,TRANS("Appearance")); - curGroup++; - - choices.clear(); - tmpStr=plotErrmodeString(PLOT_ERROR_NONE); - choices.push_back(make_pair((unsigned int) PLOT_ERROR_NONE,tmpStr)); - tmpStr=plotErrmodeString(PLOT_ERROR_MOVING_AVERAGE); - choices.push_back(make_pair((unsigned int) PLOT_ERROR_MOVING_AVERAGE,tmpStr)); - - tmpStr= choiceString(choices,errMode.mode); - p.name=TRANS("Err. Estimator"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_CHOICE; - p.helpText=TRANS("Method of estimating error associated with each bin"); - p.key=COMPOSITION_KEY_ERRMODE; - propertyList.addProperty(p,curGroup); - - if(errMode.mode == PLOT_ERROR_MOVING_AVERAGE) - { - stream_cast(tmpStr,errMode.movingAverageNum); - p.name=TRANS("Avg. Window"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_INTEGER; - p.helpText=TRANS("Number of bins to include in moving average filter"); - p.key=COMPOSITION_KEY_AVGWINSIZE; - propertyList.addProperty(p,curGroup); - } - propertyList.setGroupTitle(curGroup,TRANS("Error analysis")); -} - -//!Get approx number of bytes for caching output -size_t CompositionProfileFilter::numBytesForCache(size_t nObjects) const -{ - //FIXME: IMPLEMEMENT ME - return (unsigned int)(-1); -} - -bool CompositionProfileFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0; ui" << endl; - } - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0; ui" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" <" << endl; - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - - -void CompositionProfileFilter::setUserString(const std::string &str) -{ - if(userString != str) - { - userString=str; - clearCache(); - } -} - -bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - std::string tmpStr; - //Retrieve primitive type - //==== - if(XMLHelpFwdToElem(nodePtr,"primitivetype")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(primitiveType,tmpStr)) - return false; - - if(primitiveType >= PRIMITIVE_END) - return false; - xmlFree(xmlString); - //==== - - //Retrieve primitive visiblity - //==== - if(XMLHelpFwdToElem(nodePtr,"showprimitive")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - showPrimitive=false; - else if(tmpStr == "1") - showPrimitive=true; - else - return false; - - xmlFree(xmlString); - //==== - - //Retrieve axis lock mode - //==== - if(XMLHelpFwdToElem(nodePtr,"lockaxismag")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - lockAxisMag=false; - else if(tmpStr == "1") - lockAxisMag=true; - else - return false; - - xmlFree(xmlString); - //==== - - //Retreive vector parameters - //=== - if(XMLHelpFwdToElem(nodePtr,"vectorparams")) - return false; - xmlNodePtr tmpNode=nodePtr; - - nodePtr=nodePtr->xmlChildrenNode; - - vectorParams.clear(); - while(!XMLHelpFwdToElem(nodePtr,"point3d")) - { - float x,y,z; - //--Get X value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(x,tmpStr)) - return false; - - //--Get Z value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(y,tmpStr)) - return false; - - //--Get Y value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(z,tmpStr)) - return false; - - vectorParams.push_back(Point3D(x,y,z)); - } - //=== - - nodePtr=tmpNode; - //Retreive scalar parameters - //=== - if(XMLHelpFwdToElem(nodePtr,"scalarparams")) - return false; - - tmpNode=nodePtr; - nodePtr=nodePtr->xmlChildrenNode; - - scalarParams.clear(); - while(!XMLHelpFwdToElem(nodePtr,"scalar")) - { - float v; - //Get value - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(v,tmpStr)) - return false; - scalarParams.push_back(v); - } - //=== - - //Check the scalar params match the selected primitive - switch(primitiveType) - { - case PRIMITIVE_CYLINDER: - if(vectorParams.size() != 2 || scalarParams.size() !=1) - return false; - break; - default: - ASSERT(false); - return false; - } - - nodePtr=tmpNode; - - //Retrieve normalisation on/off - //==== - if(XMLHelpFwdToElem(nodePtr,"normalise")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - normalise=false; - else if(tmpStr == "1") - normalise=true; - else - return false; - - xmlFree(xmlString); - //==== - - //Retrieve fixed bins on/off - //==== - if(XMLHelpFwdToElem(nodePtr,"fixedbins")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - fixedBins=false; - else if(tmpStr == "1") - fixedBins=true; - else - return false; - - - xmlFree(xmlString); - //==== - - //Retrieve num bins - //==== - if(XMLHelpFwdToElem(nodePtr,"nbins")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(nBins,tmpStr)) - return false; - - xmlFree(xmlString); - //==== - - //Retrieve bin width - //==== - if(XMLHelpFwdToElem(nodePtr,"binwidth")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(binWidth,tmpStr)) - return false; - - xmlFree(xmlString); - //==== - - //Retrieve colour - //==== - if(XMLHelpFwdToElem(nodePtr,"colour")) - return false; - if(!parseXMLColour(nodePtr,r,g,b,a)) - return false; - //==== - - //Retrieve plot type - //==== - if(XMLHelpFwdToElem(nodePtr,"plottype")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(plotStyle,tmpStr)) - return false; - - if(plotStyle >= PLOT_TRACE_ENDOFENUM) - return false; - xmlFree(xmlString); - //==== - - return true; -} - -unsigned int CompositionProfileFilter::getRefreshBlockMask() const -{ - //Absolutely anything can go through this filter. - return 0; -} - -unsigned int CompositionProfileFilter::getRefreshEmitMask() const -{ - if(showPrimitive) - return STREAM_TYPE_PLOT | STREAM_TYPE_DRAW; - else - return STREAM_TYPE_PLOT; -} - -unsigned int CompositionProfileFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; -} - -void CompositionProfileFilter::setPropFromBinding(const SelectionBinding &b) -{ - switch(b.getID()) - { - case BINDING_CYLINDER_RADIUS: - b.getValue(scalarParams[0]); - break; - - case BINDING_CYLINDER_DIRECTION: - b.getValue(vectorParams[1]); - break; - - case BINDING_CYLINDER_ORIGIN: - b.getValue(vectorParams[0]); - break; - default: - ASSERT(false); - } - - clearCache(); -} - -#ifdef DEBUG - -bool testDensityCylinder(); -bool testCompositionCylinder(); -void synthComposition(const vector > &compositionData, - vector &h); -IonStreamData *synthLinearProfile(const Point3D &start, const Point3D &end, - float radialSpread,unsigned int numPts); - -bool CompositionProfileFilter::runUnitTests() -{ - if(!testDensityCylinder()) - return false; - - if(!testCompositionCylinder()) - return false; - - return true; -} - -bool testCompositionCylinder() -{ - IonStreamData *d; - const size_t NUM_PTS=10000; - - //Create a cylinder of data, forming a linear profile - Point3D startPt(-1.0f,-1.0f,-1.0f),endPt(1.0f,1.0f,1.0f); - d= synthLinearProfile(startPt,endPt, - 0.5f, NUM_PTS); - - //Generate two compositions for the test dataset - { - vector > vecCompositions; - vecCompositions.push_back(make_pair(2.0f,0.5f)); - vecCompositions.push_back(make_pair(3.0f,0.5f)); - synthComposition(vecCompositions,d->data); - } - - //Build a faux rangestream - RangeStreamData *rngStream; - rngStream = new RangeStreamData; - rngStream->rangeFile = new RangeFile; - - RGBf rgb; rgb.red=rgb.green=rgb.blue=1.0f; - - unsigned int aIon,bIon; - std::string tmpStr; - tmpStr="A"; - aIon=rngStream->rangeFile->addIon(tmpStr,tmpStr,rgb); - tmpStr="B"; - bIon=rngStream->rangeFile->addIon(tmpStr,tmpStr,rgb); - rngStream->rangeFile->addRange(1.5,2.5,aIon); - rngStream->rangeFile->addRange(2.5,3.5,bIon); - rngStream->enabledIons.resize(2,true); - rngStream->enabledRanges.resize(2,true); - - //Construct the composition filter - CompositionProfileFilter *f = new CompositionProfileFilter; - - //Build some points to pass to the filter - vector streamIn,streamOut; - - bool needUp; std::string s; - stream_cast(s,Point3D((startPt+endPt)*0.5f)); - TEST(f->setProperty(COMPOSITION_KEY_ORIGIN,s,needUp),"set origin"); - - stream_cast(s,Point3D((endPt-startPt)*0.5f)); - TEST(f->setProperty(COMPOSITION_KEY_NORMAL,s,needUp),"set direction"); - TEST(f->setProperty(COMPOSITION_KEY_SHOWPRIMITIVE,"1",needUp),"Set cylinder visibility"); - TEST(f->setProperty(COMPOSITION_KEY_NORMALISE,"1",needUp),"Disable normalisation"); - TEST(f->setProperty(COMPOSITION_KEY_RADIUS,"5",needUp),"Set radius"); - - //Inform the filter about the range stream - streamIn.push_back(rngStream); - f->initFilter(streamIn,streamOut); - - streamIn.push_back(d); - f->setCaching(false); - - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - - TEST(streamOut.size() == 3, "output stream count"); - - delete d; - - std::map countMap; - countMap[STREAM_TYPE_PLOT] = 0; - countMap[STREAM_TYPE_DRAW] = 0; - - for(unsigned int ui=0;uigetStreamType()) != countMap.end()); - countMap[streamOut[ui]->getStreamType()]++; - } - - TEST(countMap[STREAM_TYPE_PLOT] == 2,"Plot count"); - TEST(countMap[STREAM_TYPE_DRAW] == 1,"Draw count"); - - const PlotStreamData* plotData=0; - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - plotData = (const PlotStreamData *)streamOut[ui]; - break; - } - } - - TEST(plotData->xyData.size(),"Plot data size"); - - for(size_t ui=0;uixyData.size(); ui++) - { - TEST(plotData->xyData[ui].second <= 1.0f && - plotData->xyData[ui].second >=0.0f,"normalised data range test"); - } - - for(unsigned int ui=0;uirangeFile; - delete rngStream; - - return true; -} - -bool testDensityCylinder() -{ - IonStreamData *d; - const size_t NUM_PTS=10000; - - //Create a cylinder of data, forming a linear profile - Point3D startPt(-1.0f,-1.0f,-1.0f),endPt(1.0f,1.0f,1.0f); - d= synthLinearProfile(startPt,endPt, - 0.5f, NUM_PTS); - - //Generate two compositions for the test dataset - { - vector > vecCompositions; - vecCompositions.push_back(make_pair(2.0f,0.5f)); - vecCompositions.push_back(make_pair(3.0f,0.5f)); - synthComposition(vecCompositions,d->data); - } - - CompositionProfileFilter *f = new CompositionProfileFilter; - f->setCaching(false); - - //Build some points to pass to the filter - vector streamIn,streamOut; - streamIn.push_back(d); - - bool needUp; std::string s; - stream_cast(s,Point3D((startPt+endPt)*0.5f)); - TEST(f->setProperty(COMPOSITION_KEY_ORIGIN,s,needUp),"set origin"); - - stream_cast(s,Point3D((endPt-startPt)*0.5f)); - TEST(f->setProperty(COMPOSITION_KEY_NORMAL,s,needUp),"set direction"); - - TEST(f->setProperty(COMPOSITION_KEY_SHOWPRIMITIVE,"1",needUp),"Set cylinder visibility"); - - TEST(f->setProperty(COMPOSITION_KEY_NORMALISE,"0",needUp),"Disable normalisation"); - TEST(f->setProperty(COMPOSITION_KEY_RADIUS,"5",needUp),"Set radius"); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - delete f; - delete d; - - - TEST(streamOut.size() == 2, "output stream count"); - - std::map countMap; - countMap[STREAM_TYPE_PLOT] = 0; - countMap[STREAM_TYPE_DRAW] = 0; - - for(unsigned int ui=0;uigetStreamType()) != countMap.end()); - countMap[streamOut[ui]->getStreamType()]++; - } - - TEST(countMap[STREAM_TYPE_PLOT] == 1,"Plot count"); - TEST(countMap[STREAM_TYPE_DRAW] == 1,"Draw count"); - - - const PlotStreamData* plotData=0; - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - plotData = (const PlotStreamData *)streamOut[ui]; - break; - } - } - - float sum=0; - for(size_t ui=0;uixyData.size(); ui++) - sum+=plotData->xyData[ui].second; - - - TEST(sum > NUM_PTS/1.2f,"Number points roughly OK"); - TEST(sum <= NUM_PTS,"No overcounting"); - - for(unsigned int ui=0;ui > &compositionData, - vector &h) -{ - float fractionSum=0; - for(size_t ui=0;ui > ionCuts; - ionCuts.resize(compositionData.size()); - //ionCuts.resize[compositionData.size()]; - float runningSum=0; - for(size_t ui=0;ui=ionCuts[uj].second) - { - newMass=ionCuts[uj].first; - haveSetMass=true; - break; - } - } - }while(!haveSetMass); - - - h[ui].setMassToCharge(newMass); - } -} - - -//Create a line of points of fixed mass (1), with a top-hat radial spread function -// so we end up with a cylinder of unit mass data along some start-end axis -//you must free the returned value by calling "delete" -IonStreamData *synthLinearProfile(const Point3D &start, const Point3D &end, - float radialSpread,unsigned int numPts) -{ - - ASSERT((start-end).sqrMag() > std::numeric_limits::epsilon()); - IonStreamData *d = new IonStreamData; - - IonHit h; - h.setMassToCharge(1.0f); - - Point3D delta; - delta=(end-start)*1.0f/(float)numPts; - - RandNumGen rngAxial; - rngAxial.initTimer(); - - Point3D unitDelta; - unitDelta=delta; - unitDelta.normalise(); - - - d->data.resize(numPts); - for(size_t ui=0;ui::epsilon() && - randomVector.angle(delta) < std::numeric_limits::epsilon()); - - - randomVector=randomVector.crossProd(unitDelta); - randomVector.normalise(); - - //create the point - Point3D pt; - pt=delta*(float)ui + start; //true location - pt+=randomVector*radialSpread; - h.setPos(pt); - d->data[ui] =h; - } - - return d; -} -#endif diff -Nru 3depict-0.0.12/src/filters/compositionProfile.h 3depict-0.0.13/src/filters/compositionProfile.h --- 3depict-0.0.12/src/filters/compositionProfile.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/compositionProfile.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -#ifndef COMPPROFILE_H -#define COMPPROFILE_H -#include "../filter.h" -#include "../translation.h" - -enum -{ - COMPOSITION_KEY_BINWIDTH=1, - COMPOSITION_KEY_FIXEDBINS, - COMPOSITION_KEY_NORMAL, - COMPOSITION_KEY_NUMBINS, - COMPOSITION_KEY_ORIGIN, - COMPOSITION_KEY_PLOTTYPE, - COMPOSITION_KEY_PRIMITIVETYPE, - COMPOSITION_KEY_RADIUS, - COMPOSITION_KEY_SHOWPRIMITIVE, - COMPOSITION_KEY_NORMALISE, - COMPOSITION_KEY_COLOUR, - COMPOSITION_KEY_ERRMODE, - COMPOSITION_KEY_AVGWINSIZE, - COMPOSITION_KEY_LOCKAXISMAG -}; -//!Filter that does composition profiles for various primitives -class CompositionProfileFilter : public Filter -{ - private: - - //!Number explaining basic primitive type - /* Possible Modes: - * Cylindrical (origin + axis + length) - */ - unsigned int primitiveType; - //!Whether to show the primitive or not - bool showPrimitive; - //Lock the primitive axis during for cylinder? - bool lockAxisMag; - //!Vector paramaters for different primitives - vector vectorParams; - //!Scalar paramaters for different primitives - vector scalarParams; - - //!Frequency or percentile mode (0 - frequency; 1-normalised (ion freq)) - bool normalise; - //!Use fixed bins? - bool fixedBins; - - //!number of bins (if using fixed bins) - unsigned int nBins; - //!Width of each bin (if using fixed wdith) - float binWidth; - - //Plotting stuff - //Vector of spectra. Each spectra is comprised of a sorted Y data - std::vector< std::vector > spectraCache; - float r,g,b,a; - unsigned int plotStyle; - - PLOT_ERROR errMode; - - //!Do we have a range file above us in our filter tree? This is set by ::initFilter - bool haveRangeParent; - - //!internal function for binning an ion dependant upon range data - static void binIon(unsigned int targetBin, const RangeStreamData* rng, const std::map &ionIDMapping, - vector > &frequencyTable, float massToCharge); - - public: - CompositionProfileFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - //!Returns FILTER_TYPE_COMPOSITION - unsigned int getType() const { return FILTER_TYPE_COMPOSITION;}; - - //!Get approx number of bytes for caching output - size_t numBytesForCache(size_t nObjects) const; - - - //!Initialise filter, check for upstream range - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - //!update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - virtual std::string typeString() const { return std::string(TRANS("Comp. Prof."));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter. Returns true if prop set OK - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that may be utilised in computation during ::refresh - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding - void setPropFromBinding(const SelectionBinding &b) ; - - void setUserString(const std::string &s); - -#ifdef DEBUG - bool runUnitTests() ; -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/dataLoad.cpp 3depict-0.0.13/src/filters/dataLoad.cpp --- 3depict-0.0.12/src/filters/dataLoad.cpp 2012-11-18 11:46:26.000000000 +0000 +++ 3depict-0.0.13/src/filters/dataLoad.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1298 +0,0 @@ -#include "dataLoad.h" - -//Needed for modification time -#include -#include -#include -#include "../wxcommon.h" - -#include "../xmlHelper.h" -#include "../basics.h" - -#include "../translation.h" - - -//Default number of ions to load -const size_t MAX_IONS_LOAD_DEFAULT=5*1024*1024/(4*sizeof(float)); //5 MB worth. - -// Tp prevent the dropdown lists from getting too unwieldy, set an artificial maximum -const unsigned int MAX_NUM_FILE_COLS=5000; - -//Allowable text file deliminators -const char *TEXT_DELIMINATORS = "\t ,"; - -//Supported data types -enum -{ - FILEDATA_TYPE_POS, - FILEDATA_TYPE_TEXT, - FILEDATA_TYPE_ENUM_END, // Not a data type, just end of enum -}; - -const char *AVAILABLE_FILEDATA_TYPES[] = { NTRANS("POS Data"), - NTRANS("Text Data"), - }; -const char *DEFAULT_LABEL="Mass-to-Charge (amu/e)"; - -// == Pos load filter == -DataLoadFilter::DataLoadFilter() : fileType(FILEDATA_TYPE_POS), doSample(true), maxIons(MAX_IONS_LOAD_DEFAULT), - r(1.0f),g(0.0f),b(0.0f),a(1.0f),ionSize(2.0f), numColumns(4), enabled(true), - volumeRestrict(false), monitorTimestamp(-1),monitorSize((size_t)-1),wantMonitor(false), - valueLabel(TRANS(DEFAULT_LABEL)) -{ - COMPILE_ASSERT(ARRAYSIZE(AVAILABLE_FILEDATA_TYPES) == FILEDATA_TYPE_ENUM_END); - cache=true; - - bound.setInverseLimits(); - - for (unsigned int i = 0; i < numColumns; i++) { - index[i] = i; - } - -} - -Filter *DataLoadFilter::cloneUncached() const -{ - DataLoadFilter *p=new DataLoadFilter; - p->ionFilename=ionFilename; - p->doSample=doSample; - p->maxIons=maxIons; - p->ionSize=ionSize; - p->fileType=fileType; - p->guessType=guessType; - //Colours - p->r=r; - p->g=g; - p->b=b; - p->a=a; - p->fileType=fileType; - //Bounding volume - p->bound.setBounds(bound); - p->volumeRestrict=volumeRestrict; - p->numColumns=numColumns; - p->enabled=enabled; - - for(size_t ui=0;uiindex[ui]=index[ui]; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->enabled=enabled; - p->userString=userString; - - p->wantMonitor=wantMonitor; - // this is for a pos file - memcpy(p->index, index, sizeof(int) * 4); - p->numColumns=numColumns; - - return p; -} - - -void DataLoadFilter::setFileMode(unsigned int fileMode) -{ - switch(fileMode) - { - case DATALOAD_TEXT_FILE: - fileType=FILEDATA_TYPE_TEXT; - break; - case DATALOAD_FLOAT_FILE: - fileType=FILEDATA_TYPE_POS; - break; - default: - ASSERT(false); - } -} - - -void DataLoadFilter::setFilename(const char *name) -{ - ionFilename = name; - guessNumColumns(); -} - -void DataLoadFilter::setFilename(const std::string &name) -{ - ionFilename = name; - guessNumColumns(); -} - -void DataLoadFilter::guessNumColumns() -{ - //Test the extension to determine what we will do - string extension; - if(ionFilename.size() > 4) - extension = ionFilename.substr ( ionFilename.size() - 4, 4 ); - - //Set extension to lowercase version - for(size_t ui=0;ui &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - errStr=""; - //use the cached copy if we have it. - if(cacheOK) - { - bool doUseCache=true; - //If we are monitoring the file, - //the cache is only valid if we have - //the same timestamp as on the file. - if(wantMonitor) - { - if(!wxFile::Exists(wxStr(ionFilename))) - { - monitorTimestamp=-1; - monitorSize=-1; - doUseCache=false; - clearCache(); - } - else - { - //How can we have a valid cache if we don't - //have a valid load time? - ASSERT(monitorTimestamp!=-1 && monitorSize!=(size_t)-1); - - - size_t fileSizeVal; - getFilesize(ionFilename.c_str(),fileSizeVal); - if(wxFileModificationTime(wxStr(ionFilename)) ==monitorTimestamp - || fileSizeVal!= monitorSize) - { - doUseCache=false; - clearCache(); - } - } - } - - //Use the cache if it is still OK, otherwise use - //the full function - if(doUseCache) - { - ASSERT(filterOutputs.size()); - for(unsigned int ui=0;uiparent=this; - - unsigned int uiErr; - switch(fileType) - { - case FILEDATA_TYPE_POS: - { - if(doSample) - { - //Load the pos file, limiting how much you pull from it - if((uiErr = LimitLoadPosFile(numColumns, INDEX_LENGTH, index, ionData->data, ionFilename.c_str(), - maxIons,progress.filterProgress,callback,strongRandom))) - { - consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); - delete ionData; - errStr=TRANS(POS_ERR_STRINGS[uiErr]); - return uiErr; - } - } - else - { - if((uiErr = GenericLoadFloatFile(numColumns, INDEX_LENGTH, index, ionData->data, ionFilename.c_str(), - progress.filterProgress,callback))) - { - consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); - delete ionData; - errStr=TRANS(POS_ERR_STRINGS[uiErr]); - return uiErr; - } - } - break; - } - case FILEDATA_TYPE_TEXT: - { - - - if(doSample) - { - //TODO: Migrate to using a generic text data loading routine - // rather than an IonHit specific one, to avoid need for separate error strings - //Load the data from a text file - if((uiErr = limitLoadTextFile(INDEX_LENGTH,index,ionData->data, ionFilename.c_str(),TEXT_DELIMINATORS, - maxIons,progress.filterProgress,callback,strongRandom))) - { - consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); - delete ionData; - errStr=ION_TEXT_ERR_STRINGS[uiErr]; - return uiErr; - } - } - else - { - vector > outDat; - vector headerData; - if((uiErr=loadTextData(ionFilename.c_str(),outDat,headerData,TEXT_DELIMINATORS))) - { - consoleOutput.push_back(string(TRANS("Error loading file: ")) + ionFilename); - delete ionData; - errStr=TEXT_LOAD_ERR_STRINGS[uiErr]; - return uiErr; - } - - - - if(outDat.size() !=4) - { - std::string sizeStr; - stream_cast(sizeStr,outDat.size()); - - consoleOutput.push_back( - string(TRANS("Data file contained incorrect number of columns -- should be 4, was ")) + sizeStr ); - - errStr=TEXT_LOAD_ERR_STRINGS[ERR_FILE_FORMAT]; - return ERR_FILE_FORMAT; - } - - - ASSERT(outDat[0].size() == outDat[1].size() && - outDat[1].size() == outDat[2].size() - && outDat[2].size() == outDat[3].size()); - - ionData->data.resize(outDat[0].size()); - #pragma omp parallel for - for(unsigned int ui=0;uidata[ui].setPos(outDat[0][ui],outDat[1][ui],outDat[2][ui]); - ionData->data[ui].setMassToCharge(outDat[3][ui]); - } - } - - - break; - } - - default: - ASSERT(false); - } - - - ionData->r = r; - ionData->g = g; - ionData->b = b; - ionData->a = a; - ionData->ionSize=ionSize; - ionData->valueType=valueLabel; - - - if(ionData->data.empty()) - { - //Shouldn't get here... - ASSERT(false); - delete ionData; - return 0; - } - - - BoundCube dataCube; - dataCube = getIonDataLimits(ionData->data); - - if(dataCube.isNumericallyBig()) - { - consoleOutput.push_back( - TRANS("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")); - } - - string s; - stream_cast(s,ionData->data.size()); - consoleOutput.push_back( string(TRANS("Loaded ") + s + TRANS(" Points")) ); - if(cache) - { - ionData->cached=1; - filterOutputs.push_back(ionData); - cacheOK=true; - } - else - ionData->cached=0; - - for(unsigned int ui=0;ui > choices; - - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - IonStreamData *i; - i=(IonStreamData *)filterOutputs[ui]; - i->r=r; - i->g=g; - i->b=b; - i->a=a; - } - } - - } - needUpdate=true; - } - - - break; - } - case DATALOAD_KEY_IONSIZE: - { - float ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp < 0) - return false; - - ionSize=ltmp; - - //Check the cache, updating it if needed - if(cacheOK) - { - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - IonStreamData *i; - i=(IonStreamData *)filterOutputs[ui]; - i->ionSize=ionSize; - } - } - } - needUpdate=true; - - break; - } - case DATALOAD_KEY_VALUELABEL: - { - if(value !=valueLabel) - { - valueLabel=value; - needUpdate=true; - - //Check the cache, updating it if needed - if(cacheOK) - { - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - IonStreamData *i; - i=(IonStreamData *)filterOutputs[ui]; - i->valueType=valueLabel; - } - } - } - - } - - break; - } - case DATALOAD_KEY_SELECTED_COLUMN0: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp >= numColumns) - return false; - - index[0]=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case DATALOAD_KEY_SELECTED_COLUMN1: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp >= numColumns) - return false; - - index[1]=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case DATALOAD_KEY_SELECTED_COLUMN2: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp >= numColumns) - return false; - - index[2]=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case DATALOAD_KEY_SELECTED_COLUMN3: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp >= numColumns) - return false; - - index[3]=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case DATALOAD_KEY_NUMBER_OF_COLUMNS: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp >= MAX_NUM_FILE_COLS) - return false; - - numColumns=ltmp; - for (unsigned int i = 0; i < INDEX_LENGTH; i++) { - index[i] = (index[i] < numColumns? index[i]: numColumns - 1); - } - needUpdate=true; - clearCache(); - - break; - } - default: - ASSERT(false); - break; - } - return true; -} - -bool DataLoadFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - //Retrieve file name - if(XMLHelpFwdToElem(nodePtr,"file")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); - if(!xmlString) - return false; - ionFilename=(char *)xmlString; - xmlFree(xmlString); - - //retrieve file type (text,pos etc), if needed; default to pos. - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"type"); - if(xmlString) - { - int type; - if(stream_cast(type,xmlString)) - return false; - - if(fileType >=FILEDATA_TYPE_ENUM_END) - return false; - fileType=type; - xmlFree(xmlString); - } - else - fileType=FILEDATA_TYPE_POS; - - - //Override the string, as needed - if( (stateFileDir.size()) && - (ionFilename.size() > 2 && ionFilename.substr(0,2) == "./") ) - { - ionFilename=stateFileDir + ionFilename.substr(2); - } - - //Filenames need to be converted from unix format (which I make canonical on disk) into native format - ionFilename=convertFileStringToNative(ionFilename); - - //Retrieve number of columns - if(!XMLGetNextElemAttrib(nodePtr,numColumns,"columns","value")) - return false; - if(numColumns >= MAX_NUM_FILE_COLS) - return false; - - //Retrieve index - if(XMLHelpFwdToElem(nodePtr,"xyzm")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values"); - if(!xmlString) - return false; - std::vector v; - splitStrsRef((char *)xmlString,',',v); - for (unsigned int i = 0; i < INDEX_LENGTH && i < v.size(); i++) - { - if(stream_cast(index[i],v[i])) - return false; - - if(index[i] >=numColumns) - return false; - } - xmlFree(xmlString); - - //Retrieve enabled/disabled - //-- - unsigned int tmpVal; - if(!XMLGetNextElemAttrib(nodePtr,tmpVal,"enabled","value")) - return false; - enabled=tmpVal; - //-- - - //Retrieve monitor mode - //-- - xmlNodePtr nodeTmp; - nodeTmp=nodePtr; - if(XMLGetNextElemAttrib(nodePtr,tmpVal,"monitor","value")) - wantMonitor=tmpVal; - else - { - nodePtr=nodeTmp; - wantMonitor=false; - } - //-- - - //Retrieve value type string (eg mass-to-charge, - // or whatever the data type is) - //-- - nodeTmp=nodePtr; - if(XMLHelpFwdToElem(nodePtr,"valuetype")) - { - nodePtr=nodeTmp; - valueLabel=TRANS(DEFAULT_LABEL); - } - else - { - xmlChar *xmlString; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - valueLabel=(char *)xmlString; - xmlFree(xmlString); - - } - - //-- - - - //Get sampling enabled/disabled - //--- - //TODO: Remove me: - // Note, in 3Depict-0.0.10 and lower, we did not have this option, - // so some statefiles will exist without this. In the case it is not - // found, we need to make it up - { - nodeTmp=nodePtr; - bool needSampleState=false; - if(!XMLGetNextElemAttrib(nodePtr,doSample,"dosample","value")) - { - nodePtr=nodeTmp; - needSampleState=true; - } - //--- - - //Get max Ions - //-- - //TODO: Forbid zero values - don't do it now, as we previously used this - // for disabling sampling, so some users' XML files will still have this - if(!XMLGetNextElemAttrib(nodePtr,maxIons,"maxions","value")) - return false; - - if(needSampleState) - doSample=maxIons; - //-- - } - //Retrieve colour - //==== - if(XMLHelpFwdToElem(nodePtr,"colour")) - return false; - - if(!parseXMLColour(nodePtr,r,g,b,a)) - return false; - //==== - - //Retrieve drawing size value - //-- - if(!XMLGetNextElemAttrib(nodePtr,ionSize,"ionsize","value")) - return false; - //check positive or zero - if(ionSize <=0) - return false; - //-- - - - return true; -} - -unsigned int DataLoadFilter::getRefreshBlockMask() const -{ - return 0; -} - -unsigned int DataLoadFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_IONS; -} - -unsigned int DataLoadFilter::getRefreshUseMask() const -{ - return 0; -} - -std::string DataLoadFilter::getErrString(unsigned int code) const -{ - ASSERT(errStr.size()); - return errStr; -} - -bool DataLoadFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << ""<< endl; - f << tabs(depth+1) << ""<< endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" <" << endl; - f << tabs(depth) << "" << endl; - break; - } - default: - //Shouldn't get here, unhandled format string - ASSERT(false); - return false; - } - - return true; - -} - -bool DataLoadFilter::writePackageState(std::ostream &f, unsigned int format, - const std::vector &valueOverrides, unsigned int depth) const -{ - ASSERT(valueOverrides.size() == 1); - - //Temporarily modify the state of the filter, then call writestate - string tmpIonFilename=ionFilename; - - - //override const -- naughty, but we know what we are doing... - const_cast(this)->ionFilename=valueOverrides[0]; - bool result; - result=writeState(f,format,depth); - - const_cast(this)->ionFilename=tmpIonFilename; - - return result; -} - -void DataLoadFilter::getStateOverrides(std::vector &externalAttribs) const -{ - externalAttribs.push_back(ionFilename); - -} - -bool DataLoadFilter::monitorNeedsRefresh() const -{ - if(wantMonitor) - { - //Prevent call to ionFilename - if(!wxFile::Exists(wxStr(ionFilename))) - return cacheOK; - - - size_t sizeVal; - getFilesize(ionFilename.c_str(),sizeVal); - if(sizeVal != monitorSize) - return true; - - return( wxFileModificationTime(wxStr(ionFilename)) - !=monitorTimestamp); - - - } - - - return false; -} - - -#ifdef DEBUG - -#include - -bool posFileTest(); -bool textFileTest(); - - -bool DataLoadFilter::runUnitTests() -{ - if(!posFileTest()) - return false; - - if(!textFileTest()) - return false; - - return true; -} - -bool posFileTest() -{ - //Synthesise data, then *save* it. - - const unsigned int NUM_PTS=133; - vector hits; - hits.resize(NUM_PTS); - for(unsigned int ui=0; uisetCaching(false); - - bool needUp; - d->setProperty(DATALOAD_KEY_FILE,posName,needUp); - d->setProperty(DATALOAD_KEY_SAMPLE,"0",needUp); - //--------- - - vector streamIn,streamOut; - ProgressData prog; - TEST(!d->refresh(streamIn,streamOut,prog,dummyCallback),"Refresh error code"); - delete d; - - - TEST(streamOut.size() == 1, "Stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "Stream type"); - - TEST(streamOut[0]->getNumBasicObjects() == hits.size(), "Stream count"); - - -#if defined(__LINUX__) || defined(__APPLE__) - //Hackish mathod to delete file - std::string s; - s=string("rm -f ") + string(posName); - system(s.c_str()); -#endif - - delete streamOut[0]; - return true; -} - -bool textFileTest() -{ - //write some random data - // with a fixed seed value - RandNumGen r; - r.initialise(232635); - const unsigned int NUM_PTS=1000; - - //TODO: do better than this - const char *FILENAME="test-3mdfuneaascn.txt"; - //see if we can open the file for input. If so, it must exist, - //and thus we don't want to overwite it, as it may contain useful data. - std::ifstream inFile(FILENAME); - if(inFile) - { - std::string s; - s="Unwilling to execute file test, will not overwrite file :"; - s+=FILENAME; - s+=". Test is indeterminate"; - WARN(false,s.c_str()); - - return true; - } - - std::ofstream outFile(FILENAME); - - if(!outFile) - { - WARN(false,"Unable to create test output file. Unit test was indeterminate. Requires write access to excution path"); - return true; - } - - vector hitVec; - hitVec.resize(NUM_PTS); - - //Write out the file - outFile << "x y\tz\tValues" << endl; - for(unsigned int ui=0;uisetCaching(false); - - bool needUp; - d->setProperty(DATALOAD_KEY_FILE,FILENAME,needUp); - d->setProperty(DATALOAD_KEY_SAMPLE,"0",needUp); //load all data - //Load data as text file - d->setProperty(DATALOAD_KEY_FILETYPE, - AVAILABLE_FILEDATA_TYPES[FILEDATA_TYPE_TEXT],needUp); - //--------- - - - vector streamIn,streamOut; - ProgressData prog; - TEST(!d->refresh(streamIn,streamOut,prog,dummyCallback),"Refresh error code"); - delete d; - - - TEST(streamOut.size() == 1, "Stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "Stream type"); - - TEST(streamOut[0]->getNumBasicObjects() == NUM_PTS,"Stream count"); - -#if defined(__LINUX__) || defined(__APPLE__) - //Hackish mathod to delete file - std::string s; - s=string("rm -f ") + string(FILENAME); - system(s.c_str()); -#endif - - delete streamOut[0]; - return true; -} - -#endif diff -Nru 3depict-0.0.12/src/filters/dataLoad.h 3depict-0.0.13/src/filters/dataLoad.h --- 3depict-0.0.12/src/filters/dataLoad.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/dataLoad.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,167 +0,0 @@ -#ifndef DATALOAD_H -#define DATALOAD_H - -#include "../filter.h" - -#include "../translation.h" - -enum -{ - DATALOAD_FLOAT_FILE, - DATALOAD_TEXT_FILE -}; - -enum -{ - DATALOAD_KEY_FILE, - DATALOAD_KEY_FILETYPE, - DATALOAD_KEY_SAMPLE, - DATALOAD_KEY_SIZE, - DATALOAD_KEY_COLOUR, - DATALOAD_KEY_IONSIZE, - DATALOAD_KEY_ENABLED, - DATALOAD_KEY_VALUELABEL, - DATALOAD_KEY_SELECTED_COLUMN0, - DATALOAD_KEY_SELECTED_COLUMN1, - DATALOAD_KEY_SELECTED_COLUMN2, - DATALOAD_KEY_SELECTED_COLUMN3, - DATALOAD_KEY_NUMBER_OF_COLUMNS, - DATALOAD_KEY_MONITOR -}; - -class DataLoadFilter:public Filter -{ - protected: - //!filename from which the ions are being loaded - std::string ionFilename; - - //!Type of file to open - unsigned int fileType; - - //!Try our best to guess the file type? - bool guessType; - - - //!Whether to randomly sample dataset during load or not - bool doSample; - - //!Maximum number of ions to load, if performing sampling - size_t maxIons; - - //!Default ion colour vars - float r,g,b,a; - - //!Default ion size (view size) - float ionSize; - - //!Number of columns & type of file - unsigned int numColumns; - - static const unsigned int INDEX_LENGTH = 4; - //!index of columns into pos file, if pos data is visualised as a set of float record presented as a table (one line per record) - unsigned int index[INDEX_LENGTH];//x,y,z,value - - //!Is pos load enabled? - bool enabled; - - //!Volume restricted load? - bool volumeRestrict; - - //!volume restriction bounds, not sorted - BoundCube bound; - - //Epoch timestamp for the mointored file. -1 if invalid - time_t monitorTimestamp; - - //File size for monitored file - size_t monitorSize; - - //Do we want to be monitoring - //the timestamp of the file - bool wantMonitor; - - //!string to use in error situation, set during ::refresh - std::string errStr; - - //!String to use to set the value type - std::string valueLabel; - public: - DataLoadFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - //!Set the source string - void setFilename(const char *name); - void setFilename(const std::string &name); - void guessNumColumns(); - - //!Set the filter to either use text or pos as requested, - // this does not require exposing the file parameter key - void setFileMode(unsigned int mode); - - //!Get filter type (returns FILTER_TYPE_DATALOAD) - unsigned int getType() const { return FILTER_TYPE_DATALOAD;}; - - //!Get (approx) number of bytes required for cache - virtual size_t numBytesForCache(size_t nOBjects) const; - - //!Refresh object data - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - void updatePosData(); - - virtual std::string typeString() const { return std::string(TRANS("Pos Data"));} - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty( unsigned int key, const std::string &value, bool &needUpdate); - - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - - //!write an overridden filename version of the state - virtual bool writePackageState(std::ostream &f, unsigned int format, - const std::vector &valueOverrides,unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the block mask for this filter (bitmaks of streams blocked from propagation during ::refresh) - virtual unsigned int getRefreshBlockMask() const; - //!Get the refresh mask for this filter (bitmaks of streams emitted during ::refresh) - virtual unsigned int getRefreshEmitMask() const; - - //!Get the refresh use mask for this filter (bitmaks of streams possibly used during ::refresh) - virtual unsigned int getRefreshUseMask() const; - - //!Pos filter has state overrides - virtual void getStateOverrides(std::vector &overrides) const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - - //!Get the label for the chosen value column - std::string getValueLabel(); - - //!Return if we need monitoring or not - virtual bool monitorNeedsRefresh() const; - - //Are we a pure data source - i.e. can function with no input - virtual bool isPureDataSource() const { return true;}; - - //Can we be a useful filter, even if given no input specified by the Use mask? - virtual bool isUsefulAsAppend() const { return true;} - -#ifdef DEBUG - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/externalProgram.cpp 3depict-0.0.13/src/filters/externalProgram.cpp --- 3depict-0.0.12/src/filters/externalProgram.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/externalProgram.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,881 +0,0 @@ -#include "externalProgram.h" -#include "../wxcommon.h" - -#include "../xmlHelper.h" - -#include "../translation.h" - -#include -#include -#include - -enum -{ - KEY_COMMAND, - KEY_WORKDIR, - KEY_ALWAYSCACHE, - KEY_CLEANUPINPUT -}; - -//!Error codes -enum -{ - COMMANDLINE_FAIL=1, - SETWORKDIR_FAIL, - WRITEPOS_FAIL, - WRITEPLOT_FAIL, - MAKEDIR_FAIL, - PLOTCOLUMNS_FAIL, - READPLOT_FAIL, - READPOS_FAIL, - SUBSTITUTE_FAIL, - COMMAND_FAIL, -}; - -//=== External program filter === -ExternalProgramFilter::ExternalProgramFilter() : alwaysCache(false), - cleanInput(true) -{ - cacheOK=false; - cache=false; -} - -Filter *ExternalProgramFilter::cloneUncached() const -{ - ExternalProgramFilter *p=new ExternalProgramFilter(); - - //Copy the values - p->workingDir=workingDir; - p->commandLine=commandLine; - p->alwaysCache=alwaysCache; - p->cleanInput=cleanInput; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -size_t ExternalProgramFilter::numBytesForCache(size_t nObjects) const -{ - if(alwaysCache) - return 0; - else - return (size_t)-1; //Say we don't know, we are not going to cache anyway. -} - -unsigned int ExternalProgramFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - //use the cached copy if we have it. - if(cacheOK) - { - for(unsigned int ui=0;ui commandLineSplit; - - splitStrsRef(commandLine.c_str(),' ',commandLineSplit); - //Nothing to do - if(commandLineSplit.empty()) - return 0; - - vector ionOutputNames,plotOutputNames; - - //Compute the bounding box of the incoming streams - string s; - wxString tempDir; - if(workingDir.size()) - tempDir=(wxStr(workingDir) +wxT("/inputData")); - else - tempDir=(wxT("inputData")); - - - //Create a temporary dir - if(!wxDirExists(tempDir) ) - { - //Audacity claims that this can return false even on - //success (NoiseRemoval.cpp, line 148). - //I was having problems with this function too; - //so use their workaround - wxMkdir(tempDir); - - if(!wxDirExists(tempDir) ) - return MAKEDIR_FAIL; - - } - - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *i; - i = (const IonStreamData * )(dataIn[ui]); - - if(i->data.empty()) - break; - //Save the data to a file - wxString tmpStr; - - tmpStr=wxFileName::CreateTempFileName(tempDir+ wxT("/pointdata")); - //wxwidgets has no suffix option... annoying. - wxRemoveFile(tmpStr); - - s = stlStr(tmpStr); - s+=".pos"; - if(IonVectorToPos(i->data,s)) - { - //Uh-oh problem. Clean up and exit - return WRITEPOS_FAIL; - } - - ionOutputNames.push_back(s); - break; - } - case STREAM_TYPE_PLOT: - { - const PlotStreamData *i; - i = (const PlotStreamData * )(dataIn[ui]); - - if(i->xyData.empty()) - break; - //Save the data to a file - wxString tmpStr; - - tmpStr=wxFileName::CreateTempFileName(tempDir + wxT("/plot")); - //wxwidgets has no suffix option... annoying. - wxRemoveFile(tmpStr); - s = stlStr(tmpStr); - s+= ".xy"; - if(!writeTextFile(s.c_str(),i->xyData)) - { - //Uh-oh problem. Clean up and exit - return WRITEPLOT_FAIL; - } - - plotOutputNames.push_back(s); - break; - } - default: - break; - } - } - - //Nothing to do. - if(plotOutputNames.empty() && - ionOutputNames.empty()) - return 0; - - - //Construct the command, using substitution - string command; - unsigned int ionOutputPos,plotOutputPos; - ionOutputPos=plotOutputPos=0; - command = commandLineSplit[0]; - for(unsigned int ui=1;uiGetAllFiles(wxStr(workingDir),a,_("*.pos"),wxDIR_FILES); - else - dir->GetAllFiles(wxGetCwd(),a,_("*.pos"),wxDIR_FILES); - - - //read the output files, which is assumed to be any "pos" file - //in the working dir - for(unsigned int ui=0;uiCount(); ui++) - { - wxULongLong size; - size = wxFileName::GetSize((*a)[ui]); - - if( (size !=0) && size!=wxInvalidSize) - { - //Load up the pos file - - string sTmp; - wxString wxTmpStr; - wxTmpStr=(*a)[ui]; - sTmp = stlStr(wxTmpStr); - unsigned int dummy; - IonStreamData *d = new IonStreamData(); - d->parent=this; - //TODO: some kind of secondary file for specification of - //ion attribs? - d->r = 1.0; - d->g=0; - d->b=0; - d->a=1.0; - d->ionSize = 2.0; - - unsigned int index2[] = { - 0, 1, 2, 3 - }; - if(GenericLoadFloatFile(4, 4, index2, d->data,sTmp.c_str(),dummy,dummyCallback)) - return READPOS_FAIL; - - - if(alwaysCache) - { - d->cached=1; - filterOutputs.push_back(d); - } - else - d->cached=0; - getOut.push_back(d); - } - } - - a->Clear(); - if(workingDir.size()) - dir->GetAllFiles(wxStr(workingDir),a,_("*.xy"),wxDIR_FILES); - else - dir->GetAllFiles(wxGetCwd(),a,_("*.xy"),wxDIR_FILES); - - //read the output files, which is assumed to be any "pos" file - //in the working dir - for(unsigned int ui=0;uiCount(); ui++) - { - wxULongLong size; - size = wxFileName::GetSize((*a)[ui]); - - if( (size !=0) && size!=wxInvalidSize) - { - string sTmp; - wxString wxTmpStr; - wxTmpStr=(*a)[ui]; - sTmp = stlStr(wxTmpStr); - - vector > dataVec; - - vector header; - - //Possible delimiters to try when loading file - //try each in turn - const char *delimString ="\t, "; - if(!loadTextData(sTmp.c_str(),dataVec,header,delimString)) - return READPLOT_FAIL; - - //Check that the input has the correct size - for(unsigned int uj=0;ujparent=this; - d->r = 0.0; - d->g=1.0; - d->b=0; - d->a=1.0; - - - //set the title to the filename (trim the .xy extension - //and the working directory name) - string tmpFilename; - tmpFilename=sTmp.substr(workingDir.size(),sTmp.size()- - workingDir.size()-3); - - d->dataLabel=getUserString() + string(":") + onlyFilename(tmpFilename); - - if(applyLabels) - { - - //set the xy-labels to the column headers - d->xLabel=header[uj]; - d->yLabel=header[uj+1]; - } - else - { - d->xLabel="x"; - d->yLabel="y"; - } - - d->xyData.resize(dataVec[uj].size()); - - ASSERT(dataVec[uj].size() == dataVec[uj+1].size()); - for(unsigned int uk=0;ukxyData[uk]=make_pair(dataVec[uj][uk], - dataVec[uj+1][uk]); - } - - if(alwaysCache) - { - d->cached=1; - filterOutputs.push_back(d); - } - else - d->cached=0; - - getOut.push_back(d); - } - } - } - - if(alwaysCache) - cacheOK=true; - - delete dir; - delete a; - - return 0; -} - - -void ExternalProgramFilter::getProperties(FilterPropGroup &propertyList) const -{ - std::string tmpStr; - size_t curGroup=0; - FilterProperty p; - - p.name=TRANS("Command"); - p.data= commandLine; - p.type=PROPERTY_TYPE_STRING; - p.helpText=TRANS("Full command to send to operating system. See manual for escape sequence meanings"); - p.key=KEY_COMMAND; - propertyList.addProperty(p,curGroup); - - p.name=TRANS("Work Dir"); - p.data= workingDir; - p.type=PROPERTY_TYPE_STRING; - p.helpText=TRANS("Directory to run the command in"); - p.key=KEY_WORKDIR; - propertyList.addProperty(p,curGroup); - - - if(cleanInput) - tmpStr="1"; - else - tmpStr="0"; - - p.name=TRANS("Cleanup input"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Erase input files when command completed"); - p.key=KEY_CLEANUPINPUT; - propertyList.addProperty(p,curGroup); - - if(alwaysCache) - tmpStr="1"; - else - tmpStr="0"; - - p.name=TRANS("Cache"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Assume program does not alter its output, unless inputs from 3Depict are altered"); - p.key=KEY_ALWAYSCACHE; - propertyList.addProperty(p,curGroup); - -} - -bool ExternalProgramFilter::setProperty( unsigned int key, - const std::string &value, bool &needUpdate) -{ - needUpdate=false; - switch(key) - { - case KEY_COMMAND: - { - if(commandLine!=value) - { - commandLine=value; - needUpdate=true; - clearCache(); - } - break; - } - case KEY_WORKDIR: - { - if(workingDir!=value) - { - //Check the directory exists - if(!wxDirExists(wxStr(value))) - return false; - - workingDir=value; - needUpdate=true; - clearCache(); - } - break; - } - case KEY_ALWAYSCACHE: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - if(stripped=="1") - alwaysCache=true; - else - { - alwaysCache=false; - - //If we need to generate a cache, do so - //otherwise, trash it - clearCache(); - } - - needUpdate=true; - break; - } - case KEY_CLEANUPINPUT: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - cleanInput=(stripped=="1"); - needUpdate=true; - break; - } - default: - ASSERT(false); - - } - - return true; -} - - -std::string ExternalProgramFilter::getErrString(unsigned int code) const -{ - - switch(code) - { - case COMMANDLINE_FAIL: - return std::string(TRANS("Error processing command line")); - case SETWORKDIR_FAIL: - return std::string(TRANS("Unable to set working directory")); - case WRITEPOS_FAIL: - return std::string(TRANS("Error saving posfile result for external program")); - case WRITEPLOT_FAIL: - return std::string(TRANS("Error saving plot result for externalprogram")); - case MAKEDIR_FAIL: - return std::string(TRANS("Error creating temporary directory")); - case PLOTCOLUMNS_FAIL: - return std::string(TRANS("Detected unusable number of columns in plot")); - case READPLOT_FAIL: - return std::string(TRANS("Unable to parse plot result from external program")); - case READPOS_FAIL: - return std::string(TRANS("Unable to load ions from external program")); - case SUBSTITUTE_FAIL: - return std::string(TRANS("Unable to perform commandline substitution")); - case COMMAND_FAIL: - return std::string(TRANS("Error executing external program")); - default: - //Currently the only error is aborting - return std::string("Bug: write me (externalProgramfilter)."); - } -} - -bool ExternalProgramFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth) << "" << endl; - break; - - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool ExternalProgramFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - - //Retrieve command - if(XMLHelpFwdToElem(nodePtr,"commandline")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); - if(!xmlString) - return false; - commandLine=(char *)xmlString; - xmlFree(xmlString); - - //Retrieve working dir - if(XMLHelpFwdToElem(nodePtr,"workingdir")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); - if(!xmlString) - return false; - workingDir=(char *)xmlString; - xmlFree(xmlString); - - - //get should cache - string tmpStr; - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"alwayscache","value")) - return false; - - if(tmpStr == "1") - alwaysCache=true; - else if(tmpStr== "0") - alwaysCache=false; - else - return false; - - //check readable - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"cleaninput","value")) - return false; - - if(tmpStr == "1") - cleanInput=true; - else if(tmpStr== "0") - cleanInput=false; - else - return false; - - return true; -} - -unsigned int ExternalProgramFilter::getRefreshBlockMask() const -{ - //Absolutely nothing can go through this filter. - return 0; -} - -unsigned int ExternalProgramFilter::getRefreshEmitMask() const -{ - //Can only generate ion streams and plot streams - return STREAM_TYPE_IONS | STREAM_TYPE_PLOT; -} - -unsigned int ExternalProgramFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS | STREAM_TYPE_PLOT; -} - -#ifdef DEBUG - -bool echoTest() -{ - ExternalProgramFilter* f = new ExternalProgramFilter; - f->setCaching(false); - - int errCode; -#if !defined(__WIN32__) && !defined(__WIN64__) - errCode=system("echo testing... > /dev/null"); -#else - errCode=system("echo testing... > NUL"); -#endif - if(errCode) - { - WARN(false,"Unable to perform echo test on this system -- echo missing?"); - return true; - } - - bool needUp; - string s; - - wxString tmpFilename; - tmpFilename=wxFileName::CreateTempFileName(wxT("")); - s = string(" echo test > ") + stlStr(tmpFilename); - f->setProperty(KEY_COMMAND,s,needUp); - - //Simulate some data to send to the filter - vector streamIn,streamOut; - ProgressData p; - f->refresh(streamIn,streamOut,p,dummyCallback); - - - s=stlStr(tmpFilename); - ifstream file(s.c_str()); - - TEST(file,"echo retrieval"); - - - wxRemoveFile(tmpFilename); - - delete f; - - return true; -} - -IonStreamData* createTestPosData(unsigned int numPts) -{ - IonStreamData* d= new IonStreamData; - - d->data.resize(numPts); - for(unsigned int ui=0;uidata[ui].setPos(ui,ui,ui); - d->data[ui].setMassToCharge(ui); - } - - return d; -} - -bool posTest() -{ - const unsigned int NUM_PTS=100; - IonStreamData *someData; - someData=createTestPosData(NUM_PTS); - - ExternalProgramFilter* f = new ExternalProgramFilter; - f->setCaching(false); - - bool needUp; - string s; - - wxString tmpFilename,tmpDir; - tmpDir=wxFileName::GetTempDir(); - - -#if defined(__WIN32__) || defined(__WIN64__) - tmpDir=tmpDir + wxT("\\3Depict\\"); - -#else - tmpDir=tmpDir + wxT("/3Depict/"); -#endif - wxMkdir(tmpDir); - - tmpFilename=wxFileName::CreateTempFileName(tmpDir+ wxT("unittest-")); - wxRemoveFile(tmpFilename); - tmpFilename+=wxT(".pos"); - s ="mv \%i " + stlStr(tmpFilename); - - ASSERT(tmpFilename.size()); - - f->setProperty(KEY_COMMAND,s,needUp); - f->setProperty(KEY_WORKDIR,stlStr(tmpDir),needUp); - //Simulate some data to send to the filter - vector streamIn,streamOut; - streamIn.push_back(someData); - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - - //Should have exactly one stream, which is an ion stream - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - - TEST(streamOut[0]->getNumBasicObjects() ==NUM_PTS,"Number of ions"); - const IonStreamData* out =(IonStreamData*) streamOut[0]; - - for(unsigned int ui=0;uidata.size();ui++) - { - TEST(out->data[ui].getPos() == someData->data[ui].getPos(),"position"); - TEST(out->data[ui].getMassToCharge() == - someData->data[ui].getMassToCharge(),"position"); - } - - - - wxRemoveFile(tmpFilename); - wxRmdir(tmpDir+wxT("inputData")); - wxRmdir(tmpDir); - - delete streamOut[0]; - - delete someData; - delete f; - - return true; -} - - -bool ExternalProgramFilter::runUnitTests() -{ - if(!echoTest()) - return false; - - if(!posTest()) - return false; - - return true; -} - - -#endif diff -Nru 3depict-0.0.12/src/filters/externalProgram.h 3depict-0.0.13/src/filters/externalProgram.h --- 3depict-0.0.12/src/filters/externalProgram.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/externalProgram.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -#ifndef EXTERNALPROGRAM_H -#define EXTERNALPROGRAM_H - -#include "../filter.h" -#include "../translation.h" -//!External program filter -class ExternalProgramFilter : public Filter -{ - - //!The command line strings; prior to expansion - std::string commandLine; - - //!Working directory for program - std::string workingDir; - - //!Always cache output from program - bool alwaysCache; - //!Erase generated input files for ext. program after running? - bool cleanInput; - - public: - //!As this launches external programs, this could be misused. - bool canBeHazardous() const {return true;} - - ExternalProgramFilter(); - virtual ~ExternalProgramFilter(){}; - - Filter *cloneUncached() const; - //!Returns cache size as a function fo input - virtual size_t numBytesForCache(size_t nObjects) const; - - //!Returns FILTER_TYPE_EXTERNALPROC - unsigned int getType() const { return FILTER_TYPE_EXTERNALPROC;}; - //update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - virtual std::string typeString() const { return std::string(TRANS("Ext. Program"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types possibly used during ::refresh - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - -#ifdef DEBUG - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/ionClip.cpp 3depict-0.0.13/src/filters/ionClip.cpp --- 3depict-0.0.12/src/filters/ionClip.cpp 2012-11-18 00:43:41.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionClip.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1628 +0,0 @@ -#include "ionClip.h" - -#include "../xmlHelper.h" - -#include "../translation.h" - -//!Error codes -enum -{ - CALLBACK_FAIL=1, - BAD_ALLOC, -}; - -//!Possible primitive types for ion clipping -enum -{ - PRIMITIVE_SPHERE, - PRIMITIVE_PLANE, - PRIMITIVE_CYLINDER, - PRIMITIVE_AAB, //Axis aligned box - - PRIMITIVE_END //Not actually a primitive, just end of enum -}; - -enum { - KEY_ORIGIN=1, - KEY_PRIMITIVE_TYPE, - KEY_RADIUS, - KEY_PRIMITIVE_SHOW, - KEY_PRIMITIVE_INVERTCLIP, - KEY_NORMAL, - KEY_CORNER, - KEY_AXIS_LOCKMAG, -}; - -//FIXME: make member functions. -bool inSphere(const Point3D &testPt, const Point3D &origin, float sqrRadius) -{ - return testPt.sqrDist(origin)< sqrRadius; -} - -bool inFrontPlane(const Point3D &testPt, const Point3D &origin, const Point3D &planeVec) -{ - return ((testPt-origin).dotProd(planeVec) > 0.0f); -} - - -const char *PRIMITIVE_NAMES[] = { - NTRANS("Sphere"), - NTRANS("Plane"), - NTRANS("Cylinder"), - NTRANS("Aligned box") - }; - - - -unsigned int primitiveID(const std::string &str) -{ - for(unsigned int ui=0;uiprimitiveType=primitiveType; - p->invertedClip=invertedClip; - p->showPrimitive=showPrimitive; - p->vectorParams.resize(vectorParams.size()); - p->scalarParams.resize(scalarParams.size()); - - std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin()); - std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin()); - - p->lockAxisMag = lockAxisMag; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - - return p; -} - -//!Get approx number of bytes for caching output -size_t IonClipFilter::numBytesForCache(size_t nObjects) const -{ - //Without full processing, we cannot tell, so provide upper estimate. - return nObjects*IONDATA_SIZE; -} - -//!update filter -unsigned int IonClipFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, - bool (*callback)(bool)) -{ - ASSERT(vectorParams.size() || scalarParams.size()); - //Clear selection devices, first deleting any we have - clearDevices(); - - if(showPrimitive) - { - //construct a new primitive, do not cache - DrawStreamData *drawData=new DrawStreamData; - drawData->parent =this; - switch(primitiveType) - { - case PRIMITIVE_SPHERE: - { - //Add drawable components - DrawSphere *dS = new DrawSphere; - dS->setOrigin(vectorParams[0]); - dS->setRadius(scalarParams[0]); - //FIXME: Alpha blending is all screwed up. May require more - //advanced drawing in scene. (front-back drawing). - //I have set alpha=1 for now. - dS->setColour(0.5,0.5,0.5,1.0); - dS->setLatSegments(40); - dS->setLongSegments(40); - dS->wantsLight=true; - drawData->drawables.push_back(dS); - - //Set up selection "device" for user interaction - //Note the order of s->addBinding is critical, - //as bindings are selected by first match. - //==== - //The object is selectable - dS->canSelect=true; - - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding b[3]; - - //Apple doesn't have right click, so we need - //to hook up an additional system for them. - //Don't use ifdefs, as this would be useful for - //normal laptops and the like. - b[0].setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_SPHERE_BIND_ORIGIN, - BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); - b[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b[0]); - - //Bind the drawable object to the properties we wish - //to be able to modify - b[1].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_RADIUS, - BINDING_SPHERE_RADIUS,dS->getRadius(),dS); - b[1].setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); - b[1].setFloatLimits(0,std::numeric_limits::max()); - s->addBinding(b[1]); - - b[2].setBinding(SELECT_BUTTON_RIGHT,0,DRAW_SPHERE_BIND_ORIGIN, - BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); - b[2].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b[2]); - - devices.push_back(s); - //===== - break; - } - case PRIMITIVE_PLANE: - { - //Origin + normal - ASSERT(vectorParams.size() == 2); - - //Add drawable components - DrawSphere *dS = new DrawSphere; - dS->setOrigin(vectorParams[0]); - dS->setRadius(drawScale/10); - dS->setColour(0.5,0.5,0.5,1.0); - dS->setLatSegments(40); - dS->setLongSegments(40); - dS->wantsLight=true; - drawData->drawables.push_back(dS); - - DrawVector *dV = new DrawVector; - dV->setOrigin(vectorParams[0]); - dV->setVector(vectorParams[1]*drawScale); - dV->wantsLight=true; - drawData->drawables.push_back(dV); - - //Set up selection "device" for user interaction - //==== - //The object is selectable - dS->canSelect=true; - dV->canSelect=true; - - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding b[2]; - //Bind the drawable object to the properties we wish - //to be able to modify - - //Bind orientation to vector left click - b[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_VECTOR_BIND_ORIENTATION, - BINDING_PLANE_DIRECTION, dV->getVector(),dV); - b[0].setInteractionMode(BIND_MODE_POINT3D_ROTATE); - b[0].setFloatLimits(0,std::numeric_limits::max()); - s->addBinding(b[0]); - - //Bind translation to sphere left click - b[1].setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN, - BINDING_PLANE_ORIGIN,dS->getOrigin(),dS); - b[1].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b[1]); - - - devices.push_back(s); - //===== - break; - } - case PRIMITIVE_CYLINDER: - { - //Origin + normal - ASSERT(vectorParams.size() == 2); - //Add drawable components - DrawCylinder *dC = new DrawCylinder; - dC->setOrigin(vectorParams[0]); - dC->setRadius(scalarParams[0]); - dC->setColour(0.5,0.5,0.5,1.0); - dC->setSlices(40); - dC->setLength(sqrt(vectorParams[1].sqrMag())); - dC->setDirection(vectorParams[1]); - dC->wantsLight=true; - drawData->drawables.push_back(dC); - - //Set up selection "device" for user interaction - //==== - //The object is selectable - dC->canSelect=true; - //Start and end radii must be the same (not a - //tapered cylinder) - dC->lockRadii(); - - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding b; - //Bind the drawable object to the properties we wish - //to be able to modify - - //Bind left + command button to move - b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_CYLINDER_BIND_ORIGIN, - BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); - b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b); - - //Bind left + shift to change orientation - b.setBinding(SELECT_BUTTON_LEFT,FLAG_SHIFT,DRAW_CYLINDER_BIND_DIRECTION, - BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); - - if(lockAxisMag) - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); - else - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); - s->addBinding(b); - - //Bind right button to changing position - b.setBinding(SELECT_BUTTON_RIGHT,0,DRAW_CYLINDER_BIND_ORIGIN, - BINDING_CYLINDER_ORIGIN,dC->getOrigin(),dC); - b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b); - - //Bind middle button to changing orientation - b.setBinding(SELECT_BUTTON_MIDDLE,0,DRAW_CYLINDER_BIND_DIRECTION, - BINDING_CYLINDER_DIRECTION,dC->getDirection(),dC); - if(lockAxisMag) - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE_LOCK); - else - b.setInteractionMode(BIND_MODE_POINT3D_ROTATE); - s->addBinding(b); - - //Bind left button to changing radius - b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_CYLINDER_BIND_RADIUS, - BINDING_CYLINDER_RADIUS,dC->getRadius(),dC); - b.setInteractionMode(BIND_MODE_FLOAT_TRANSLATE); - b.setFloatLimits(0,std::numeric_limits::max()); - s->addBinding(b); - - devices.push_back(s); - //===== - - break; - } - case PRIMITIVE_AAB: - { - //Centre + corner - ASSERT(vectorParams.size() == 2); - ASSERT(scalarParams.size() == 0); - - //Add drawable components - DrawRectPrism *dR = new DrawRectPrism; - dR->setAxisAligned(vectorParams[0]-vectorParams[1], - vectorParams[0] + vectorParams[1]); - dR->setColour(0.5,0.5,0.5,1.0); - dR->setDrawMode(DRAW_FLAT); - dR->wantsLight=true; - drawData->drawables.push_back(dR); - - - //Set up selection "device" for user interaction - //==== - //The object is selectable - dR->canSelect=true; - - SelectionDevice *s = new SelectionDevice(this); - SelectionBinding b[2]; - //Bind the drawable object to the properties we wish - //to be able to modify - - //Bind orientation to sphere left click - b[0].setBinding(SELECT_BUTTON_LEFT,0,DRAW_RECT_BIND_TRANSLATE, - BINDING_RECT_TRANSLATE, vectorParams[0],dR); - b[0].setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b[0]); - - - b[1].setBinding(SELECT_BUTTON_RIGHT,0,DRAW_RECT_BIND_CORNER_MOVE, - BINDING_RECT_CORNER_MOVE, vectorParams[1],dR); - b[1].setInteractionMode(BIND_MODE_POINT3D_SCALE); - s->addBinding(b[1]); - - devices.push_back(s); - //===== - break; - } - default: - ASSERT(false); - - } - - drawData->cached=0; - getOut.push_back(drawData); - } - - //use the cached copy of the data if we have it. - if(cacheOK) - { - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) - getOut.push_back(dataIn[ui]); - } - - return 0; - } - - - IonStreamData *d=0; - try - { - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - d=new IonStreamData; - d->parent=this; - switch(primitiveType) - { - case PRIMITIVE_SPHERE: - { - //origin + radius - ASSERT(vectorParams.size() == 1); - ASSERT(scalarParams.size() == 1); - ASSERT(scalarParams[0] >= 0.0f); - float sqrRad = scalarParams[0]*scalarParams[0]; - - unsigned int curProg=NUM_CALLBACK; - //Loop through each ion in the dataset - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - //Use XOR operand - if((inSphere(it->getPosRef(),vectorParams[0],sqrRad)) ^ (invertedClip)) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - delete d; - return CALLBACK_FAIL; - } - } - } - break; - } - case PRIMITIVE_PLANE: - { - //Origin + normal - ASSERT(vectorParams.size() == 2); - - - //Loop through each data set - unsigned int curProg=NUM_CALLBACK; - //Loop through each ion in the dataset - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - //Use XOR operand - if((inFrontPlane(it->getPosRef(),vectorParams[0],vectorParams[1])) ^ invertedClip) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - delete d; - return CALLBACK_FAIL; - } - } - } - break; - } - case PRIMITIVE_CYLINDER: - { - //Origin + axis - ASSERT(vectorParams.size() == 2); - //Radius perp. to axis - ASSERT(scalarParams.size() == 1); - - - unsigned int curProg=NUM_CALLBACK; - Point3f rotVec; - //Cross product desired drection with default - //direction to produce rotation vector - Point3D dir(0.0f,0.0f,1.0f),direction; - direction=vectorParams[1]; - direction.normalise(); - - float angle = dir.angle(direction); - - float halfLen=sqrt(vectorParams[1].sqrMag())/2.0f; - float sqrRad=scalarParams[0]*scalarParams[0]; - //Check that we actually need to rotate, to avoid numerical singularity - //when cylinder axis is too close to (or is) z-axis - if(angle > sqrt(std::numeric_limits::epsilon()) - && angle < M_PI - sqrt(std::numeric_limits::epsilon())) - { - dir = dir.crossProd(direction); - dir.normalise(); - - rotVec.fx=dir[0]; - rotVec.fy=dir[1]; - rotVec.fz=dir[2]; - - Quaternion q1; - - - //Generate the rotating quaternions - quat_get_rot_quat(&rotVec,-angle,&q1); - //pre-compute cylinder length and radius^2 - //Loop through each ion in the dataset - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - Point3f p; - //Translate to get position w respect to cylinder centre - Point3D ptmp; - ptmp=it->getPosRef()-vectorParams[0]; - p.fx=ptmp[0]; - p.fy=ptmp[1]; - p.fz=ptmp[2]; - //rotate ion position into cylindrical coordinates - quat_rot_apply_quat(&p,&q1); - - - //Keep ion if inside cylinder XOR inversion of the clippping (inside vs outside) - if((p.fz < halfLen && p.fz > -halfLen && p.fx*p.fx+p.fy*p.fy < sqrRad) ^ invertedClip) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - delete d; - return CALLBACK_FAIL; - } - } - } - - } - else - { - //Too close to the z-axis, rotation vector is unable to be stably computed, - //and we don't need to rotate anyway - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - Point3D ptmp; - ptmp=it->getPosRef()-vectorParams[0]; - - //Keep ion if inside cylinder XOR inversion of the clippping (inside vs outside) - if((ptmp[2] < halfLen && ptmp[2] > -halfLen && ptmp[0]*ptmp[0]+ptmp[1]*ptmp[1] < sqrRad) ^ invertedClip) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - delete d; - return CALLBACK_FAIL; - } - } - } - - } - break; - } - case PRIMITIVE_AAB: - { - //origin + corner - ASSERT(vectorParams.size() == 2); - ASSERT(scalarParams.size() == 0); - unsigned int curProg=NUM_CALLBACK; - - BoundCube c; - c.setBounds(vectorParams[0]+vectorParams[1],vectorParams[0]-vectorParams[1]); - //Loop through each ion in the dataset - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - //Use XOR operand - if((c.containsPt(it->getPosRef())) ^ (invertedClip)) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - delete d; - return CALLBACK_FAIL; - } - } - } - break; - } - - - default: - ASSERT(false); - return 1; - } - - - if(d->data.size()) - { - //Copy over other attributes - d->r = ((IonStreamData *)dataIn[ui])->r; - d->g = ((IonStreamData *)dataIn[ui])->g; - d->b =((IonStreamData *)dataIn[ui])->b; - d->a =((IonStreamData *)dataIn[ui])->a; - d->ionSize =((IonStreamData *)dataIn[ui])->ionSize; - d->representationType=((IonStreamData *)dataIn[ui])->representationType; - - //getOut is const, so shouldn't be modified - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - - getOut.push_back(d); - d=0; - } - else - delete d; - break; - } - default: - //Just copy across the ptr, if we are unfamiliar with this type - getOut.push_back(dataIn[ui]); - break; - } - - } - } - catch(std::bad_alloc) - { - if(d) - delete d; - return BAD_ALLOC; - } - return 0; - -} - -//!Get the properties of the filter, in key-value form. First vector is for each output. -void IonClipFilter::getProperties(FilterPropGroup &propertyList) const -{ - ASSERT(vectorParams.size() || scalarParams.size()); - - FilterProperty p; - - size_t curGroup=0; - //Let the user know what the valid values for Primitive type - string tmpStr; - - vector > choices; - - choices.push_back(make_pair((unsigned int)PRIMITIVE_SPHERE , - primitiveStringFromID(PRIMITIVE_SPHERE))); - choices.push_back(make_pair((unsigned int)PRIMITIVE_PLANE , - primitiveStringFromID(PRIMITIVE_PLANE))); - choices.push_back(make_pair((unsigned int)PRIMITIVE_CYLINDER , - primitiveStringFromID(PRIMITIVE_CYLINDER))); - choices.push_back(make_pair((unsigned int)PRIMITIVE_AAB, - primitiveStringFromID(PRIMITIVE_AAB))); - - tmpStr= choiceString(choices,primitiveType); - p.name=TRANS("Primitive"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_CHOICE; - p.helpText=TRANS("Shape of clipping object"); - p.key=KEY_PRIMITIVE_TYPE; - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,showPrimitive); - p.key=KEY_PRIMITIVE_SHOW; - p.name=TRANS("Show Primitive"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Display the 3D interaction object"); - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,invertedClip); - p.key=KEY_PRIMITIVE_INVERTCLIP; - p.name=TRANS("Invert Clip"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Switch between retaining points inside (false) and outside (true) of primitive"); - propertyList.addProperty(p,curGroup); - - switch(primitiveType) - { - case PRIMITIVE_SPHERE: - { - ASSERT(vectorParams.size() == 1); - ASSERT(scalarParams.size() == 1); - stream_cast(tmpStr,vectorParams[0]); - p.key=KEY_ORIGIN; - p.name=TRANS("Origin"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Position for centre of sphere"); - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,scalarParams[0]); - p.key=KEY_RADIUS; - p.name=TRANS("Radius"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Radius of sphere"); - propertyList.addProperty(p,curGroup); - - break; - } - case PRIMITIVE_PLANE: - { - ASSERT(vectorParams.size() == 2); - ASSERT(scalarParams.size() == 0); - stream_cast(tmpStr,vectorParams[0]); - p.key=KEY_ORIGIN; - p.name=TRANS("Origin"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Position that plane passes through"); - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,vectorParams[1]); - p.key=KEY_NORMAL; - p.name=TRANS("Plane Normal"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Perpendicular direction for plane"); - propertyList.addProperty(p,curGroup); - - break; - } - case PRIMITIVE_CYLINDER: - { - ASSERT(vectorParams.size() == 2); - ASSERT(scalarParams.size() == 1); - stream_cast(tmpStr,vectorParams[0]); - p.key=KEY_ORIGIN; - p.name=TRANS("Origin"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Centre of cylinder"); - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,vectorParams[1]); - p.key=KEY_NORMAL; - p.name=TRANS("Axis"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Positive vector for cylinder"); - propertyList.addProperty(p,curGroup); - - if(lockAxisMag) - tmpStr="1"; - else - tmpStr="0"; - p.key=KEY_AXIS_LOCKMAG; - p.name=TRANS("Lock Axis Mag."); - p.data=tmpStr; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Prevent changing length of cylinder during 3D interaction"); - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,scalarParams[0]); - p.key=KEY_RADIUS; - p.name=TRANS("Radius"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Radius of cylinder"); - propertyList.addProperty(p,curGroup); - break; - } - case PRIMITIVE_AAB: - { - ASSERT(vectorParams.size() == 2); - ASSERT(scalarParams.size() == 0); - stream_cast(tmpStr,vectorParams[0]); - p.key=KEY_ORIGIN; - p.name=TRANS("Origin"); - p.data= tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Centre of axis aligned box"); - propertyList.addProperty(p,curGroup); - - stream_cast(tmpStr,vectorParams[1]); - p.key=KEY_CORNER; - p.name=TRANS("Corner offset"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_POINT3D; - p.helpText=TRANS("Vector to corner of box"); - propertyList.addProperty(p,curGroup); - break; - } - default: - ASSERT(false); - } - -} - -//!Set the properties for the nth filter. Returns true if prop set OK -bool IonClipFilter::setProperty(unsigned int key, - const std::string &value, bool &needUpdate) -{ - - needUpdate=false; - switch(key) - { - case KEY_PRIMITIVE_TYPE: - { - unsigned int newPrimitive; - - newPrimitive=primitiveID(value); - if(newPrimitive == (unsigned int)-1) - return false; - - primitiveType=newPrimitive; - - switch(primitiveType) - { - //If we are switchign between essentially - //similar data types, don't reset the data. - //Otherwise, wipe it and try again - case PRIMITIVE_SPHERE: - if(vectorParams.size() !=1) - { - vectorParams.clear(); - vectorParams.push_back(Point3D(0,0,0)); - } - if(scalarParams.size()!=1) - { - scalarParams.clear(); - scalarParams.push_back(10.0f); - } - break; - case PRIMITIVE_PLANE: - if(vectorParams.size() >2) - { - vectorParams.clear(); - vectorParams.push_back(Point3D(0,0,0)); - vectorParams.push_back(Point3D(0,1,0)); - } - else if (vectorParams.size() ==2) - { - vectorParams[1].normalise(); - } - else if(vectorParams.size() ==1) - { - vectorParams.push_back(Point3D(0,1,0)); - } - - scalarParams.clear(); - break; - case PRIMITIVE_CYLINDER: - if(vectorParams.size()>2) - { - vectorParams.resize(2); - } - else if(vectorParams.size() ==1) - { - vectorParams.push_back(Point3D(0,1,0)); - } - else if(!vectorParams.size()) - { - vectorParams.push_back(Point3D(0,0,0)); - vectorParams.push_back(Point3D(0,1,0)); - - } - - if(scalarParams.size()!=1) - { - scalarParams.clear(); - scalarParams.push_back(10.0f); - } - break; - case PRIMITIVE_AAB: - - if(vectorParams.size() >2) - { - vectorParams.clear(); - vectorParams.push_back(Point3D(0,0,0)); - vectorParams.push_back(Point3D(1,1,1)); - } - else if(vectorParams.size() ==1) - { - vectorParams.push_back(Point3D(1,1,1)); - } - //check to see if any components of the - //corner offset are zero; we disallow a - //zero, 1 or 2 dimensional box - for(unsigned int ui=0;ui<3;ui++) - { - vectorParams[1][ui]=fabs(vectorParams[1][ui]); - if(vectorParams[1][ui] ::epsilon()) - vectorParams[1][ui] = 1; - } - scalarParams.clear(); - break; - - default: - ASSERT(false); - } - - clearCache(); - needUpdate=true; - return true; - } - case KEY_ORIGIN: - { - ASSERT(vectorParams.size() >= 1); - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(vectorParams[0] == newPt )) - { - vectorParams[0] = newPt; - needUpdate=true; - clearCache(); - } - - return true; - } - case KEY_CORNER: - { - ASSERT(vectorParams.size() >= 2); - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(!(vectorParams[1] == newPt )) - { - vectorParams[1] = newPt; - needUpdate=true; - clearCache(); - } - - return true; - } - case KEY_RADIUS: - { - ASSERT(scalarParams.size() >=1); - float newRad; - if(stream_cast(newRad,value)) - return false; - - if(scalarParams[0] != newRad ) - { - scalarParams[0] = newRad; - needUpdate=true; - clearCache(); - } - return true; - } - case KEY_NORMAL: - { - ASSERT(vectorParams.size() >=2); - Point3D newPt; - if(!parsePointStr(value,newPt)) - return false; - - if(primitiveType == PRIMITIVE_CYLINDER) - { - if(lockAxisMag && - newPt.sqrMag() > sqrt(std::numeric_limits::epsilon())) - { - newPt.normalise(); - newPt*=sqrt(vectorParams[1].sqrMag()); - } - } - if(!(vectorParams[1] == newPt )) - { - vectorParams[1] = newPt; - needUpdate=true; - clearCache(); - } - return true; - } - case KEY_PRIMITIVE_SHOW: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - if(stripped=="1") - showPrimitive=true; - else - showPrimitive=false; - - needUpdate=true; - - break; - } - case KEY_PRIMITIVE_INVERTCLIP: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=invertedClip; - if(stripped=="1") - invertedClip=true; - else - invertedClip=false; - - //if the result is different, the - //cache should be invalidated - if(lastVal!=invertedClip) - { - needUpdate=true; - clearCache(); - } - - break; - } - - case KEY_AXIS_LOCKMAG: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - if(stripped=="1") - lockAxisMag=true; - else - lockAxisMag=false; - - needUpdate=true; - - break; - } - default: - ASSERT(false); - return false; - } - - ASSERT(vectorParams.size() || scalarParams.size()); - - return true; -} - -//!Get the human readable error string associated with a particular error code during refresh(...) -std::string IonClipFilter::getErrString(unsigned int code) const -{ - switch(code) - { - case BAD_ALLOC: - return std::string("Insufficient mem. for Ionclip"); - case CALLBACK_FAIL: - return std::string("Ionclip Aborted"); - } - ASSERT(false); -} - -bool IonClipFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<"<< trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0; ui" << endl; - } - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0; ui" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool IonClipFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - std::string tmpStr; - //Retrieve primitive type - //==== - if(!XMLGetNextElemAttrib(nodePtr,primitiveType,"primitivetype","value")) - return false; - if(primitiveType >= PRIMITIVE_END) - return false; - //==== - - //Retrieve clip inversion - //==== - // - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"invertedclip","value")) - return false; - if(tmpStr == "0") - invertedClip=false; - else if(tmpStr == "1") - invertedClip=true; - else - return false; - //==== - - //Retrieve primitive visiblity - //==== - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"showprimitive","value")) - return false; - if(tmpStr == "0") - showPrimitive=false; - else if(tmpStr == "1") - showPrimitive=true; - else - return false; - //==== - - //Retrieve axis lock mode - //==== - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"lockaxismag","value")) - return false; - if(tmpStr == "0") - lockAxisMag=false; - else if(tmpStr == "1") - lockAxisMag=true; - else - return false; - //==== - - //Retreive vector parameters - //=== - if(XMLHelpFwdToElem(nodePtr,"vectorparams")) - return false; - xmlNodePtr tmpNode=nodePtr; - - nodePtr=nodePtr->xmlChildrenNode; - - vectorParams.clear(); - while(!XMLHelpFwdToElem(nodePtr,"point3d")) - { - float x,y,z; - //--Get X value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(x,tmpStr)) - return false; - - //--Get Z value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(y,tmpStr)) - return false; - - //--Get Y value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(z,tmpStr)) - return false; - - vectorParams.push_back(Point3D(x,y,z)); - } - //=== - - nodePtr=tmpNode; - //Retreive scalar parameters - //=== - if(XMLHelpFwdToElem(nodePtr,"scalarparams")) - return false; - - tmpNode=nodePtr; - nodePtr=nodePtr->xmlChildrenNode; - - scalarParams.clear(); - while(!XMLHelpFwdToElem(nodePtr,"scalar")) - { - float v; - //Get value - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(v,tmpStr)) - return false; - scalarParams.push_back(v); - } - //=== - - //Check the scalar params match the selected primitive - switch(primitiveType) - { - case PRIMITIVE_SPHERE: - if(vectorParams.size() != 1 || scalarParams.size() !=1) - return false; - break; - case PRIMITIVE_PLANE: - case PRIMITIVE_AAB: - if(vectorParams.size() != 2 || scalarParams.size() !=0) - return false; - break; - case PRIMITIVE_CYLINDER: - if(vectorParams.size() != 2 || scalarParams.size() !=1) - return false; - break; - - default: - ASSERT(false); - return false; - } - - ASSERT(vectorParams.size() || scalarParams.size()); - return true; -} - -unsigned int IonClipFilter::getRefreshBlockMask() const -{ - return STREAM_TYPE_IONS ; -} - -unsigned int IonClipFilter::getRefreshEmitMask() const -{ - if(showPrimitive) - return STREAM_TYPE_IONS | STREAM_TYPE_DRAW; - else - return STREAM_TYPE_IONS ; -} - -unsigned int IonClipFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS; -} - -void IonClipFilter::setPropFromBinding(const SelectionBinding &b) -{ - switch(b.getID()) - { - case BINDING_CYLINDER_RADIUS: - case BINDING_SPHERE_RADIUS: - b.getValue(scalarParams[0]); - break; - case BINDING_CYLINDER_ORIGIN: - case BINDING_SPHERE_ORIGIN: - case BINDING_PLANE_ORIGIN: - case BINDING_RECT_TRANSLATE: - b.getValue(vectorParams[0]); - break; - case BINDING_CYLINDER_DIRECTION: - b.getValue(vectorParams[1]); - break; - case BINDING_PLANE_DIRECTION: - { - Point3D p; - b.getValue(p); - p.normalise(); - - vectorParams[1] =p; - break; - } - case BINDING_RECT_CORNER_MOVE: - { - //Prevent the corner offset from acquiring a vector - //with a negative component. - Point3D p; - b.getValue(p); - for(unsigned int ui=0;ui<3;ui++) - { - p[ui]=fabs(p[ui]); - //Should be positive - if(p[ui] ::epsilon()) - return; - } - - vectorParams[1]=p; - break; - } - default: - ASSERT(false); - } - clearCache(); -} - - -#ifdef DEBUG - -//Create a synthetic dataset of points -// returned pointer *must* be deleted by caller. -//Span must have 3 elements, and for best results sould be co-prime with -// one another; eg all prime numbers -IonStreamData *synthData(const unsigned int span[],unsigned int numPts); - - -//Test the spherical clipping primitive -bool sphereTest(); -//Test the plane primitive -bool planeTest(); -//Test the cylinder primitive -bool cylinderTest(const Point3D &pAxis, const unsigned int *span, float testRadius); - -//Test the axis-aligned box primitve -bool rectTest(); - - -bool IonClipFilter::runUnitTests() -{ - if(!sphereTest()) - return false; - - if(!planeTest()) - return false; - - unsigned int span[]={ - 5, 7, 9 - }; - const float TEST_RADIUS=3.0f; - Point3D axis; - axis=Point3D(1,2,3); - if(!cylinderTest(axis,span,TEST_RADIUS)) - return false; - - axis=Point3D(0,1,0); - if(!cylinderTest(axis,span,TEST_RADIUS)) - return false; - - if(!rectTest()) - return false; - - return true; -} - -bool sphereTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - unsigned int span[]={ - 5, 7, 9 - }; - const unsigned int NUM_PTS=10000; - IonStreamData *d=synthData(span,NUM_PTS); - streamIn.push_back(d); - - IonClipFilter *f=new IonClipFilter; - f->setCaching(false); - - bool needUp; std::string s; - f->setProperty(KEY_PRIMITIVE_TYPE, - primitiveStringFromID(PRIMITIVE_SPHERE),needUp); - - Point3D pOrigin((float)span[0]/2,(float)span[1]/2,(float)span[2]/2); - stream_cast(s,pOrigin); - f->setProperty(KEY_ORIGIN,s,needUp); - - const float TEST_RADIUS=1.2f; - stream_cast(s,TEST_RADIUS); - f->setProperty(KEY_RADIUS,s,needUp); - - f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp); - - //Do the refresh - ProgressData p; - f->refresh(streamIn,streamOut,p,dummyCallback); - - delete f; - delete d; - - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - - TEST(streamOut[0]->getNumBasicObjects() > 0, "clipped point count"); - - const IonStreamData *dOut=(IonStreamData*)streamOut[0]; - - for(unsigned int ui=0;uidata.size();ui++) - { - Point3D p; - p=dOut->data[ui].getPos(); - - TEST(sqrt(p.sqrDist(pOrigin)) - <= TEST_RADIUS,"Sphere containment"); - } - - delete dOut; - return true; -} - -bool planeTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - unsigned int span[]={ - 5, 7, 9 - }; - const unsigned int NUM_PTS=10000; - IonStreamData *d=synthData(span,NUM_PTS); - streamIn.push_back(d); - - IonClipFilter *f=new IonClipFilter; - f->setCaching(false); - - bool needUp; std::string s; - f->setProperty(KEY_PRIMITIVE_TYPE, - primitiveStringFromID(PRIMITIVE_PLANE),needUp); - - Point3D pOrigin((float)span[0]/2,(float)span[1]/2,(float)span[2]/2); - stream_cast(s,pOrigin); - f->setProperty(KEY_ORIGIN,s,needUp); - - Point3D pPlaneDir(1,2,3); - stream_cast(s,pPlaneDir); - f->setProperty(KEY_NORMAL,s,needUp); - - f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp); - - //Do the refresh - ProgressData p; - f->refresh(streamIn,streamOut,p,dummyCallback); - - delete f; - delete d; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - - const IonStreamData *dOut=(IonStreamData*)streamOut[0]; - - for(unsigned int ui=0;uidata.size();ui++) - { - Point3D p; - p=dOut->data[ui].getPos(); - - p=p-pOrigin; - TEST(p.dotProd(pPlaneDir) >=0, "Plane direction"); - } - - delete dOut; - return true; -} - -bool cylinderTest(const Point3D &pAxis, const unsigned int *span, float testRadius) -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - const unsigned int NUM_PTS=10000; - IonStreamData *d=synthData(span,NUM_PTS); - streamIn.push_back(d); - - IonClipFilter*f=new IonClipFilter; - f->setCaching(false); - - bool needUp; std::string s; - f->setProperty(KEY_PRIMITIVE_TYPE, - primitiveStringFromID(PRIMITIVE_CYLINDER),needUp); - - Point3D pOrigin((float)span[0]/2,(float)span[1]/2,(float)span[2]/2); - stream_cast(s,pOrigin); - f->setProperty(KEY_ORIGIN,s,needUp); - - stream_cast(s,pAxis); - f->setProperty(KEY_NORMAL,s,needUp); - - stream_cast(s,testRadius); - f->setProperty(KEY_RADIUS,s,needUp); - - f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp); - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - delete f; - delete d; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - - const IonStreamData *dOut=(IonStreamData*)streamOut[0]; - - DrawCylinder *dC = new DrawCylinder; - dC->setRadius(testRadius); - dC->setOrigin(pOrigin); - float len = sqrt(pAxis.sqrMag()); - - Point3D axisNormal(pAxis); - axisNormal.normalise(); - - dC->setDirection(pAxis); - dC->setLength(len); - - BoundCube b; - dC->getBoundingBox(b); - - delete dC; - - b.expand(sqrt(std::numeric_limits::epsilon())); - for(unsigned int ui=0;uidata.size();ui++) - { - Point3D p; - p=dOut->data[ui].getPos(); - //FIXME: This fails, but appears to work, depending upon the - // tests I put it through??? - TEST(b.containsPt(p), "Bounding box containment"); - } - - delete dOut; - - return true; -} - -bool rectTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - unsigned int span[]={ - 5, 7, 9 - }; - const unsigned int NUM_PTS=10000; - IonStreamData *d=synthData(span,NUM_PTS); - streamIn.push_back(d); - - IonClipFilter*f=new IonClipFilter; - f->setCaching(false); - - bool needUp; std::string s; - f->setProperty(KEY_PRIMITIVE_TYPE, - primitiveStringFromID(PRIMITIVE_AAB),needUp); - f->setProperty(KEY_PRIMITIVE_SHOW,"0",needUp); - f->setProperty(KEY_PRIMITIVE_INVERTCLIP,"0",needUp); - - Point3D pOrigin(span[0],span[1],span[2]); - pOrigin*=0.25f; - stream_cast(s,pOrigin); - f->setProperty(KEY_ORIGIN,s,needUp); - - Point3D pCorner(span[0],span[1],span[2]); - pCorner*=0.25f; - stream_cast(s,pCorner); - f->setProperty(KEY_CORNER,s,needUp); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - delete f; - delete d; - - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - const IonStreamData *dOut=(IonStreamData*)streamOut[0]; - - BoundCube b; - b.setBounds(pOrigin-pCorner,pOrigin+pCorner); - for(unsigned int ui=0;uidata.size();ui++) - { - Point3D p; - p=dOut->data[ui].getPos(); - - TEST(b.containsPt(p), "Bounding box containment"); - } - - - delete dOut; - return true; -} - - -IonStreamData *synthData(const unsigned int span[], unsigned int numPts) -{ - IonStreamData *d = new IonStreamData; - - for(unsigned int ui=0;uidata.push_back(h); - } - - return d; -} - - - -#endif diff -Nru 3depict-0.0.12/src/filters/ionClip.h 3depict-0.0.13/src/filters/ionClip.h --- 3depict-0.0.12/src/filters/ionClip.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionClip.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -#ifndef IONCLIP_H -#define IONCLIP_H - -#include "../filter.h" -#include "../translation.h" - -//!Ion spatial clipping filter -class IonClipFilter : public Filter -{ - protected: - //!Number explaining basic primitive type - /* Possible Modes: - * Planar clip (origin + normal) - * spherical clip (origin + radius) - * Cylindrical clip (origin + axis + length) - * Axis aligned box (origin + corner) - */ - unsigned int primitiveType; - - //!Whether to reverse the clip. True means that the interior is excluded - bool invertedClip; - //!Whether to show the primitive or not - bool showPrimitive; - //!Vector paramaters for different primitives - vector vectorParams; - //!Scalar paramaters for different primitives - vector scalarParams; - //Lock the primitive axis during for cylinder? - bool lockAxisMag; - - public: - IonClipFilter(); - - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - - //!Returns FILTER_TYPE_IONCLIP - unsigned int getType() const { return FILTER_TYPE_IONCLIP;}; - - //!Get approx number of bytes for caching output - size_t numBytesForCache(size_t nObjects) const; - - //!update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - //!Return human readable name for filter - virtual std::string typeString() const { return std::string(TRANS("Clipping"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter. Returns true if prop set OK - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, unsigned int depth=0) const; - - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be possibly used during ::refresh - unsigned int getRefreshUseMask() const; - - - //!Set internal property value using a selection binding - void setPropFromBinding(const SelectionBinding &b); - -#ifdef DEBUG - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/ionColour.cpp 3depict-0.0.13/src/filters/ionColour.cpp --- 3depict-0.0.12/src/filters/ionColour.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionColour.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,630 +0,0 @@ -#include "ionColour.h" - -#include "../xmlHelper.h" - -#include "../colourmap.h" - -#include "../translation.h" - -const unsigned int MAX_NUM_COLOURS=256; -enum -{ - KEY_IONCOLOURFILTER_COLOURMAP, - KEY_IONCOLOURFILTER_MAPSTART, - KEY_IONCOLOURFILTER_MAPEND, - KEY_IONCOLOURFILTER_NCOLOURS, - KEY_IONCOLOURFILTER_SHOWBAR, -}; - -enum -{ - IONCOLOUR_ABORT_ERR -}; - -IonColourFilter::IonColourFilter() : colourMap(0), nColours(MAX_NUM_COLOURS), - showColourBar(true) -{ - mapBounds[0] = 0.0f; - mapBounds[1] = 100.0f; - - cacheOK=false; - cache=true; //By default, we should cache, but decision is made higher up - -} - -Filter *IonColourFilter::cloneUncached() const -{ - IonColourFilter *p=new IonColourFilter(); - p->colourMap = colourMap; - p->mapBounds[0]=mapBounds[0]; - p->mapBounds[1]=mapBounds[1]; - p->nColours =nColours; - p->showColourBar =showColourBar; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -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 r,g,b; - r.resize(nColours); - g.resize(nColours); - b.resize(nColours); - - for (unsigned int ui=0;uisetColourVec(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 &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - //use the cached copy if we have it. - if(cacheOK) - { - ASSERT(filterOutputs.size()); - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) - getOut.push_back(dataIn[ui]); - } - - for(unsigned int ui=0;uiparent=this; - d->drawables.push_back(makeColourBar()); - d->cached=0; - getOut.push_back(d); - } - return 0; - } - - - ASSERT(nColours >0 && nColours<=MAX_NUM_COLOURS); - IonStreamData *d[nColours]; - unsigned char rgb[3]; //RGB array - //Build the colourmap values, each as a unique filter output - for(unsigned int ui=0;uiparent=this; - 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]); - - d[ui]->r=rgb[0]/255.0f; - d[ui]->g=rgb[1]/255.0f; - d[ui]->b=rgb[2]/255.0f; - d[ui]->a=1.0f; - } - - //Try to maintain ion size if possible - bool haveIonSize,sameSize; // have we set the ionSize? - float ionSize; - haveIonSize=false; - sameSize=true; - - //Did we find any ions in this pass? - bool foundIons=false; - unsigned int totalSize=numElements(dataIn); - unsigned int curProg=NUM_CALLBACK; - size_t n=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - foundIons=true; - - //Check for ion size consistency - if(haveIonSize) - { - sameSize &= (fabs(ionSize-((const IonStreamData *)dataIn[ui])->ionSize) - < std::numeric_limits::epsilon()); - } - else - { - ionSize=((const IonStreamData *)dataIn[ui])->ionSize; - haveIonSize=true; - } - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - unsigned int colour; - - float tmp; - tmp= (it->getMassToCharge()-mapBounds[0])/(mapBounds[1]-mapBounds[0]); - tmp = std::max(0.0f,tmp); - tmp = std::min(tmp,1.0f); - - colour=(unsigned int)(tmp*(float)(nColours-1)); - d[colour]->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - for(unsigned int ui=0;uidrawables.push_back(makeColourBar()); - d->parent=this; - d->cached=0; - getOut.push_back(d); - } - - - //If all the ions are the same size, then propagate - if(haveIonSize && sameSize) - { - for(unsigned int ui=0;uiionSize=ionSize; - } - //merge the results as needed - if(cache) - { - for(unsigned int ui=0;uidata.size()) - d[ui]->cached=1; - else - d[ui]->cached=0; - if(d[ui]->data.size()) - filterOutputs.push_back(d[ui]); - } - cacheOK=filterOutputs.size(); - } - else - { - for(unsigned int ui=0;uicached=0; - } - cacheOK=false; - } - - //push the colours onto the output. cached or not (their status is set above). - for(unsigned int ui=0;uidata.size()) - getOut.push_back(d[ui]); - else - delete d[ui]; - } - - return 0; -} - - -void IonColourFilter::getProperties(FilterPropGroup &propertyList) const -{ - - FilterProperty p; - string tmpStr; - vector > choices; - - size_t curGroup=0; - - for(unsigned int ui=0;ui=NUM_COLOURMAPS || tmpMap ==colourMap) - return false; - - clearCache(); - needUpdate=true; - colourMap=tmpMap; - break; - } - case KEY_IONCOLOURFILTER_MAPSTART: - { - float tmpBound; - stream_cast(tmpBound,value); - if(tmpBound >=mapBounds[1]) - return false; - - clearCache(); - needUpdate=true; - mapBounds[0]=tmpBound; - break; - } - case KEY_IONCOLOURFILTER_MAPEND: - { - float tmpBound; - stream_cast(tmpBound,value); - if(tmpBound <=mapBounds[0]) - return false; - - clearCache(); - needUpdate=true; - mapBounds[1]=tmpBound; - break; - } - case KEY_IONCOLOURFILTER_NCOLOURS: - { - unsigned int numColours; - if(stream_cast(numColours,value)) - return false; - - clearCache(); - needUpdate=true; - //enforce 1->MAX_NUM_COLOURS range - nColours=std::min(numColours,MAX_NUM_COLOURS); - if(!nColours) - nColours=1; - break; - } - case KEY_IONCOLOURFILTER_SHOWBAR: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=showColourBar; - showColourBar=(stripped == "1"); - - //Only need update if changed - if(lastVal!=showColourBar) - needUpdate=true; - break; - } - - default: - ASSERT(false); - } - return true; -} - - -std::string IonColourFilter::getErrString(unsigned int code) const -{ - //Currently the only error is aborting - return std::string(TRANS("Aborted")); -} - - -bool IonColourFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - string str; - if(showColourBar) - str="1"; - else - str="0"; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool IonColourFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - std::string tmpStr; - //Retrieve colourmap - //==== - if(XMLHelpFwdToElem(nodePtr,"colourmap")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(colourMap,tmpStr)) - return false; - - if(colourMap>= NUM_COLOURMAPS) - return false; - xmlFree(xmlString); - //==== - - //Retrieve Extrema - //=== - float tmpMin,tmpMax; - if(XMLHelpFwdToElem(nodePtr,"extrema")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"min"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(tmpMin,tmpStr)) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"max"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(tmpMax,tmpStr)) - return false; - - xmlFree(xmlString); - - if(tmpMin > tmpMax) - return false; - - mapBounds[0]=tmpMin; - mapBounds[1]=tmpMax; - - //=== - - //Retrieve num colours - //==== - if(XMLHelpFwdToElem(nodePtr,"ncolours")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(nColours,tmpStr)) - return false; - - xmlFree(xmlString); - //==== - - //Retrieve num colours - //==== - if(XMLHelpFwdToElem(nodePtr,"showcolourbar")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - //convert from string to digit - if(stream_cast(showColourBar,tmpStr)) - return false; - - xmlFree(xmlString); - //==== - return true; -} - -unsigned int IonColourFilter::getRefreshBlockMask() const -{ - //Anything but ions can go through this filter. - return STREAM_TYPE_IONS; -} - -unsigned int IonColourFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_DRAW | STREAM_TYPE_IONS; -} - -unsigned int IonColourFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS; -} -#ifdef DEBUG - -IonStreamData *sythIonCountData(unsigned int numPts, float mStart, float mEnd) -{ - IonStreamData *d = new IonStreamData; - d->data.resize(numPts); - for(unsigned int ui=0; uidata[ui] =h; - } - - return d; -} - - -bool ionCountTest() -{ - const int NUM_PTS=1000; - vector streamIn,streamOut; - IonStreamData *d=sythIonCountData(NUM_PTS,0,100); - streamIn.push_back(d); - - - IonColourFilter *f = new IonColourFilter; - f->setCaching(false); - - bool needUpdate; - f->setProperty(KEY_IONCOLOURFILTER_NCOLOURS,"100",needUpdate); - f->setProperty(KEY_IONCOLOURFILTER_MAPSTART,"0",needUpdate); - f->setProperty(KEY_IONCOLOURFILTER_MAPEND,"100",needUpdate); - f->setProperty(KEY_IONCOLOURFILTER_SHOWBAR,"0",needUpdate); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - delete f; - delete d; - - TEST(streamOut.size() == 99,"stream count"); - - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS,"stream type"); - } - - for(unsigned int ui=0;ui &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - //!return string naming the human readable type of this class - virtual std::string typeString() const { return std::string(TRANS("Spectral Colour"));} - - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty( unsigned int key, const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be used during ::refresh - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - -#ifdef DEBUG - bool runUnitTests() ; -#endif -}; -#endif diff -Nru 3depict-0.0.12/src/filters/ionDownsample.cpp 3depict-0.0.13/src/filters/ionDownsample.cpp --- 3depict-0.0.12/src/filters/ionDownsample.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionDownsample.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,931 +0,0 @@ -#include "../APTClasses.h" -#include "../xmlHelper.h" - -#include "../translation.h" - -#include "ionDownsample.h" - - -//!Downsampling filter -enum -{ - IONDOWNSAMPLE_ABORT_ERR=1, - IONDOWNSAMPLE_BAD_ALLOC, -}; - - -// == Ion Downsampling filter == - -IonDownsampleFilter::IonDownsampleFilter() -{ - rng.initTimer(); - fixedNumOut=true; - fraction=0.1f; - maxAfterFilter=5000; - rsdIncoming=0; - perSpecies=false; - - cacheOK=false; - cache=true; //By default, we should cache, but decision is made higher up - -} - -void IonDownsampleFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - const RangeStreamData *c=0; - //Determine if we have an incoming range - for (size_t i = 0; i < dataIn.size(); i++) - { - if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE) - { - c=(const RangeStreamData *)dataIn[i]; - - dataOut.push_back(dataIn[i]); - break; - } - } - - //we no longer (or never did) have any incoming ranges. Not much to do - if(!c) - { - //delete the old incoming range pointer - if(rsdIncoming) - delete rsdIncoming; - rsdIncoming=0; - - //Well, don't use per-species info anymore - perSpecies=false; - } - else - { - - - //If we didn't have a previously incoming rsd, then make one up! - // - we can't use a reference, as the rangestreams are technically transient, - // so we have to copy. - if(!rsdIncoming) - { - rsdIncoming = new RangeStreamData; - *rsdIncoming=*c; - - if(ionFractions.size() != c->rangeFile->getNumIons()) - { - //set up some defaults; seeded from normal - ionFractions.resize(c->rangeFile->getNumIons(),fraction); - ionLimits.resize(c->rangeFile->getNumIons(),maxAfterFilter); - } - } - else - { - - //OK, so we have a range incoming already (from last time) - //-- the question is, is it the same one we had before ? - // - //Do a pointer comparison (its a hack, yes, but it should work) - if(rsdIncoming->rangeFile != c->rangeFile) - { - //hmm, it is different. well, trash the old incoming rng - delete rsdIncoming; - - rsdIncoming = new RangeStreamData; - *rsdIncoming=*c; - - ionFractions.resize(c->rangeFile->getNumIons(),fraction); - ionLimits.resize(c->rangeFile->getNumIons(),maxAfterFilter); - } - else if(ionFractions.size() !=c->rangeFile->getNumIons()) - { - //well its the same range, but somehow the number of ions - //have changed. Could be range was reloaded. - ionFractions.resize(rsdIncoming->rangeFile->getNumIons(),fraction); - ionLimits.resize(rsdIncoming->rangeFile->getNumIons(),maxAfterFilter); - } - - //Ensure what is enabled and is disabled is up-to-date - for(unsigned int ui=0;uienabledRanges.size();ui++) - rsdIncoming->enabledRanges[ui] = c->enabledRanges[ui]; - for(unsigned int ui=0;uienabledIons.size();ui++) - rsdIncoming->enabledIons[ui] = c->enabledIons[ui]; - - } - - } - - - ASSERT(ionLimits.size() == ionFractions.size()); -} - -Filter *IonDownsampleFilter::cloneUncached() const -{ - IonDownsampleFilter *p=new IonDownsampleFilter(); - p->rng = rng; - p->maxAfterFilter=maxAfterFilter; - p->fraction=fraction; - p->perSpecies=perSpecies; - p->rsdIncoming=rsdIncoming; - - p->ionFractions.resize(ionFractions.size()); - std::copy(ionFractions.begin(),ionFractions.end(),p->ionFractions.begin()); - p->ionLimits.resize(ionLimits.size()); - std::copy(ionLimits.begin(),ionLimits.end(),p->ionLimits.begin()); - - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - p->fixedNumOut=fixedNumOut; - return p; -} - -size_t IonDownsampleFilter::numBytesForCache(size_t nObjects) const -{ - if(fixedNumOut) - { - if(nObjects > maxAfterFilter) - return maxAfterFilter*IONDATA_SIZE; - else - return nObjects*IONDATA_SIZE; - } - else - { - return (size_t)((float)(nObjects*IONDATA_SIZE)*fraction); - } -} - -unsigned int IonDownsampleFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - //use the cached copy if we have it. - if(cacheOK) - { - for(size_t ui=0;uigetStreamType() != STREAM_TYPE_IONS) - getOut.push_back(dataIn[ui]); - } - for(size_t ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - if(!totalSize) - continue; - - IonStreamData *d; - d=new IonStreamData; - d->parent=this; - try - { - if(fixedNumOut) - { - float frac; - frac = (float)(((const IonStreamData*)dataIn[ui])->data.size())/(float)totalSize; - - randomSelect(d->data,((const IonStreamData *)dataIn[ui])->data, - rng,maxAfterFilter*frac,progress.filterProgress,callback,strongRandom); - - - } - else - { - - unsigned int curProg=NUM_CALLBACK; - size_t n=0; - //Reserve 90% of storage needed. - //highly likely with even modest numbers of ions - //that this will be exceeeded - d->data.reserve(fraction*0.9*totalSize); - - ASSERT(dataIn[ui]->getStreamType() == STREAM_TYPE_IONS); - - for(vector::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin(); - it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it) - { - if(rng.genUniformDev() < fraction) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - curProg=NUM_CALLBACK; - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return IONDOWNSAMPLE_ABORT_ERR; - } - } - } - } - } - catch(std::bad_alloc) - { - delete d; - return IONDOWNSAMPLE_BAD_ALLOC; - } - - //skip ion output sets wth no ions in them - if(d->data.empty()) - { - delete d; - continue; - } - - //Copy over other attributes - d->r = ((IonStreamData *)dataIn[ui])->r; - d->g = ((IonStreamData *)dataIn[ui])->g; - d->b =((IonStreamData *)dataIn[ui])->b; - d->a =((IonStreamData *)dataIn[ui])->a; - d->ionSize =((IonStreamData *)dataIn[ui])->ionSize; - d->representationType=((IonStreamData *)dataIn[ui])->representationType; - d->valueType=((IonStreamData *)dataIn[ui])->valueType; - - //getOut is const, so shouldn't be modified - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - - getOut.push_back(d); - break; - } - - default: - getOut.push_back(dataIn[ui]); - break; - } - - } - } - else - { - ASSERT(rsdIncoming); - const IonStreamData *input; - - //Construct two vectors. One with the ion IDs for each input - //ion stream. the other with the total number of ions in the input - //for each ion type - vector numIons,ionIDVec; - numIons.resize(rsdIncoming->rangeFile->getNumIons(),0); - - for(unsigned int uj=0;ujgetStreamType() == STREAM_TYPE_IONS) - { - input=(const IonStreamData*)dataIn[uj]; - if(input->data.size()) - { - unsigned int ionID; - ionID=rsdIncoming->rangeFile->getIonID( - input->data[0].getMassToCharge()); - - if(ionID != (unsigned int)-1) - numIons[ionID]+=input->data.size(); - - ionIDVec.push_back(ionID); - } - } - } - - size_t n=0; - unsigned int idPos=0; - for(size_t ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - input=(const IonStreamData*)dataIn[ui]; - - //Don't process ionstreams that are empty - if(input->data.empty()) - continue; - - //FIXME: Allow processing of unranged data - //Don't process streams that are not ranged, as we cannot get their desired fractions - //at this time - if(ionIDVec[idPos]==(unsigned int)-1) - continue; - - IonStreamData *d; - d=new IonStreamData; - d->parent=this; - try - { - if(fixedNumOut) - { - //if we are building the fixed number for output, - //then compute the relative fraction for this ion set - float frac; - frac = (float)(input->data.size())/(float)(numIons[ionIDVec[idPos]]); - - //The total number of ions is the specified value for this ionID, multiplied by - //this stream's fraction of the total incoming data - randomSelect(d->data,input->data, rng,frac*ionLimits[ionIDVec[idPos]], - progress.filterProgress,callback,strongRandom); - } - else - { - //Use the direct fractions as entered in by user. - - unsigned int curProg=NUM_CALLBACK; - - float thisFraction = ionFractions[ionIDVec[idPos]]; - - //Reserve 90% of storage needed. - //highly likely (poisson) with even modest numbers of ions - //that this will be exceeeded, and thus we won't over-allocate - d->data.reserve(thisFraction*0.9*numIons[ionIDVec[idPos]]); - - if(thisFraction) - { - for(vector::const_iterator it=input->data.begin(); - it!=input->data.end(); ++it) - { - if(rng.genUniformDev() < thisFraction) - d->data.push_back(*it); - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= - (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return IONDOWNSAMPLE_ABORT_ERR; - } - } - } - - } - } - } - catch(std::bad_alloc) - { - delete d; - return IONDOWNSAMPLE_BAD_ALLOC; - } - - - if(d->data.size()) - { - //Copy over other attributes - d->r = input->r; - d->g = input->g; - d->b =input->b; - d->a =input->a; - d->ionSize =input->ionSize; - d->representationType=input->representationType; - d->valueType=input->valueType; - - - //getOut is const, so shouldn't be modified - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - - getOut.push_back(d); - } - else - delete d; - //next ion - idPos++; - - break; - } - - default: - getOut.push_back(dataIn[ui]); - break; - } - - } - - - } - - return 0; -} - - -void IonDownsampleFilter::getProperties(FilterPropGroup &propertyList) const -{ - - FilterProperty p; - size_t curGroup=0; - - string tmpStr; - stream_cast(tmpStr,fixedNumOut); - p.data=tmpStr; - p.name=TRANS("By Count"); - p.key=KEY_IONDOWNSAMPLE_FIXEDOUT; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Sample up to a fixed number of ions"); - propertyList.addProperty(p,curGroup); - - if(rsdIncoming) - { - stream_cast(tmpStr,perSpecies); - p.name=TRANS("Per Species"); - p.data=tmpStr; - p.key=KEY_IONDOWNSAMPLE_PERSPECIES; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Use species specific (from ranging) sampling values"); - propertyList.addProperty(p,curGroup); - } - - - propertyList.setGroupTitle(curGroup,TRANS("Sampling rates")); - curGroup++; - if(rsdIncoming && perSpecies) - { - unsigned int typeVal; - if(fixedNumOut) - typeVal=PROPERTY_TYPE_INTEGER; - else - typeVal=PROPERTY_TYPE_REAL; - - //create a single line for each - for(unsigned int ui=0; uienabledIons.size(); ui++) - { - if(rsdIncoming->enabledIons[ui]) - { - if(fixedNumOut) - stream_cast(tmpStr,ionLimits[ui]); - else - stream_cast(tmpStr,ionFractions[ui]); - - p.name=rsdIncoming->rangeFile->getName(ui); - p.data=tmpStr; - p.type=typeVal; - p.helpText=TRANS("Sampling value for species"); - p.key=KEY_IONDOWNSAMPLE_DYNAMIC+ui; - propertyList.addProperty(p,curGroup); - } - } - } - else - { - if(fixedNumOut) - { - stream_cast(tmpStr,maxAfterFilter); - p.key=KEY_IONDOWNSAMPLE_COUNT; - p.name=TRANS("Output Count"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_INTEGER; - p.helpText=TRANS("Sample up to this value of points"); - } - else - { - stream_cast(tmpStr,fraction); - p.name=TRANS("Out Fraction"); - p.data=tmpStr; - p.key=KEY_IONDOWNSAMPLE_FRACTION; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Sample this fraction of points"); - - } - propertyList.addProperty(p,curGroup); - } -} - -bool IonDownsampleFilter::setProperty( unsigned int key, - const std::string &value, bool &needUpdate) -{ - needUpdate=false; - switch(key) - { - case KEY_IONDOWNSAMPLE_FIXEDOUT: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=fixedNumOut; - fixedNumOut=(stripped=="1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=fixedNumOut) - { - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_IONDOWNSAMPLE_FRACTION: - { - float newFraction; - if(stream_cast(newFraction,value)) - return false; - - if(newFraction < 0.0f || newFraction > 1.0f) - return false; - - //In the case of fixed number output, - //our cache is invalidated - if(!fixedNumOut) - { - needUpdate=true; - clearCache(); - } - - fraction=newFraction; - - - break; - } - case KEY_IONDOWNSAMPLE_COUNT: - { - size_t count; - - if(stream_cast(count,value)) - return false; - - maxAfterFilter=count; - //In the case of fixed number output, - //our cache is invalidated - if(fixedNumOut) - { - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_IONDOWNSAMPLE_PERSPECIES: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=perSpecies; - - perSpecies=(stripped=="1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=perSpecies) - { - needUpdate=true; - clearCache(); - } - - break; - } - default: - { - ASSERT(rsdIncoming); - ASSERT(key >=KEY_IONDOWNSAMPLE_DYNAMIC); - ASSERT(key < KEY_IONDOWNSAMPLE_DYNAMIC+ionLimits.size()); - ASSERT(ionLimits.size() == ionFractions.size()); - - unsigned int offset; - offset=key-KEY_IONDOWNSAMPLE_DYNAMIC; - - //TODO: Disable this test - - // offset >=ionLimits.size() did happen, but should not have. - // Can't reproduce bug - something to do with wrong filter being given selected properties in UI - ASSERT( offset < ionLimits.size()); - if(offset >= ionLimits.size()) - return false; - - //Dynamically generated list of downsamples - if(fixedNumOut) - { - //Fixed count - size_t v; - if(stream_cast(v,value)) - return false; - ionLimits[offset]=v; - } - else - { - //Fixed fraction - float v; - if(stream_cast(v,value)) - return false; - - if(v < 0.0f || v> 1.0f) - return false; - - ionFractions[offset]=v; - } - - needUpdate=true; - clearCache(); - break; - } - - } - return true; -} - - -std::string IonDownsampleFilter::getErrString(unsigned int code) const -{ - switch(code) - { - case IONDOWNSAMPLE_ABORT_ERR: - return std::string(TRANS("Downsample Aborted")); - case IONDOWNSAMPLE_BAD_ALLOC: - return std::string(TRANS("Insuffient memory for downsample")); - } - - return std::string("BUG! Should not see this (IonDownsample)"); -} - -bool IonDownsampleFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0;ui" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0;ui" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool IonDownsampleFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - using std::string; - string tmpStr; - - xmlChar *xmlString; - //Retrieve user string - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - - //Retrieve number out (yes/no) mode - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixednumout","value")) - return false; - - if(tmpStr == "1") - fixedNumOut=true; - else if(tmpStr== "0") - fixedNumOut=false; - else - return false; - //=== - - //Retrieve Fraction - //=== - if(!XMLGetNextElemAttrib(nodePtr,fraction,"fraction","value")) - return false; - //disallow negative or values gt 1. - if(fraction < 0.0f || fraction > 1.0f) - return false; - //=== - - - //Retrieve "perspecies" attrib - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"perspecies","value")) - return false; - - if(tmpStr == "1") - perSpecies=true; - else if(tmpStr== "0") - perSpecies=false; - else - return false; - - xmlNodePtr lastNode; - lastNode=nodePtr; - //Retrieve the ion per-species fractions - if(XMLHelpFwdToElem(nodePtr,"fractions")) - return false; - - nodePtr=nodePtr->xmlChildrenNode; - - //Populate the ion fraction vector - float fracThis; - while(XMLGetNextElemAttrib(nodePtr,fracThis,"scalar","value")) - ionFractions.push_back(fracThis); - - - nodePtr=lastNode; - - //Retrieve the ion per-species fractions - if(XMLHelpFwdToElem(nodePtr,"limits")) - return false; - - nodePtr=nodePtr->xmlChildrenNode; - size_t limitThis; - while(XMLGetNextElemAttrib(nodePtr,limitThis,"scalar","value")) - ionLimits.push_back(limitThis); - - if(ionLimits.size()!=ionFractions.size()) - return false; - - return true; -} - - -unsigned int IonDownsampleFilter::getRefreshBlockMask() const -{ - return STREAM_TYPE_IONS ; -} - -unsigned int IonDownsampleFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_IONS; -} - -unsigned int IonDownsampleFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_RANGE | STREAM_TYPE_IONS; -} -//---------- - - -//Unit testing for this class -///----- -#ifdef DEBUG - -//Create a synthetic dataset of points -// returned pointer *must* be deleted. Span must have 3 elements, -// and for best results sould be co-prime with one another; eg all prime numbers -IonStreamData *synthDataPts(unsigned int span[],unsigned int numPts); - -//Test for fixed number of output ions -bool fixedSampleTest(); - -//Test for variable number of output ions -bool variableSampleTest(); - -//Unit tests -bool IonDownsampleFilter::runUnitTests() -{ - if(!fixedSampleTest()) - return false; - - if(!variableSampleTest()) - return false; - - return true; -} - -bool fixedSampleTest() -{ - //Simulate some data to send to the filter - vector streamIn,streamOut; - IonStreamData *d= new IonStreamData; - - const unsigned int NUM_PTS=10000; - for(unsigned int ui=0;uidata.push_back(h); - } - - - streamIn.push_back(d); - //Set up the filter itself - IonDownsampleFilter *f=new IonDownsampleFilter; - f->setCaching(false); - - bool needUp; - string s; - unsigned int numOutput=NUM_PTS/10; - - f->setProperty(KEY_IONDOWNSAMPLE_FIXEDOUT,"1",needUp); - stream_cast(s,numOutput); - f->setProperty(KEY_IONDOWNSAMPLE_COUNT,s,needUp); - - //Do the refresh - ProgressData p; - f->refresh(streamIn,streamOut,p,dummyCallback); - - delete f; - delete d; - - //Pass some tests - TEST(streamOut.size() == 1, "Stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "stream type"); - TEST(streamOut[0]->getNumBasicObjects() == numOutput, "output ions (basicobject)"); - TEST( ((IonStreamData*)streamOut[0])->data.size() == numOutput, "output ions (direct)") - - delete streamOut[0]; - - return true; -} - -bool variableSampleTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - unsigned int span[]={ - 5, 7, 9 - }; - const unsigned int NUM_PTS=10000; - IonStreamData *d=synthDataPts(span,NUM_PTS); - - streamIn.push_back(d); - IonDownsampleFilter *f=new IonDownsampleFilter; - f->setCaching(false); - - bool needUp; - f->setProperty(KEY_IONDOWNSAMPLE_FIXEDOUT,"0",needUp); - f->setProperty(KEY_IONDOWNSAMPLE_FRACTION,"0.1",needUp); - - //Do the refresh - ProgressData p; - TEST(!(f->refresh(streamIn,streamOut,p,dummyCallback)),"refresh error code"); - - delete f; - delete d; - - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - - //It is HIGHLY improbable that it will be <1/10th of the requested number - TEST(streamOut[0]->getNumBasicObjects() > 0.01*NUM_PTS - && streamOut[0]->getNumBasicObjects() <= NUM_PTS,"ion fraction"); - - delete streamOut[0]; - - - return true; -} - -IonStreamData *synthDataPts(unsigned int span[], unsigned int numPts) -{ - IonStreamData *d = new IonStreamData; - - for(unsigned int ui=0;uidata.push_back(h); - } - - return d; -} - -#endif -///----- - diff -Nru 3depict-0.0.12/src/filters/ionDownsample.h 3depict-0.0.13/src/filters/ionDownsample.h --- 3depict-0.0.12/src/filters/ionDownsample.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionDownsample.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -#ifndef IONDOWNSAMPLE_H -#define IONDOWNSAMPLE_H - -#include "../filter.h" -#include "../translation.h" - -enum -{ - KEY_IONDOWNSAMPLE_FRACTION=1, - KEY_IONDOWNSAMPLE_FIXEDOUT, - KEY_IONDOWNSAMPLE_COUNT, - KEY_IONDOWNSAMPLE_PERSPECIES, - KEY_IONDOWNSAMPLE_ENABLE, - //Dynamic area for this filter class. May validly use any index after this value - KEY_IONDOWNSAMPLE_DYNAMIC, -}; - -//!Random picker filter -class IonDownsampleFilter : public Filter -{ - private: - RandNumGen rng; - //When usng fixed number output, maximum to allow out. - size_t maxAfterFilter; - //!Allow only a fixed number at output, alternate is random fraction (binomial dist). - bool fixedNumOut; - //Fraction to output - float fraction; - - - //!Should we use a per-species split or not? - bool perSpecies; - //This is filter's enabled ranges. 0 if we don't have a range - RangeStreamData *rsdIncoming; - - //!Fractions to output for species specific - std::vector ionFractions; - std::vector ionLimits; - public: - IonDownsampleFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - //!Returns FILTER_TYPE_IONDOWNSAMPLE - unsigned int getType() const { return FILTER_TYPE_IONDOWNSAMPLE;}; - //!Initialise filter prior to tree propagation - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - - //!Set mode, fixed num out/approximate out (fraction) - void setControlledOut(bool controlled) {fixedNumOut=controlled;}; - - //!Set the number of ions to generate after the filtering (when using count based fitlering). - void setFilterCount(size_t nMax) { maxAfterFilter=nMax;}; - - //!Get (approx) number of bytes required for cache - virtual size_t numBytesForCache(size_t nObjects) const; - //update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - //!return string naming the human readable type of this class - virtual std::string typeString() const { return std::string(TRANS("Ion Sampler"));} - - - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty( unsigned int key, const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be possibly used during ::refresh - unsigned int getRefreshUseMask() const; - -#ifdef DEBUG - //Fire off the unit tests for this class. returns false if *any* test fails - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/ionInfo.cpp 3depict-0.0.13/src/filters/ionInfo.cpp --- 3depict-0.0.12/src/filters/ionInfo.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionInfo.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1181 +0,0 @@ -#include "ionInfo.h" - -#include "../xmlHelper.h" -#include "../translation.h" -#include "../voxels.h" - -//QHull library -#ifdef __POWERPC__ - #pragma push_macro("__POWERPC__") - #define __POWERPC__ 1 -#endif -extern "C" -{ - #include -} -#ifdef __POWERPC__ - #pragma pop_macro("__POWERPC__") -#endif - -//TODO: Work out where the payoff for this is -//grab size when doing convex hull calculations -const unsigned int HULL_GRAB_SIZE=4096; - - - -enum -{ - VOLUME_MODE_RECTILINEAR=0, - VOLUME_MODE_CONVEX, - VOLUME_MODE_END -}; - -const char *volumeModeString[] = { - NTRANS("Rectilinear"), - NTRANS("Convex hull") - }; - -enum -{ - ERR_NO_MEM, - ERR_USER_ABORT, - ERR_BAD_QHULL -}; - -unsigned int doHull(unsigned int bufferSize, double *buffer, - vector &resHull, Point3D &midPoint) -{ - const int dim=3; - //Now compute the new hull - //Generate the convex hull - //(result is stored in qh's globals :( ) - //note that the input is "joggled" to - //ensure simplicial facet generation - - qh_new_qhull( dim, - bufferSize, - buffer, - false, - (char *)"qhull QJ", //Joggle the output, such that only simplical facets are generated - NULL, - NULL); - - unsigned int numPoints=0; - //count points - //-- - //OKay, whilst this may look like invalid syntax, - //qh is actually a macro from qhull - //that creates qh. or qh-> as needed - vertexT *vertex = qh vertex_list; - while(vertex != qh vertex_tail) - { - vertex = vertex->next; - numPoints++; - } - //-- - - //store points in vector - //-- - vertex= qh vertex_list; - try - { - resHull.resize(numPoints); - } - catch(std::bad_alloc) - { - free(buffer); - return ERR_NO_MEM; - } - //-- - - //Compute mean point - //-- - int curPt=0; - midPoint=Point3D(0,0,0); - while(vertex != qh vertex_tail) - { - resHull[curPt]=Point3D(vertex->point[0], - vertex->point[1], - vertex->point[2]); - midPoint+=resHull[curPt]; - curPt++; - vertex = vertex->next; - } - midPoint*=1.0f/(float)numPoints; - //-- - - return 0; -} - -bool getRectilinearBounds(const std::vector &dataIn, BoundCube &bound, - unsigned int *progress, unsigned int totalSize,bool (*callback)(bool)) -{ - bound.setInvalid(); - - vector overflow; - - size_t n=0; - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - - const IonStreamData *ions; - ions = ( const IonStreamData *)dataIn[ui]; - n+=ions->data.size(); - BoundCube c; - if(ions->data.size() >1) - { - ions = (const IonStreamData*)dataIn[ui]; - c=getIonDataLimits(ions->data); - - if(c.isValid()) - { - if(bound.isValid()) - bound.expand(c); - else - bound=c; - } - } - else - { - //Do we have single ions in their own - //data structure? if so, they don't have a bound - //on their own, but may have one collectively. - if(ions->data.size()) - overflow.push_back(ions->data[0].getPos()); - } - - *progress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - return false; - } - } - - - //Handle any single ions - if(overflow.size() > 1) - { - BoundCube c; - c.setBounds(overflow); - if(bound.isValid()) - bound.expand(c); - else - bound=c; - } - else if(bound.isValid() && overflow.size() == 1) - bound.expand(overflow[0]); - - return true; -} - -IonInfoFilter::IonInfoFilter() : wantIonCounts(true), wantNormalise(false), - range(0), wantVolume(false), volumeAlgorithm(VOLUME_MODE_RECTILINEAR), - cubeSideLen(1.0f) -{ - cacheOK=false; - cache=true; //By default, we should cache, but decision is made higher up -} - -void IonInfoFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - const RangeStreamData *c=0; - //Determine if we have an incoming range - for (size_t i = 0; i < dataIn.size(); i++) - { - if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE) - { - c=(const RangeStreamData *)dataIn[i]; - - break; - } - } - - //we no longer (or never did) have any incoming ranges. Not much to do - if(!c) - { - //delete the old incoming range pointer - if(range) - delete range; - range=0; - } - else - { - //If we didn't have an incoming rsd, then make one up! - if(!range) - { - range= new RangeStreamData; - *range=*c; - } - else - { - - //OK, so we have a range incoming already (from last time) - //-- the question is, is it the same one we had before ? - //Do a pointer comparison (its a hack, yes, but it should work) - if(range->rangeFile != c->rangeFile) - { - //hmm, it is different. well, trash the old incoming rng - delete range; - - range = new RangeStreamData; - *range=*c; - } - - } - - } - -} - -//TODO: Refactor -- this is a clone of countPoints from voxelise.cpp -//This is not a member of voxels.h, as the voxels do not have any concept of the IonHit -int countPoints(Voxels &v, const std::vector &points, - bool noWrap,bool (*callback)(bool)) -{ - - size_t x,y,z; - size_t binCount[3]; - v.getSize(binCount[0],binCount[1],binCount[2]); - - unsigned int downSample=MAX_CALLBACK; - for (size_t ui=0; ui::max()) - v.setData(x,y,z,value+1); - } - } - return 0; -} - -Filter *IonInfoFilter::cloneUncached() const -{ - IonInfoFilter *p=new IonInfoFilter(); - - p->wantIonCounts=wantIonCounts; - p->wantVolume=wantVolume; - p->wantNormalise=wantNormalise; - p->cubeSideLen=cubeSideLen; - p->volumeAlgorithm=volumeAlgorithm; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - p->wantVolume=wantVolume; - p->volumeAlgorithm=volumeAlgorithm; - return p; -} - -unsigned int IonInfoFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - - //Count the number of ions input - size_t numTotalPoints = numElements(dataIn,STREAM_TYPE_IONS); - size_t numRanged=0; - - - if(!numTotalPoints) - { - consoleOutput.push_back((TRANS("No ions"))); - return 0; - } - - //Compute ion counts/composition as needed - if(wantIonCounts) - { - std::string str; - //Count the number of ions - if(range) - { - vector numIons; - ASSERT(range); - - const RangeFile *r=range->rangeFile; - numIons.resize(r->getNumIons()+1,0); - - //count ions per-species. Add a bin on the end for unranged - for(size_t ui=0;uigetStreamType() != STREAM_TYPE_IONS) - continue; - - const IonStreamData *i; - i = (const IonStreamData *)dataIn[ui]; - - for(size_t uj=0;ujdata.size(); uj++) - { - unsigned int id; - id = r->getIonID(i->data[uj].getMassToCharge()); - if(id != (unsigned int) -1) - numIons[id]++; - else - numIons[numIons.size()-1]++; - } - } - - stream_cast(str,numTotalPoints); - str=std::string(TRANS("--Counts--") ); - consoleOutput.push_back(str); - - size_t totalRanged; - if(wantNormalise) - { - totalRanged=0; - //sum all ions *except* the unranged. - for(size_t ui=0;uigetName(ui)) + std::string("\t") + str; - else - { - //output unranged count - str=std::string(TRANS("Unranged")) + std::string("\t") + str; - } - - consoleOutput.push_back(str); - } - str=std::string("----------"); - consoleOutput.push_back(str); - - - for(size_t ui=0;ui0) - consoleOutput.push_back(string(TRANS("Convex Volume (len^3): ")) + s); - else - consoleOutput.push_back(string(TRANS("Unable to compute volume"))); - - - break; - } - default: - ASSERT(false); - - } - -#ifdef DEBUG - lastVolume=computedVol; -#endif - } - - - //"Pairwise events" - where we perform an action if both - //These - if(wantIonCounts && wantVolume) - { - if(computedVol > sqrt(std::numeric_limits::epsilon())) - { - float density; - std::string s; - - if(range) - { - density=(float)numRanged/computedVol; - stream_cast(s,density); - consoleOutput.push_back(string(TRANS("Ranged Density (pts/vol):")) + s ); - } - - density=(float)numTotalPoints/computedVol; - stream_cast(s,density); - consoleOutput.push_back(string(TRANS("Total Density (pts/vol):")) + s ); - - - } - } - - return 0; -} - -size_t IonInfoFilter::numBytesForCache(size_t nObjects) const -{ - return 0; -} - - -void IonInfoFilter::getProperties(FilterPropGroup &propertyList) const -{ - string str; - FilterProperty p; - size_t curGroup=0; - - vector > choices; - string tmpStr; - - stream_cast(str,wantIonCounts); - p.key=IONINFO_KEY_TOTALS; - if(range) - { - p.name=TRANS("Compositions"); - p.helpText=TRANS("Display compositional data for points in console"); - } - else - { - p.name=TRANS("Counts"); - p.helpText=TRANS("Display count data for points in console"); - } - p.data= str; - p.type=PROPERTY_TYPE_BOOL; - propertyList.addProperty(p,curGroup); - - - if(wantIonCounts && range) - { - stream_cast(str,wantNormalise); - p.name=TRANS("Normalise"); - p.data=str; - p.key=IONINFO_KEY_NORMALISE; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Normalise count data"); - - propertyList.addProperty(p,curGroup); - } - - curGroup++; - - stream_cast(str,wantVolume); - p.key=IONINFO_KEY_VOLUME; - p.name=TRANS("Volume"); - p.data= str; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Compute volume for point data"); - propertyList.addProperty(p,curGroup); - - if(wantVolume) - { - for(unsigned int ui=0;ui &data, - float &volume,bool (*callback)(bool))const -{ - //OK, so heres the go. partition the input data - //into GRAB_SIZE lots before processing hull. - - volume=0; - double *buffer; - double *tmp; - //Use malloc so we can re-alloc - buffer =(double*) malloc(HULL_GRAB_SIZE*3*sizeof(double)); - - if(!buffer) - return ERR_NO_MEM; - - size_t bufferSize=0; - - vector curHull; - - //Do the convex hull in steps for two reasons - // 1) qhull chokes on large data - // 2) we need to run the callback every now and again, so we have to - // work in batches. - Point3D midPoint; - float maxSqrDist=-1; - bool doneHull=false; - for(size_t ui=0;uigetStreamType() != STREAM_TYPE_IONS) - continue; - - const IonStreamData* ions=(const IonStreamData*)data[ui]; - - for(size_t uj=0; ujdata.size(); uj++) - { - if(curHull.size()) - { - //Do contained-in-sphere check - if(midPoint.sqrDist(ions->data[uj].getPos()) < maxSqrDist) - continue; - } - //Copy point data into hull buffer - buffer[3*bufferSize]=ions->data[uj].getPos()[0]; - buffer[3*bufferSize+1]=ions->data[uj].getPos()[1]; - buffer[3*bufferSize+2]=ions->data[uj].getPos()[2]; - bufferSize++; - - - if(bufferSize == HULL_GRAB_SIZE) - { - bufferSize+=curHull.size(); - tmp=(double*)realloc(buffer, - 3*bufferSize*sizeof(double)); - if(!tmp) - { - free(buffer); - return ERR_NO_MEM; - } - - buffer=tmp; - //Copy in the old hull - for(size_t uk=0;uk::max(); - for(size_t ui=0;ui 3) - { - //Re-allocate the buffer to determine the last hull size - tmp=(double*)realloc(buffer, - 3*(bufferSize+curHull.size())*sizeof(double)); - if(!tmp) - { - free(buffer); - return ERR_NO_MEM; - } - buffer=tmp; - - #pragma omp parallel for - for(unsigned int ui=0;uisimplicial); - - ui=0; - vertex = (vertexT *)curFac->vertices->e[ui].p; - while(vertex) - { //copy the vertex info into the pt array - (ptArray[ui])[0] = vertex->point[0]; - (ptArray[ui])[1] = vertex->point[1]; - (ptArray[ui])[2] = vertex->point[2]; - - //aggregate pyramidal points - pyramidCentroid += ptArray[ui]; - - //increment before updating vertex - //to allow checking for NULL termination - ui++; - vertex = (vertexT *)curFac->vertices->e[ui].p; - - } - - //note that this counter has been post incremented. - ASSERT(ui ==3); - volume+=pyramidVol(ptArray,midPoint); - - - curFac=curFac->next; - } - - - //Free the convex hull mem - qh_freeqhull(!qh_ALL); - int curlong, totlong; - qh_memfreeshort(&curlong, &totlong); - free(buffer); - - return 0; -} - -bool IonInfoFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool IonInfoFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - using std::string; - string tmpStr; - - xmlChar *xmlString; - //Retrieve user string - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - - //-- - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantioncounts","value")) - return false; - if(tmpStr == "1") - wantIonCounts=true; - else if(tmpStr == "0") - wantIonCounts=false; - else - return false; - //--= - - //-- - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantnormalise","value")) - return false; - if(tmpStr == "1") - wantNormalise=true; - else if(tmpStr == "0") - wantNormalise=false; - else - return false; - //--= - - - //-- - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantvolume","value")) - return false; - if(tmpStr == "1") - wantVolume=true; - else if(tmpStr == "0") - wantVolume=false; - else - return false; - //--= - - //-- - unsigned int tmpInt; - if(!XMLGetNextElemAttrib(nodePtr,tmpInt,"volumealgorithm","value")) - return false; - - if(tmpInt >=VOLUME_MODE_END) - return false; - volumeAlgorithm=tmpInt; - //--= - - //-- - float tmpFloat; - if(!XMLGetNextElemAttrib(nodePtr,tmpFloat,"cubesidelen","value")) - return false; - - if(tmpFloat <= 0.0f) - return false; - cubeSideLen=tmpFloat; - //--= - - - return true; -} - -unsigned int IonInfoFilter::getRefreshBlockMask() const -{ - return STREAMTYPE_MASK_ALL; -} - -unsigned int IonInfoFilter::getRefreshEmitMask() const -{ - return 0; -} - -unsigned int IonInfoFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; -} - -#ifdef DEBUG - -void makeBox(float boxSize,IonStreamData *d) -{ - d->data.clear(); - for(unsigned int ui=0;ui<8;ui++) - { - IonHit h; - float x,y,z; - - x= (float)(ui &1)*boxSize; - y= (float)((ui &2) >> 1)*boxSize; - z= (float)((ui &4) >> 2)*boxSize; - - h.setPos(Point3D(x,y,z)); - h.setMassToCharge(1); - d->data.push_back(h); - } -} -void makeSphereOutline(float radius, float angularStep, - IonStreamData *d) -{ - d->clear(); - ASSERT(angularStep > 0.0f); - unsigned int numAngles=(unsigned int)( 180.0f/angularStep); - - for( unsigned int ui=0; ui0.5 - longit = (float)((int)ui-(int)(numAngles/2))/(float)(numAngles); - //longitude test - longit*=180.0f; - - for( unsigned int uj=0; uj1 - latit = (float)((int)uj)/(float)(numAngles); - latit*=180.0f; - - float x,y,z; - x=radius*cos(longit)*sin(latit); - y=radius*sin(longit)*sin(latit); - z=radius*cos(latit); - - IonHit h; - h.setPos(Point3D(x,y,z)); - h.setMassToCharge(1); - d->data.push_back(h); - } - } -} - -bool volumeBoxTest() -{ - //Construct a few boxes, then test each of their volumes - IonStreamData *d=new IonStreamData(); - - const float SOMEBOX=7.0f; - makeBox(7.0,d); - - - //Construct the filter, and then set up the options we need - IonInfoFilter *f = new IonInfoFilter; - f->setCaching(false); - - //activate volume measurement - bool needUp; - f->setProperty(IONINFO_KEY_VOLUME,"1",needUp); - string s; - stream_cast(s,(int)VOLUME_MODE_RECTILINEAR); - f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, s,needUp); - - - vector streamIn,streamOut; - streamIn.push_back(d); - - ProgressData p; - f->refresh(streamIn,streamOut,p,dummyCallback); - - //No ions come out of the info - TEST(streamOut.empty(),"stream size test"); - - vector consoleStrings; - f->getConsoleStrings(consoleStrings); - - //weak test for the console string size - TEST(consoleStrings.size(), "console strings existance test"); - - - //Ensure that the rectilinear volume is the same as - // the theoretical value - float volMeasure,volReal;; - volMeasure=f->getLastVolume(); - volReal =SOMEBOX*SOMEBOX*SOMEBOX; - - TEST(fabs(volMeasure -volReal) < - 10.0f*sqrt(std::numeric_limits::epsilon()), - "volume estimation test (rect)"); - - - //Try again, but with convex hull - stream_cast(s,(int)VOLUME_MODE_CONVEX); - f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, s,needUp); - f->refresh(streamIn,streamOut,p,dummyCallback); - volMeasure=f->getLastVolume(); - - TEST(fabs(volMeasure -volReal) < - 10.0f*sqrt(std::numeric_limits::epsilon()), - "volume estimation test (convex)"); - - - - - delete d; - delete f; - return true; -} - -bool volumeSphereTest() -{ - //Construct a few boxes, then test each of their volumes - IonStreamData *d=new IonStreamData(); - - const float OUTLINE_RADIUS=7.0f; - const float ANGULAR_STEP=2.0f; - makeSphereOutline(OUTLINE_RADIUS,ANGULAR_STEP,d); - - //Construct the filter, and then set up the options we need - IonInfoFilter *f = new IonInfoFilter; - f->setCaching(false); - - //activate volume measurement - bool needUp; - f->setProperty(IONINFO_KEY_VOLUME,"1",needUp); - - f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, - volumeModeString[VOLUME_MODE_RECTILINEAR],needUp); - - - vector streamIn,streamOut; - streamIn.push_back(d); - - ProgressData p; - f->refresh(streamIn,streamOut,p,dummyCallback); - - //No ions come out of the info - TEST(streamOut.empty(),"stream size test"); - - vector consoleStrings; - f->getConsoleStrings(consoleStrings); - - //weak test for the console string size - TEST(consoleStrings.size(), "console strings existance test"); - - - float volMeasure,volReal; - volMeasure=f->getLastVolume(); - //Bounding box for sphere is diameter^3. - volReal =8.0f*OUTLINE_RADIUS*OUTLINE_RADIUS*OUTLINE_RADIUS; - TEST(fabs(volMeasure -volReal) < 0.05*volReal,"volume test (rect est of sphere)"); - - - //Try again, but with convex hull - f->setProperty(IONINFO_KEY_VOLUME_ALGORITHM, - volumeModeString[VOLUME_MODE_CONVEX],needUp); - - vector dummy; - f->getConsoleStrings(dummy); - - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - - volMeasure=f->getLastVolume(); - - //Convex volume of sphere - 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"); - - delete d; - delete f; - return true; -} - -bool IonInfoFilter::runUnitTests() -{ - if(!volumeBoxTest()) - return false; - - if(!volumeSphereTest()) - return false; - - return true; -} -#endif - diff -Nru 3depict-0.0.12/src/filters/ionInfo.h 3depict-0.0.13/src/filters/ionInfo.h --- 3depict-0.0.12/src/filters/ionInfo.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/ionInfo.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -#ifndef IONINFO_H -#define IONINFO_H - -#include "../filter.h" -#include "../translation.h" - -enum -{ - IONINFO_KEY_TOTALS=1, - IONINFO_KEY_NORMALISE, - IONINFO_KEY_VOLUME, - IONINFO_KEY_VOLUME_ALGORITHM, -}; - -//!Ion derived information filter, things like volume, composition, etc. -class IonInfoFilter : public Filter -{ - private: - //!Do we want to know information about the number of ions/composition - bool wantIonCounts; - - //!Do we want to normalise the ion count data? - bool wantNormalise; - - - //!Parent rangefile in tree - RangeStreamData *range; - - //!Do we want to know about the volume - bool wantVolume; - - //!Method for volume computation - unsigned int volumeAlgorithm; - - //Side length for filled cube volume estimation - float cubeSideLen; - -#ifdef DEBUG - float lastVolume; -#endif - - //!String for - size_t volumeEstimationStringFromID(const char *str) const; - - //Convex hull volume estmation routine. - //returns 0 on success. global "qh " "object" will contain - //the hull. Volume is computed. - unsigned int convexHullEstimateVol(const vector &data, - float &vol,bool (*callback)(bool)) const; - public: - //!Constructor - IonInfoFilter(); - - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - - //Perform filter intialisation, for pre-detection of range data - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - - //!Apply filter to new data, updating cache as needed. Vector - // of returned pointers must be deleted manually, first checking - // ->cached. - unsigned int refresh(const std::vector &dataIn, - std::vector &dataOut, - ProgressData &progress, bool (*callback)(bool)); - //!Get (approx) number of bytes required for cache - size_t numBytesForCache(size_t nObjects) const; - - //!return type ID - unsigned int getType() const { return FILTER_TYPE_IONINFO;} - - //!Return filter type as std::string - std::string typeString() const { return std::string(TRANS("Ion info"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter, - //!needUpdate tells us if filter output changes due to property set - bool setProperty( unsigned int key, - const std::string &value, bool &needUpdate); - - - void setPropFromBinding( const SelectionBinding &b) {ASSERT(false)}; - - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - /* Current supported formats are STATE_FORMAT_XML - */ - bool writeState(std::ostream &f, unsigned int format, - unsigned int depth) const; - - //!Read state from XML stream, using xml format - /* Current supported formats are STATE_FORMAT_XML - */ - bool readState(xmlNodePtr& n, const std::string &packDir=""); - - //!Get the bitmask encoded list of filterStreams that this filter blocks from propagation. - // i.e. if this filterstream is passed to refresh, it is not emitted. - // This MUST always be consistent with ::refresh for filters current state. - unsigned int getRefreshBlockMask() const; - - //!Get the bitmask encoded list of filterstreams that this filter emits from ::refresh. - // This MUST always be consistent with ::refresh for filters current state. - unsigned int getRefreshEmitMask() const; - - //!Get the bitmask encoded list of filterstreams that this filter may use during ::refresh. - unsigned int getRefreshUseMask() const; - -#ifdef DEBUG - bool runUnitTests(); - - //Debugging function only; must be called after refresh. - //Returns the last estimation for volume. - float getLastVolume() { float tmp=lastVolume; lastVolume=0;return tmp; } -#endif -}; - - -#endif diff -Nru 3depict-0.0.12/src/filters/rangeFile.cpp 3depict-0.0.13/src/filters/rangeFile.cpp --- 3depict-0.0.12/src/filters/rangeFile.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/rangeFile.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1353 +0,0 @@ -#include "rangeFile.h" -#include "../xmlHelper.h" -#include "../commonConstants.h" - -#include "../translation.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, -}; - -const unsigned int NUM_ROWS_ION=3; -const unsigned int NUM_ROWS_RANGE=4; -//!Error codes -enum -{ - RANGEFILE_ABORT_FAIL=1, - RANGEFILE_BAD_ALLOC -}; -//== Range File Filter == - -RangeFileFilter::RangeFileFilter() -{ - dropUnranged=true; - assumedFileFormat=RANGE_FORMAT_ORNL; -} - - -Filter *RangeFileFilter::cloneUncached() const -{ - RangeFileFilter *p=new RangeFileFilter(); - p->rng = rng; - p->rngName=rngName; - p->enabledRanges.resize(enabledRanges.size()); - std::copy(enabledRanges.begin(),enabledRanges.end(), - p->enabledRanges.begin()); - p->enabledIons.resize(enabledIons.size()); - std::copy(enabledIons.begin(),enabledIons.end(), - p->enabledIons.begin()); - p->assumedFileFormat=assumedFileFormat; - p->dropUnranged=dropUnranged; - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -void RangeFileFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - //Copy any input, except range files to output - for(size_t ui=0;uigetStreamType() != STREAM_TYPE_RANGE) - dataOut.push_back(dataIn[ui]); - } - - //Create a rangestream data to push through the init phase - if(rng.getNumIons() && rng.getNumRanges()) - { - RangeStreamData *rngData=new RangeStreamData; - rngData->parent=this; - rngData->rangeFile=&rng; - rngData->enabledRanges.resize(enabledRanges.size()); - std::copy(enabledRanges.begin(),enabledRanges.end(),rngData->enabledRanges.begin()); - rngData->enabledIons.resize(enabledIons.size()); - std::copy(enabledIons.begin(),enabledIons.end(),rngData->enabledIons.begin()); - rngData->cached=0; - - dataOut.push_back(rngData); - } - -} - -unsigned int RangeFileFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - - //use the cached copy of the data if we have it. - if(cacheOK) - { - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) - getOut.push_back(dataIn[ui]); - } - - return 0; - } - - vector d; - - //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;uiparent=this; - } - - 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; - - - progress.step=1; - progress.filterProgress=0; - progress.stepName=TRANS("Pre-Allocate"); - progress.maxStep=2; - - vector 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;uigetStreamType()) - { - 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 *dSizeArr = new vector[nT]; - for(unsigned int uk=0;ukdata.size();uj++) - { -#ifdef _OPENMP - 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--) - { -#pragma omp critical - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - - - if(!(*callback)(false)) - spin=true; - } - } - } - - if(spin) - return RANGEFILE_ABORT_FAIL; -#ifdef _OPENMP - //Merge the arrays back together - for(unsigned int uk=0;ukdata.reserve(dSizes[ui]); - } - catch(std::bad_alloc) - { - for(size_t ui=0;uigetStreamType()) - { - 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::epsilon()); - } - else - { - ionSize=((const IonStreamData *)dataIn[ui])->ionSize; - haveIonSize=true; - } - - unsigned int curProg=NUM_CALLBACK; - const size_t off=d.size()-1; - - for(vector::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); - - //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); - } - - //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;uir=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;uiionSize=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;uidata.size())) - { - delete d[ui]; - std::swap(d[ui],d.back()); - d.pop_back(); - } - else - ui++; - } - - //====================================== - - //Having ranged all streams, merge them back into one ranged stream. - if(cache) - { - for(unsigned int ui=0;uicached=1; //IMPORTANT: ->cached must be set PRIOR to push back - filterOutputs.push_back(d[ui]); - } - } - else - { - for(unsigned int ui=0;uicached=0; //IMPORTANT: ->cached must be set PRIOR to push back - cacheOK=false; - } - - for(unsigned int ui=0;uiparent=this; - rngData->rangeFile=&rng; - - rngData->enabledRanges.resize(enabledRanges.size()); - std::copy(enabledRanges.begin(),enabledRanges.end(),rngData->enabledRanges.begin()); - rngData->enabledIons.resize(enabledIons.size()); - std::copy(enabledIons.begin(),enabledIons.end(),rngData->enabledIons.begin()); - - - rngData->cached=cache; - - if(cache) - filterOutputs.push_back(rngData); - - getOut.push_back(rngData); - - cacheOK=cache; - return 0; -} - -bool RangeFileFilter::updateRng() -{ - if(!rng.openGuessFormat(rngName.c_str())) - return false; - - unsigned int nRng = rng.getNumRanges(); - enabledRanges.resize(nRng); - unsigned int nIon = rng.getNumIons(); - enabledIons.resize(nIon); - //Turn all ranges to "on" - for(unsigned int ui=0;ui thisRange; - thisRange = rng.getRange(ui); - string rangeVal; - stream_cast(rangeVal,thisRange.first); - - prop.name=string(TRANS("Start rng "))+suffix; - 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; - p.addProperty(prop,curGroup); - - stream_cast(rangeVal,thisRange.second); - prop.name=string(TRANS("End rng "))+suffix; - 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; - p.addProperty(prop,curGroup); - } - p.setGroupTitle(curGroup,TRANS("Ranges")); - //---- - -} - -bool RangeFileFilter::setProperty(unsigned int key, - const std::string &value, bool &needUpdate) -{ - using std::string; - needUpdate=false; - - - switch(key) - { - case KEY_RANGE_FILENAME: - { - //Check to see if the new file can actually be opened - RangeFile rngTwo; - - if(value != rngName) - { - if(!rngTwo.open(value.c_str())) - return false; - else - { - rng.swap(rngTwo); - rngName=value; - needUpdate=true; - } - - } - else - return false; - - if(needUpdate) - clearCache(); - - break; - } - case KEY_DROP_UNRANGED: //Enable/disable unranged dropping - { - unsigned int valueInt; - if(stream_cast(valueInt,value)) - return false; - - if(valueInt ==0 || valueInt == 1) - { - if((int)dropUnranged!= valueInt) - { - needUpdate=true; - dropUnranged=valueInt; - } - else - needUpdate=false; - } - else - return false; - - if(needUpdate) - clearCache(); - - break; - } - case KEY_ENABLE_ALL_RANGES: - { - - bool allEnable; - if(value == "1") - allEnable=true; - else if ( value == "0") - allEnable=false; - else - return false; - - //set them to the opposite of whatever we have now - //if any single one needs a change, then we need to - //update - for(unsigned int ui=0;ui9 - for(unsigned int ui=0;ui rng.getNumRanges()) - return false; - - rng.setIonID(rangeId,newID); - needUpdate=true; - break; - } - //Range start - case 2: - { - - //Check for valid data type conversion - float newMass; - if(stream_cast(newMass,value)) - return false; - - //Ensure that it has actually changed - if(newMass == rng.getRange(rangeId).first) - return false; - - //Attempt to move the range to a new position - if(!rng.moveRange(rangeId,0,newMass)) - return false; - - needUpdate=true; - - break; - } - //Range end - case 3: - { - - //Check for valid data type conversion - float newMass; - if(stream_cast(newMass,value)) - return false; - - //Ensure that it has actually changed - if(newMass == rng.getRange(rangeId).second) - return false; - - //Attempt to move the range to a new position - if(!rng.moveRange(rangeId,1,newMass)) - return false; - - needUpdate=true; - - break; - } - } - - if(needUpdate) - clearCache(); - } - } - } - - return true; -} - - -std::string RangeFileFilter::getErrString(unsigned int code) const -{ - switch(code) - { - case RANGEFILE_ABORT_FAIL: - return std::string(TRANS("Ranging aborted by user")); - case RANGEFILE_BAD_ALLOC: - return std::string(TRANS("Insufficient memory for range")); - } - - return std::string("BUG(range file filter): Shouldn't see this!"); -} - -void RangeFileFilter::setFormat(unsigned int format) -{ - ASSERT(format < RANGE_FORMAT_END_OF_ENUM); - - assumedFileFormat=format; -} - -bool RangeFileFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << ""<< endl; - for(unsigned int ui=0;ui" << endl; - } - f << tabs(depth+1) << ""<< endl; - - f << tabs(depth+1) << ""<< endl; - - for(unsigned int ui=0;ui" << endl; - } - f << tabs(depth+1) << ""<< endl; - - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - - //Retrieve user string - //== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //== - - //Retrieve file name - //== - //Retrieve file name - if(XMLHelpFwdToElem(nodePtr,"file")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"name"); - if(!xmlString) - return false; - rngName=(char *)xmlString; - xmlFree(xmlString); - - //Override the string, as needed - if( (stateFileDir.size()) && - (rngName.size() > 2 && rngName.substr(0,2) == "./") ) - { - rngName=stateFileDir + rngName.substr(2); - } - - rngName=convertFileStringToNative(rngName); - - //try using the extension name of the file to guess format - if(!rng.openGuessFormat(rngName.c_str())) - return false; - - //== - - std::string tmpStr; - //Retrieve user string - //== - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"dropunranged","value")) - return false; - - if(tmpStr=="1") - dropUnranged=true; - else if(tmpStr=="0") - dropUnranged=false; - else - return false; - - //== - - - //Retrieve enabled ions - //=== - if(XMLHelpFwdToElem(nodePtr,"enabledions")) - return false; - xmlNodePtr tmpNode=nodePtr; - - nodePtr=nodePtr->xmlChildrenNode; - - unsigned int ionID; - bool enabled; - //By default, turn ions off, but use state file to turn them on - enabledIons.resize(rng.getNumIons(),false); - while(!XMLHelpFwdToElem(nodePtr,"ion")) - { - //Get ID value - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"id"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(ionID,tmpStr)) - return false; - - if(ionID>= rng.getNumIons()) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"enabled"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - enabled=false; - else if(tmpStr == "1") - enabled=true; - else - return false; - - enabledIons[ionID]=enabled; - xmlFree(xmlString); - - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"colour"); - if(!xmlString) - return false; - - - tmpStr=(char *)xmlString; - - unsigned char r,g,b,a; - if(!parseColString(tmpStr,r,g,b,a)) - return false; - - RGBf col; - col.red=(float)r/255.0f; - col.green=(float)g/255.0f; - col.blue=(float)b/255.0f; - rng.setColour(ionID,col); - xmlFree(xmlString); - } - - //=== - - - nodePtr=tmpNode; - //Retrieve enabled ranges - //=== - if(XMLHelpFwdToElem(nodePtr,"enabledranges")) - return false; - tmpNode=nodePtr; - - nodePtr=nodePtr->xmlChildrenNode; - - //By default, turn ranges off (cause there are lots of them), and use state to turn them on - enabledRanges.resize(rng.getNumRanges(),true); - unsigned int rngID; - while(!XMLHelpFwdToElem(nodePtr,"range")) - { - //Get ID value - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"id"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(rngID,tmpStr)) - return false; - - if(rngID>= rng.getNumRanges()) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"enabled"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(tmpStr == "0") - enabled=false; - else if(tmpStr == "1") - enabled=true; - else - return false; - - xmlFree(xmlString); - enabledRanges[rngID]=enabled; - } - //=== - - return true; -} - -void RangeFileFilter::getStateOverrides(std::vector &externalAttribs) const -{ - externalAttribs.push_back(rngName); -} - -unsigned int RangeFileFilter::getRefreshBlockMask() const -{ - return STREAM_TYPE_RANGE | STREAM_TYPE_IONS ; -} - -unsigned int RangeFileFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_RANGE | STREAM_TYPE_IONS ; -} - -unsigned int RangeFileFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS ; -} - -void RangeFileFilter::setPropFromRegion(unsigned int method, unsigned int regionID, float newPos) -{ - ASSERT(regionID < rng.getNumRanges()); - - unsigned int rangeID = regionID; - - switch(method) - { - case REGION_MOVE_EXTEND_XMINUS: - rng.moveRange(rangeID,false, newPos); - break; - case REGION_MOVE_TRANSLATE_X: - { - std::pair limits; - limits=rng.getRange(rangeID); - float delta; - delta = (limits.second-limits.first)/2; - rng.moveBothRanges(rangeID,newPos-delta,newPos+delta); - break; - } - case REGION_MOVE_EXTEND_XPLUS: - rng.moveRange(rangeID,true, newPos); - break; - default: - ASSERT(false); - } - - clearCache(); -} - -bool RangeFileFilter::writePackageState(std::ostream &f, unsigned int format, - const std::vector &valueOverrides, unsigned int depth) const -{ - ASSERT(valueOverrides.size() == 1); - - //Temporarily modify the state of the filter, then call writestate - string tmpFilename=rngName; - - - //override const -- naughty, but we know what we are doing... - const_cast(this)->rngName=valueOverrides[0]; - bool result; - result=writeState(f,format,depth); - const_cast(this)->rngName=tmpFilename; - - return result; -} - -#ifdef DEBUG - -bool testRanged(); -//bool testRangeWithOnOffs(); -bool testUnranged(); - -bool RangeFileFilter::runUnitTests() -{ - if(!testRanged()) - return false; - - return true; -} - -bool testUnranged() -{ - return true; -} - -bool testRanged() -{ - vector streamIn,streamOut; - //Synthesise data - //----- - IonStreamData *d = new IonStreamData; - - IonHit h; - h.setPos(Point3D(1,1,1)); - - for(unsigned int ui=0;ui<100; ui++) - { - h.setMassToCharge(ui); - d->data.push_back(h); - } - - streamIn.push_back(d); - - //Now build some range data - RangeFile rng; - - //Insert *non overlapping* ranges. - const unsigned int NUM[]={10,14}; - const unsigned int OFFSET[]={0,20}; - string longName,shortName; - - RGBf col; - col.red=col.green=col.blue=1; - shortName="Bl"; longName="Blahium"; - unsigned int ionID; - ionID=rng.addIon(shortName,longName,col); - rng.addRange((float)OFFSET[0],(float)(OFFSET[0]+NUM[0]-1),ionID); - - shortName="Pl"; longName="Palatherum"; - ionID=rng.addIon(shortName,longName,col); - rng.addRange((float)OFFSET[1],(float)(OFFSET[1]+NUM[1]-1),ionID); - - //----- - - //Run the range filter - //-- - RangeFileFilter *r = new RangeFileFilter; - r->setCaching(false); - r->setRangeData(rng); - - //Run the initialisation stage - ProgressData prog; - TEST(!r->refresh(streamIn,streamOut,prog,dummyCallback),"Refresh error code"); - //-- - - //Run the tests - //--- - vector numIons; - for(unsigned int ui=0; uigetStreamType() == STREAM_TYPE_IONS) - { - numIons.push_back(streamOut[ui]->getNumBasicObjects()); - const IonStreamData *dI; - dI = (IonStreamData*)streamOut[ui]; - for(unsigned int uj=0;ujdata[uj].getMassToCharge()), - "Range containment"); - } - } - - } - - //Ion stream output - ranges + unranged - TEST(numIons.size() == 2, "Ranged ionstream count"); - TEST(std::find(numIons.begin(),numIons.end(),NUM[0]) - != numIons.end(), "ion count test (1)"); - TEST(std::find(numIons.begin(),numIons.end(),NUM[1]) - != numIons.end(), "ion count test (2)"); - - for(unsigned int uj=0;uj enabledRanges; - //!Vector of chars stating if user has enabled a particular Ion or not. - std::vector enabledIons; - - //!Whether to drop unranged ions in our output - bool dropUnranged; - - //!Assumed file format when loading. - unsigned int assumedFileFormat; - - void guessFormat(const std::string &s); - - //!range file object - RangeFile rng; - - public: - const RangeFile &getRange() const { return rng;}; - - //!Set the format to assume when loading file - void setFormat(unsigned int format); - - std::vector getEnabledRanges() const {return enabledRanges;}; - void setEnabledRanges(vector i) {enabledRanges = i;}; - - - RangeFileFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - void setRangeFilename(std::string filename){rngName=filename;}; - - //!Returns -1, as range file cache size is dependant upon input. - virtual size_t numBytesForCache(size_t nObjects) const; - //!Returns FILTER_TYPE_RANGEFILE - unsigned int getType() const { return FILTER_TYPE_RANGEFILE;}; - - //!Propagates a range stream data through the filter init stage. Blocks any other range stream datas - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - //update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - //!Force a re-read of the rangefile, returning false on failure, true on success - bool updateRng(); - - //!Set the internal data using the specified range object - void setRangeData(const RangeFile &newRange); - - virtual std::string typeString() const { return std::string(TRANS("Ranging"));}; - - //Types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //Types that are emitted by filer during ::refrash - unsigned int getRefreshEmitMask() const; - - //Types that are possibly used by filer during ::refrash - unsigned int getRefreshUseMask() const; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - - //!Set a region update - virtual void setPropFromRegion(unsigned int method, unsigned int regionID, float newPos); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - - //!Modified version of writeState for packaging. By default simply calls writeState. - //value overrides override the values returned by getStateOverrides. In order. - virtual bool writePackageState(std::ostream &f, unsigned int format, - const std::vector &valueOverrides,unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!filter has state overrides - virtual void getStateOverrides(std::vector &overrides) const; - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - -#ifdef DEBUG - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/spatialAnalysis.cpp 3depict-0.0.13/src/filters/spatialAnalysis.cpp --- 3depict-0.0.12/src/filters/spatialAnalysis.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/spatialAnalysis.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2257 +0,0 @@ -#include "spatialAnalysis.h" -#include "../xmlHelper.h" -#include "../rdf.h" - - -#include "../translation.h" -enum -{ - KEY_STOPMODE, - KEY_ALGORITHM, - KEY_DISTMAX, - KEY_NNMAX, - KEY_NUMBINS, - KEY_REMOVAL, - KEY_REDUCTIONDIST, - KEY_RETAIN_UPPER, - KEY_CUTOFF, - KEY_COLOUR, - KEY_ENABLE_SOURCE, - KEY_ENABLE_TARGET, -}; - -enum { - ALGORITHM_DENSITY, //Local density analysis - ALGORITHM_DENSITY_FILTER, //Local density filtering - ALGORITHM_RDF, //Radial Distribution Function - ALGORITHM_ENUM_END, -}; - -enum{ - STOP_MODE_NEIGHBOUR, - STOP_MODE_RADIUS, - STOP_MODE_ENUM_END -}; - -//!Error codes -enum -{ - ABORT_ERR=1, - INSUFFICIENT_SIZE_ERR, -}; -// == NN analysis filter == - - -//User visible names for the different algorithms -const char *SPATIAL_ALGORITHMS[] = { - NTRANS("Local Density"), - NTRANS("Density Filtering"), - NTRANS("Radial Distribution") - }; - -const char *STOP_MODES[] = { - NTRANS("Fixed Neighbour Count"), - NTRANS("Fixed Radius") -}; - -//Switch to determine if algorithms need range propagation or not -const bool WANT_RANGE_PROPAGATION[] = { false, - true, - false - }; - -template -bool xorFunc(const T a, const T b) -{ - return (a || b) && !(a && b); -} - - - -SpatialAnalysisFilter::SpatialAnalysisFilter() -{ - COMPILE_ASSERT(ARRAYSIZE(STOP_MODES) == STOP_MODE_ENUM_END); - COMPILE_ASSERT(ARRAYSIZE(SPATIAL_ALGORITHMS) == ALGORITHM_ENUM_END); - COMPILE_ASSERT(ARRAYSIZE(WANT_RANGE_PROPAGATION) == ALGORITHM_ENUM_END); - algorithm=ALGORITHM_DENSITY; - nnMax=1; - distMax=1; - stopMode=STOP_MODE_NEIGHBOUR; - - haveRangeParent=false; - - //Default colour is red - r=a=1.0f; - g=b=0.0f; - - //RDF params - numBins=100; - excludeSurface=false; - - //Density filtering params - densityCutoff=1.0f; - keepDensityUpper=true; - - reductionDistance=distMax; - - cacheOK=false; - cache=true; //By default, we should cache, but decision is made higher up - -} - -Filter *SpatialAnalysisFilter::cloneUncached() const -{ - SpatialAnalysisFilter *p=new SpatialAnalysisFilter; - - p->r=r; - p->g=g; - p->b=b; - p->a=a; - - p->algorithm=algorithm; - p->stopMode=stopMode; - p->nnMax=nnMax; - p->distMax=distMax; - - p->numBins=numBins; - p->excludeSurface=excludeSurface; - p->reductionDistance=reductionDistance; - - p->keepDensityUpper=keepDensityUpper; - p->densityCutoff=densityCutoff; - - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -size_t SpatialAnalysisFilter::numBytesForCache(size_t nObjects) const -{ - return nObjects*IONDATA_SIZE; -} - -void SpatialAnalysisFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - //Check for range file parent - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_RANGE) - { - const RangeStreamData *r; - r = (const RangeStreamData *)dataIn[ui]; - - if(WANT_RANGE_PROPAGATION[algorithm]) - dataOut.push_back(dataIn[ui]); - - bool different=false; - if(!haveRangeParent) - { - //well, things have changed, we didn't have a - //range parent before. - different=true; - } - else - { - //OK, last time we had a range parent. Check to see - //if the ion names are the same. If they are, keep the - //current bools, iff the ion names are all the same - unsigned int numEnabled=std::count(r->enabledIons.begin(), - r->enabledIons.end(),1); - if(ionNames.size() == numEnabled) - { - unsigned int pos=0; - for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) - { - //Only look at parent-enabled ranges - if(r->enabledIons[uj]) - { - if(r->rangeFile->getName(uj) != ionNames[pos]) - { - different=true; - break; - } - pos++; - } - } - } - } - haveRangeParent=true; - - if(different) - { - //OK, its different. we will have to re-assign, - //but only allow the ranges enabled in the parent filter - ionNames.clear(); - ionNames.reserve(r->rangeFile->getNumRanges()); - for(unsigned int uj=0;ujrangeFile->getNumIons();uj++) - { - - if(r->enabledIons[uj]) - ionNames.push_back(r->rangeFile->getName(uj)); - } - - ionSourceEnabled.resize(ionNames.size(),true); - ionTargetEnabled.resize(ionNames.size(),true); - } - - return; - } - } - haveRangeParent=false; -} - -unsigned int SpatialAnalysisFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - //use the cached copy if we have it. - if(cacheOK) - { - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) - { - //Only propagate ranges if we want range propagation - if(dataIn[ui]->getStreamType() !=STREAM_TYPE_RANGE - || WANT_RANGE_PROPAGATION[algorithm]) - getOut.push_back(dataIn[ui]); - } - } - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - totalDataSize+=d->data.size(); - } - break; - default: - break; - } - } - - //Nothing to do, but propagate inputs - if(!totalDataSize) - { - //Propagate any inputs that we don't normally block - for(size_t ui=0;uigetStreamType() & getRefreshBlockMask())) - getOut.push_back(dataIn[ui]); - } - return 0; - } - - const RangeFile *rngF=0; - if(haveRangeParent) - { - //Check we actually have something to do - if(!std::count(ionSourceEnabled.begin(), - ionSourceEnabled.end(),true)) - return 0; - if(!std::count(ionTargetEnabled.begin(), - ionTargetEnabled.end(),true)) - return 0; - - rngF=getRangeFile(dataIn); - } - - //Run the algorithm - if(algorithm == ALGORITHM_DENSITY) - { - //Build monolithic point set - //--- - vector p; - p.resize(totalDataSize); - - size_t dataSize=0; - size_t n=0; - - progress.step=1; - progress.stepName=TRANS("Collate"); - progress.maxStep=3; - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - - if(extendPointVector(p,d->data, - callback,progress.filterProgress, - dataSize)) - return ABORT_ERR; - - dataSize+=d->data.size(); - } - break; - default: - break; - } - } - //--- - - progress.step=2; - progress.stepName=TRANS("Build"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - BoundCube treeDomain; - treeDomain.setBounds(p); - - //Build the tree (its roughly nlogn timing, but worst case n^2) - K3DTree kdTree; - kdTree.setCallbackMethod(callback); - kdTree.setProgressPointer(&(progress.filterProgress)); - - kdTree.buildByRef(p); - - - //Update progress & User interface by calling callback - if(!(*callback)(false)) - return ABORT_ERR; - p.clear(); //We don't need pts any more, as tree *is* a copy. - - - //Its algorithim time! - //---- - //Update progress stuff - n=0; - progress.step=3; - progress.stepName=TRANS("Analyse"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - //List of points for which there was a failure - //first entry is the point Id, second is the - //dataset id. - std::list > badPts; - for(size_t ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - IonStreamData *newD = new IonStreamData; - newD->parent=this; - - //Adjust this number to provide more update thanusual, because we - //are not doing an o(1) task between updates; yes, it is a hack - unsigned int curProg=NUM_CALLBACK/(10*nnMax); - newD->data.resize(d->data.size()); - if(stopMode == STOP_MODE_NEIGHBOUR) - { - bool spin=false; - #pragma omp parallel for shared(spin) - for(size_t uj=0;ujdata.size();uj++) - { - if(spin) - continue; - Point3D r; - vector res; - r=d->data[uj].getPosRef(); - - //Assign the mass to charge using nn density estimates - kdTree.findKNearest(r,treeDomain,nnMax,res); - - if(res.size()) - { - float maxSqrRad; - - //Get the radius as the furtherst object - maxSqrRad= (res[res.size()-1]->sqrDist(r)); - - //Set the mass as the volume of sphere * the number of NN - newD->data[uj].setMassToCharge(res.size()/(4.0/3.0*M_PI*powf(maxSqrRad,3.0/2.0))); - //Keep original position - newD->data[uj].setPos(r); - } - else - { - #pragma omp critical - badPts.push_back(make_pair(uj,ui)); - } - - res.clear(); - - //Update callback as needed - if(!curProg--) - { - #pragma omp critical - { - n+=NUM_CALLBACK/(nnMax); - progress.filterProgress= (unsigned int)(((float)n/(float)totalDataSize)*100.0f); - if(!(*callback)(false)) - spin=true; - curProg=NUM_CALLBACK/(nnMax); - } - } - } - - if(spin) - { - delete newD; - return ABORT_ERR; - } - - - } - else if(stopMode == STOP_MODE_RADIUS) - { -#ifdef _OPENMP - bool spin=false; -#endif - float maxSqrRad = distMax*distMax; - float vol = 4.0/3.0*M_PI*maxSqrRad*distMax; //Sphere volume=4/3 Pi R^3 - #pragma omp parallel for shared(spin) firstprivate(treeDomain,curProg) - for(size_t uj=0;ujdata.size();uj++) - { - Point3D r; - const Point3D *res; - float deadDistSqr; - unsigned int numInRad; -#ifdef _OPENMP - if(spin) - continue; -#endif - r=d->data[uj].getPosRef(); - numInRad=0; - deadDistSqr=0; - - //Assign the mass to charge using nn density estimates - do - { - res=kdTree.findNearest(r,treeDomain,deadDistSqr); - - //Check to see if we found something - if(!res) - { -#pragma omp critical - badPts.push_back(make_pair(uj, ui)); - break; - } - - if(res->sqrDist(r) >maxSqrRad) - break; - numInRad++; - //Advance ever so slightly beyond the next ion - deadDistSqr = res->sqrDist(r)+std::numeric_limits::epsilon(); - //Update callback as needed - if(!curProg--) - { -#pragma omp critical - { - progress.filterProgress= (unsigned int)((float)n/(float)totalDataSize*100.0f); - if(!(*callback)(false)) - { -#ifdef _OPENMP - spin=true; -#else - delete newD; - return ABORT_ERR; -#endif - } - } -#ifdef _OPENMP - if(spin) - break; -#endif - curProg=NUM_CALLBACK/(10*nnMax); - } - }while(true); - - n++; - //Set the mass as the volume of sphere * the number of NN - newD->data[uj].setMassToCharge(numInRad/vol); - //Keep original position - newD->data[uj].setPos(r); - - } - -#ifdef _OPENMP - if(spin) - { - delete newD; - return ABORT_ERR; - } -#endif - } - else - { - //Should not get here. - ASSERT(false); - } - - - //move any bad points from the array to the end, then drop them - //To do this, we have to reverse sort the array, then - //swap the output ion vector entries with the end, - //then do a resize. - ComparePairFirst cmp; - badPts.sort(cmp); - badPts.reverse(); - - //Do some swappage - size_t pos=1; - for(std::list >::iterator it=badPts.begin(); it!=badPts.end();++it) - { - newD->data[(*it).first]=newD->data[newD->data.size()-pos]; - } - - //Trim the tail of bad points, leaving only good points - newD->data.resize(newD->data.size()-badPts.size()); - - - if(newD->data.size()) - { - //Use default colours - newD->r=d->r; - newD->g=d->g; - newD->b=d->b; - newD->a=d->a; - newD->ionSize=d->ionSize; - newD->representationType=d->representationType; - newD->valueType=TRANS("Number Density (\\#/Vol^3)"); - - //Cache result as needed - if(cache) - { - newD->cached=1; - filterOutputs.push_back(newD); - cacheOK=true; - } - else - newD->cached=0; - getOut.push_back(newD); - } - } - break; - case STREAM_TYPE_RANGE: - break; - default: - getOut.push_back(dataIn[ui]); - break; - } - } - //If we have bad points, let the user know. - if(!badPts.empty()) - { - std::string sizeStr; - stream_cast(sizeStr,badPts.size()); - consoleOutput.push_back(std::string(TRANS("Warning,")) + sizeStr + - TRANS(" points were un-analysable. These have been dropped")); - - //Print out a list of points if we can - - size_t maxPrintoutSize=std::min(badPts.size(),(size_t)200); - list >::iterator it; - it=badPts.begin(); - while(maxPrintoutSize--) - { - std::string s; - const IonStreamData *d; - d=((const IonStreamData *)dataIn[it->second]); - - Point3D getPos; - getPos= d->data[it->first].getPosRef(); - stream_cast(s,getPos); - consoleOutput.push_back(s); - ++it; - } - - if(badPts.size() > 200) - { - consoleOutput.push_back(TRANS("And so on...")); - } - - - } - } - else if (algorithm == ALGORITHM_RDF) - { - progress.step=1; - progress.stepName=TRANS("Collate"); - progress.filterProgress=0; - if(excludeSurface) - progress.maxStep=4; - else - progress.maxStep=3; - - if(!(*callback)(true)) - return ABORT_ERR; - - K3DTree kdTree; - kdTree.setCallbackMethod(callback); - kdTree.setProgressPointer(&(progress.filterProgress)); - - //Source points - vector p; - bool needSplitting; - - needSplitting=false; - //We only need to split up the data if we hvae to - if(std::count(ionSourceEnabled.begin(),ionSourceEnabled.end(),true)!=ionSourceEnabled.size()) - needSplitting=true; - if(std::count(ionTargetEnabled.begin(),ionTargetEnabled.end(),true)!=ionTargetEnabled.size()) - needSplitting=true; - - if(haveRangeParent && needSplitting) - { - ASSERT(ionNames.size()); - //Build monolithic point sets - //one for targets, one for sources - //--- - vector pts[2]; //0 -> Source, 1-> Target - size_t sizeNeeded[2]; - sizeNeeded[0]=sizeNeeded[1]=0; - //Presize arrays - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - unsigned int rangeID; - - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - rangeID=getIonstreamIonID(d,rngF); - - if(rangeID == (unsigned int)-1) - break; - - if(ionSourceEnabled[rangeID]) - sizeNeeded[0]+=d->data.size(); - - if(ionTargetEnabled[rangeID]) - sizeNeeded[1]+=d->data.size(); - break; - } - default: - break; - } - } - - pts[0].resize(sizeNeeded[0]); - pts[1].resize(sizeNeeded[1]); - - //Fill arrays - size_t curPos[2]; - curPos[0]=curPos[1]=0; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - unsigned int rangeID; - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - rangeID=getIonstreamIonID(d,rngF); - - if(rangeID==(unsigned int)(-1)) - break; - if(ionSourceEnabled[rangeID]) - { - if(extendPointVector(pts[0],d->data,callback, - progress.filterProgress,curPos[0])) - return ABORT_ERR; - curPos[0]+=d->data.size(); - } - - if(ionTargetEnabled[rangeID]) - { - if(extendPointVector(pts[1],d->data,callback, - progress.filterProgress,curPos[1])) - return ABORT_ERR; - - curPos[1]+=d->data.size(); - } - break; - } - default: - break; - } - } - //--- - - progress.step=2; - progress.stepName=TRANS("Build"); - - //Build the tree using the target ions - //(its roughly nlogn timing, but worst case n^2) - kdTree.buildByRef(pts[1]); - pts[1].clear(); - - //Remove surface points from sources if desired - if(excludeSurface) - { - ASSERT(reductionDistance > 0); - progress.step++; - progress.stepName=TRANS("Surface"); - - - //Take the input points, then use them - //to compute the convex hull reduced - //volume. - vector returnPoints; - GetReducedHullPts(pts[0],reductionDistance, - returnPoints); - - pts[0].clear(); - //Forget the original points, and use the new ones - p.swap(returnPoints); - } - else - p.swap(pts[0]); - - } - else - { - //Build monolithic point set - //--- - p.resize(totalDataSize); - - size_t dataSize=0; - - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - if(extendPointVector(p,d->data,callback, - progress.filterProgress,dataSize)) - return ABORT_ERR; - dataSize+=d->data.size(); - } - break; - default: - break; - } - } - //--- - - progress.step=2; - progress.stepName=TRANS("Build"); - BoundCube treeDomain; - treeDomain.setBounds(p); - - //Build the tree (its roughly nlogn timing, but worst case n^2) - kdTree.buildByRef(p); - - //Remove surface points if desired - if(excludeSurface) - { - ASSERT(reductionDistance > 0); - progress.step++; - progress.stepName=TRANS("Surface"); - - - //Take the input points, then use them - //to compute the convex hull reduced - //volume. - vector returnPoints; - GetReducedHullPts(p,reductionDistance, - returnPoints); - - //Forget the original points, and use the new ones - p.swap(returnPoints); - - } - - } - - //Let us perform the desired analysis - progress.step++; - progress.stepName=TRANS("Analyse"); - - //If there is no data, there is nothing to do. - if(p.empty() || !kdTree.nodeCount()) - return 0; - //OK, at this point, the KD tree contains the target points - //of interest, and the vector "p" contains the source points - //of interest, whatever they might be. - - switch(stopMode) - { - case STOP_MODE_NEIGHBOUR: - { - //User is after an NN histogram analysis - - //Histogram is output as a per-NN histogram of frequency. - vector > histogram; - - //Bin widths for the NN histograms (each NN hist - //is scaled separately). The +1 is due to the tail bin - //being the totals - float *binWidth = new float[nnMax]; - - - unsigned int errCode; - //Run the analysis - errCode=generateNNHist(p,kdTree,nnMax, - numBins,histogram,binWidth, - &(progress.filterProgress),callback); - switch(errCode) - { - case 0: - break; - case RDF_ERR_INSUFFICIENT_INPUT_POINTS: - { - delete[] binWidth; - return INSUFFICIENT_SIZE_ERR; - } - case RDF_ABORT_FAIL: - { - delete[] binWidth; - return ABORT_ERR; - } - default: - ASSERT(false); - } - - //Alright then, we have the histogram in x-{y1,y2,y3...y_n} form - //lets make some plots shall we? - PlotStreamData *plotData[nnMax]; - - for(unsigned int ui=0;uiindex=ui; - plotData[ui]->parent=this; - plotData[ui]->plotMode=PLOT_MODE_1D; - plotData[ui]->xLabel=TRANS("Radial Distance"); - plotData[ui]->yLabel=TRANS("Count"); - std::string tmpStr; - stream_cast(tmpStr,ui+1); - plotData[ui]->dataLabel=getUserString() + string(" ") +tmpStr + TRANS("NN Freq."); - - //Red plot. - plotData[ui]->r=r; - plotData[ui]->g=g; - plotData[ui]->b=b; - plotData[ui]->xyData.resize(numBins); - - for(unsigned int uj=0;ujxyData[uj] = std::make_pair(dist, - histogram[ui][uj]); - } - - if(cache) - { - plotData[ui]->cached=1; - filterOutputs.push_back(plotData[ui]); - cacheOK=true; - } - else - { - plotData[ui]->cached=0; - } - - getOut.push_back(plotData[ui]); - } - - delete[] binWidth; - break; - } - - case STOP_MODE_RADIUS: - { - unsigned int warnBiasCount=0; - - //Histogram is output as a histogram of frequency vs distance - unsigned int *histogram = new unsigned int[numBins]; - for(unsigned int ui=0;uiplotMode=PLOT_MODE_1D; - plotData->index=0; - plotData->parent=this; - plotData->xLabel=TRANS("Radial Distance"); - plotData->yLabel=TRANS("Count"); - plotData->dataLabel=getUserString() + TRANS(" RDF"); - - //Red plot. - plotData->r=r; - plotData->g=g; - plotData->b=b; - plotData->xyData.resize(numBins); - - for(unsigned int uj=0;ujxyData[uj] = std::make_pair(dist, - histogram[uj]); - } - - delete[] histogram; - - if(cache) - { - plotData->cached=1; - filterOutputs.push_back(plotData); - cacheOK=true; - } - else - plotData->cached=0; - - getOut.push_back(plotData); - - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - case STREAM_TYPE_RANGE: - //Do not propagate ranges, or ions - break; - default: - getOut.push_back(dataIn[ui]); - break; - } - - } - - break; - } - default: - ASSERT(false); - } - } - else if (algorithm == ALGORITHM_DENSITY_FILTER) - { - //Build monolithic point set - //--- - vector p; - p.resize(totalDataSize); - - size_t dataSize=0; - size_t n=0; - - progress.step=1; - progress.stepName=TRANS("Collate"); - progress.maxStep=3; - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - - if(extendPointVector(p,d->data, - callback,progress.filterProgress, - dataSize)) - return ABORT_ERR; - - dataSize+=d->data.size(); - } - break; - default: - break; - } - } - //--- - - progress.step=2; - progress.stepName=TRANS("Build"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - BoundCube treeDomain; - treeDomain.setBounds(p); - - //Build the tree (its roughly nlogn timing, but worst case n^2) - K3DTree kdTree; - kdTree.setCallbackMethod(callback); - kdTree.setProgressPointer(&(progress.filterProgress)); - - kdTree.buildByRef(p); - - - //Update progress & User interface by calling callback - if(!(*callback)(false)) - return ABORT_ERR; - p.clear(); //We don't need pts any more, as tree *is* a copy. - - - //Its algorithim time! - //---- - //Update progress stuff - n=0; - progress.step=3; - progress.stepName=TRANS("Analyse"); - progress.filterProgress=0; - if(!(*callback)(true)) - return ABORT_ERR; - - //List of points for which there was a failure - //first entry is the point Id, second is the - //dataset id. - std::list > badPts; - for(size_t ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *d; - d=((const IonStreamData *)dataIn[ui]); - IonStreamData *newD = new IonStreamData; - newD->parent=this; - - //Adjust this number to provide more update thanusual, because we - //are not doing an o(1) task between updates; yes, it is a hack - unsigned int curProg=NUM_CALLBACK/(10*nnMax); - newD->data.reserve(d->data.size()); - if(stopMode == STOP_MODE_NEIGHBOUR) - { - bool spin=false; - #pragma omp parallel for shared(spin) - for(size_t uj=0;ujdata.size();uj++) - { - if(spin) - continue; - Point3D r; - vector res; - r=d->data[uj].getPosRef(); - - //Assign the mass to charge using nn density estimates - kdTree.findKNearest(r,treeDomain,nnMax,res); - - if(res.size()) - { - float maxSqrRad; - - //Get the radius as the furtherst object - maxSqrRad= (res[res.size()-1]->sqrDist(r)); - - - float density; - density = res.size()/(4.0/3.0*M_PI*powf(maxSqrRad,3.0/2.0)); - - if(xorFunc((density <=densityCutoff), keepDensityUpper)) - { -#pragma omp critical - newD->data.push_back(d->data[uj]); - } - - } - else - { - #pragma omp critical - badPts.push_back(make_pair(uj,ui)); - } - - res.clear(); - - //Update callback as needed - if(!curProg--) - { - #pragma omp critical - { - n+=NUM_CALLBACK/(nnMax); - progress.filterProgress= (unsigned int)(((float)n/(float)totalDataSize)*100.0f); - if(!(*callback)(false)) - spin=true; - curProg=NUM_CALLBACK/(nnMax); - } - } - } - - if(spin) - { - delete newD; - return ABORT_ERR; - } - - - } - else if(stopMode == STOP_MODE_RADIUS) - { -#ifdef _OPENMP - bool spin=false; -#endif - float maxSqrRad = distMax*distMax; - float vol = 4.0/3.0*M_PI*maxSqrRad*distMax; //Sphere volume=4/3 Pi R^3 - #pragma omp parallel for shared(spin) firstprivate(treeDomain,curProg) - for(size_t uj=0;ujdata.size();uj++) - { - Point3D r; - const Point3D *res; - float deadDistSqr; - unsigned int numInRad; -#ifdef _OPENMP - if(spin) - continue; -#endif - r=d->data[uj].getPosRef(); - numInRad=0; - deadDistSqr=0; - - //Assign the mass to charge using nn density estimates - do - { - res=kdTree.findNearest(r,treeDomain,deadDistSqr); - - //Check to see if we found something - if(!res) - { -#pragma omp critical - badPts.push_back(make_pair(uj, ui)); - break; - } - - if(res->sqrDist(r) >maxSqrRad) - break; - numInRad++; - //Advance ever so slightly beyond the next ion - deadDistSqr = res->sqrDist(r)+std::numeric_limits::epsilon(); - //Update callback as needed - if(!curProg--) - { -#pragma omp critical - { - progress.filterProgress= (unsigned int)((float)n/(float)totalDataSize*100.0f); - if(!(*callback)(false)) - { -#ifdef _OPENMP - spin=true; -#else - delete newD; - return ABORT_ERR; -#endif - } - } -#ifdef _OPENMP - if(spin) - break; -#endif - curProg=NUM_CALLBACK/(10*nnMax); - } - }while(true); - - n++; - float density; - density = numInRad/vol; - - if(xorFunc((density <=densityCutoff), keepDensityUpper)) - { -#pragma omp critical - newD->data.push_back(d->data[uj]); - } - - } - -#ifdef _OPENMP - if(spin) - { - delete newD; - return ABORT_ERR; - } -#endif - } - else - { - //Should not get here. - ASSERT(false); - } - - - //move any bad points from the array to the end, then drop them - //To do this, we have to reverse sort the array, then - //swap the output ion vector entries with the end, - //then do a resize. - ComparePairFirst cmp; - badPts.sort(cmp); - badPts.reverse(); - - //Do some swappage - size_t pos=1; - for(std::list >::iterator it=badPts.begin(); it!=badPts.end();++it) - { - newD->data[(*it).first]=newD->data[newD->data.size()-pos]; - } - - //Trim the tail of bad points, leaving only good points - newD->data.resize(newD->data.size()-badPts.size()); - - - if(newD->data.size()) - { - //Use default colours - newD->r=d->r; - newD->g=d->g; - newD->b=d->b; - newD->a=d->a; - newD->ionSize=d->ionSize; - newD->representationType=d->representationType; - newD->valueType=TRANS("Number Density (\\#/Vol^3)"); - - //Cache result as needed - if(cache) - { - newD->cached=1; - filterOutputs.push_back(newD); - cacheOK=true; - } - else - newD->cached=0; - getOut.push_back(newD); - } - } - break; - default: - getOut.push_back(dataIn[ui]); - break; - } - } - //If we have bad points, let the user know. - if(!badPts.empty()) - { - std::string sizeStr; - stream_cast(sizeStr,badPts.size()); - consoleOutput.push_back(std::string(TRANS("Warning,")) + sizeStr + - TRANS(" points were un-analysable. These have been dropped")); - - //Print out a list of points if we can - - size_t maxPrintoutSize=std::min(badPts.size(),(size_t)200); - list >::iterator it; - it=badPts.begin(); - while(maxPrintoutSize--) - { - std::string s; - const IonStreamData *d; - d=((const IonStreamData *)dataIn[it->second]); - - Point3D getPos; - getPos= d->data[it->first].getPosRef(); - stream_cast(s,getPos); - consoleOutput.push_back(s); - ++it; - } - - if(badPts.size() > 200) - { - consoleOutput.push_back(TRANS("And so on...")); - } - - - } - } - - return 0; -} - -void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const -{ - FilterProperty p; - size_t curGroup=0; - - string tmpStr; - vector > choices; - - for(unsigned int ui=0;ui=ALGORITHM_ENUM_END) - return false; - - algorithm=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_STOPMODE: - { - switch(algorithm) - { - case ALGORITHM_DENSITY: - case ALGORITHM_DENSITY_FILTER: - case ALGORITHM_RDF: - { - size_t ltmp=STOP_MODE_ENUM_END; - - for(unsigned int ui=0;ui=STOP_MODE_ENUM_END) - return false; - - stopMode=ltmp; - needUpdate=true; - clearCache(); - break; - } - - - default: - //Should know what algorithm we use. - ASSERT(false); - break; - } - break; - } - case KEY_DISTMAX: - { - float ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp<= 0.0) - return false; - - distMax=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_NNMAX: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp==0) - return false; - - nnMax=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_NUMBINS: - { - unsigned int ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp==0) - return false; - - numBins=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_REDUCTIONDIST: - { - float ltmp; - if(stream_cast(ltmp,value)) - return false; - - if(ltmp<= 0.0) - return false; - - reductionDistance=ltmp; - needUpdate=true; - clearCache(); - - break; - } - case KEY_REMOVAL: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - bool lastVal=excludeSurface; - excludeSurface=(stripped=="1"); - - //if the result is different, the - //cache should be invalidated - if(lastVal!=excludeSurface) - { - needUpdate=true; - clearCache(); - } - - break; - } - case KEY_COLOUR: - { - unsigned char newR,newG,newB,newA; - - parseColString(value,newR,newG,newB,newA); - - if(newB != b || newR != r || - newG !=g || newA != a) - { - r=newR/255.0; - g=newG/255.0; - b=newB/255.0; - a=newA/255.0; - - if(cacheOK) - { - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - PlotStreamData *p; - p =(PlotStreamData*)filterOutputs[ui]; - - p->r=r; - p->g=g; - p->b=b; - } - } - - } - - needUpdate=true; - } - - - break; - } - case KEY_ENABLE_SOURCE: - { - ASSERT(haveRangeParent); - bool allEnabled=true; - for(unsigned int ui=0;ui=KEY_ENABLE_SOURCE*1000 && - key < KEY_ENABLE_TARGET*1000) - { - size_t offset; - offset = key-KEY_ENABLE_SOURCE*1000; - - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - bool lastVal = ionSourceEnabled[offset]; - - - if(stripped=="1") - ionSourceEnabled[offset]=true; - else - ionSourceEnabled[offset]=false; - - //if the result is different, the - //cache should be invalidated - if(lastVal!=ionSourceEnabled[offset]) - { - needUpdate=true; - clearCache(); - } - - - - } - else if ( key >=KEY_ENABLE_TARGET*1000) - { - size_t offset; - offset = key-KEY_ENABLE_TARGET*1000; - - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - bool lastVal = ionTargetEnabled[offset]; - - - if(stripped=="1") - ionTargetEnabled[offset]=true; - else - ionTargetEnabled[offset]=false; - - //if the result is different, the - //cache should be invalidated - if(lastVal!=ionTargetEnabled[offset]) - { - needUpdate=true; - clearCache(); - } - } - else - { - ASSERT(false); - } - - } - - } - return true; -} - - -std::string SpatialAnalysisFilter::getErrString(unsigned int code) const -{ - //Currently the only error is aborting - - - switch(code) - { - case ABORT_ERR: - return std::string(TRANS("Spatial analysis aborted by user")); - case INSUFFICIENT_SIZE_ERR: - return std::string(TRANS("Insufficient data to complete analysis.")); - default: - ASSERT(false); - - } - - return std::string("Bug! (Spatial analysis filter) Shouldn't see this"); -} - -unsigned int SpatialAnalysisFilter::getRefreshBlockMask() const -{ - //Anything but ions and ranges can go through this filter. - if(!WANT_RANGE_PROPAGATION[algorithm]) - return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; - else - return STREAM_TYPE_IONS; - -} - -unsigned int SpatialAnalysisFilter::getRefreshEmitMask() const -{ - if(algorithm == ALGORITHM_RDF) - return STREAM_TYPE_IONS | STREAM_TYPE_PLOT; - else - return STREAM_TYPE_IONS; -} - -unsigned int SpatialAnalysisFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS; -} - -bool SpatialAnalysisFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" <" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool SpatialAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - using std::string; - string tmpStr; - - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - //Retrieve algorithm - //====== - if(!XMLGetNextElemAttrib(nodePtr,algorithm,"algorithm","value")) - return false; - if(algorithm >=ALGORITHM_ENUM_END) - return false; - //=== - - //Retrieve stop mode - //=== - if(!XMLGetNextElemAttrib(nodePtr,stopMode,"stopmode","value")) - return false; - if(stopMode >=STOP_MODE_ENUM_END) - return false; - //=== - - //Retrieve nnMax val - //====== - if(!XMLGetNextElemAttrib(nodePtr,nnMax,"nnmax","value")) - return false; - if(!nnMax) - return false; - //=== - - //Retrieve distMax val - //====== - if(!XMLGetNextElemAttrib(nodePtr,distMax,"distmax","value")) - return false; - if(distMax <=0.0) - return false; - //=== - - //Retrieve numBins val - //====== - if(!XMLGetNextElemAttrib(nodePtr,numBins,"numbins","value")) - return false; - if(!numBins) - return false; - //=== - - //Retreive exclude surface on/off - //=== - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"excludesurface","value")) - return false; - //check that new value makes sense - if(tmpStr == "1") - excludeSurface=true; - else if( tmpStr == "0") - excludeSurface=false; - else - return false; - //=== - - - //Get reduction distance - //=== - if(!XMLGetNextElemAttrib(nodePtr,reductionDistance,"reductiondistance","value")) - return false; - if(reductionDistance < 0.0f) - return false; - //=== - - //Retrieve colour - //==== - if(XMLHelpFwdToElem(nodePtr,"colour")) - return false; - if(!parseXMLColour(nodePtr,r,g,b,a)) - return false; - //==== - - - //Retrieve density cutoff & upper - if(!XMLGetNextElemAttrib(nodePtr,densityCutoff,"densitycutoff","value")) - return false; - if(densityCutoff< 0.0f) - return false; - - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"keepdensityupper","value")) - return false; - //check that new value makes sense - if(tmpStr == "1") - keepDensityUpper=true; - else if( tmpStr == "0") - keepDensityUpper=false; - else - return false; - - - return true; -} - - -#ifdef DEBUG - -bool densityPairTest(); -bool nnHistogramTest(); -bool rdfPlotTest(); - -bool SpatialAnalysisFilter::runUnitTests() -{ - if(!densityPairTest()) - return false; - - if(!nnHistogramTest()) - return false; - - if(!rdfPlotTest()) - return false; - - return true; -} - - -bool densityPairTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - - - IonStreamData*d = new IonStreamData; - IonHit h; - h.setMassToCharge(1); - - //create two points, 1 unit apart - h.setPos(Point3D(0,0,0)); - d->data.push_back(h); - - h.setPos(Point3D(0,0,1)); - d->data.push_back(h); - - streamIn.push_back(d); - //--------- - - //Create a spatial analysis filter - SpatialAnalysisFilter *f=new SpatialAnalysisFilter; - f->setCaching(false); - //Set it to do an NN terminated density computation - bool needUp; - string s; - stream_cast(s,STOP_MODES[STOP_MODE_NEIGHBOUR]); - f->setProperty(KEY_STOPMODE,s,needUp); - stream_cast(s,SPATIAL_ALGORITHMS[ALGORITHM_DENSITY]); - f->setProperty(KEY_ALGORITHM,s,needUp); - - - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK"); - delete f; - //Kill the input ion stream - delete d; - streamIn.clear(); - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - - const IonStreamData* dOut = (const IonStreamData*)streamOut[0]; - - TEST(dOut->data.size() == 2, "ion count"); - - for(unsigned int ui=0;ui<2;ui++) - { - TEST( fabs( dOut->data[0].getMassToCharge() - 1.0/(4.0/3.0*M_PI)) - < sqrt(std::numeric_limits::epsilon()),"NN density test"); - } - - - delete streamOut[0]; - - return true; -} - -bool nnHistogramTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - - - IonStreamData*d = new IonStreamData; - IonHit h; - h.setMassToCharge(1); - - //create two points, 1 unit apart - h.setPos(Point3D(0,0,0)); - d->data.push_back(h); - - h.setPos(Point3D(0,0,1)); - d->data.push_back(h); - - streamIn.push_back(d); - - //Create a spatial analysis filter - SpatialAnalysisFilter *f=new SpatialAnalysisFilter; - f->setCaching(false); - //Set it to do an NN terminated density computation - bool needUp; - TEST(f->setProperty(KEY_STOPMODE, - STOP_MODES[STOP_MODE_NEIGHBOUR],needUp),"set stop mode"); - TEST(f->setProperty(KEY_ALGORITHM, - SPATIAL_ALGORITHMS[ALGORITHM_RDF],needUp),"set Algorithm"); - TEST(f->setProperty(KEY_NNMAX,"1",needUp),"Set NNmax"); - - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK"); - delete f; - - streamIn.clear(); - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_PLOT,"plot outputting"); - const PlotStreamData* dPlot=(const PlotStreamData *)streamOut[0]; - - - float fMax=0; - for(size_t ui=0;uixyData.size();ui++) - { - fMax=std::max(fMax,dPlot->xyData[ui].second); - } - - TEST(fMax > 0 , "plot has nonzero contents"); - //Kill the input ion stream - delete d; - - delete dPlot; - - return true; -} - -bool rdfPlotTest() -{ - //Build some points to pass to the filter - vector streamIn,streamOut; - - IonStreamData*d = new IonStreamData; - IonHit h; - h.setMassToCharge(1); - - //create two points, 1 unit apart - h.setPos(Point3D(0,0,0)); - d->data.push_back(h); - - h.setPos(Point3D(0,0,1)); - d->data.push_back(h); - - streamIn.push_back(d); - - //Create a spatial analysis filter - SpatialAnalysisFilter *f=new SpatialAnalysisFilter; - f->setCaching(false); - //Set it to do an NN terminated density computation - bool needUp; - TEST(f->setProperty(KEY_STOPMODE, - STOP_MODES[STOP_MODE_RADIUS],needUp),"set stop mode"); - TEST(f->setProperty(KEY_ALGORITHM, - SPATIAL_ALGORITHMS[ALGORITHM_RDF],needUp),"set Algorithm"); - TEST(f->setProperty(KEY_DISTMAX,"2",needUp),"Set NNmax"); - - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK"); - delete f; - - - streamIn.clear(); - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_PLOT,"plot outputting"); - const PlotStreamData* dPlot=(const PlotStreamData *)streamOut[0]; - - - float fMax=0; - for(size_t ui=0;uixyData.size();ui++) - { - fMax=std::max(fMax,dPlot->xyData[ui].second); - } - - TEST(fMax > 0 , "plot has nonzero contents"); - - - //kill output data - delete dPlot; - - //Kill the input ion stream - delete d; - - return true; -} - - -#endif - diff -Nru 3depict-0.0.12/src/filters/spatialAnalysis.h 3depict-0.0.13/src/filters/spatialAnalysis.h --- 3depict-0.0.12/src/filters/spatialAnalysis.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/spatialAnalysis.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -#ifndef SPATIALANALYSIS_H -#define SPATIALANALYSIS_H -#include "../filter.h" -#include "../translation.h" - -//!Spatial analysis filter -class SpatialAnalysisFilter : public Filter -{ - private: - //!Colour to use for output plots - float r,g,b,a; - - //!Which algorithm to use - unsigned int algorithm; - - //!Stopping criterion - unsigned int stopMode; - - //!NN stopping criterion (max) - unsigned int nnMax; - - //!Distance maximum - float distMax; - - //!Do we have range data to use (is nonzero) - bool haveRangeParent; - //!The names of the incoming ions - std::vector ionNames; - //!Are the sources/targets enabled for a particular incoming range? - std::vector ionSourceEnabled,ionTargetEnabled; - - //RDF specific params - //-------- - //RDF bin count - unsigned int numBins; - - //!Optional convex hull reduction - bool excludeSurface; - - //!Surface reduction distance (convex hull) - float reductionDistance; - //-------- - - //Density filtering specific params - //------- - //Do we keep points with density >= cutoff (true), or - // points with density < cutoff (false) - bool keepDensityUpper; - - //Cutoff value when performing density filtering - float densityCutoff; - - //------- - - public: - SpatialAnalysisFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - - //!Initialise filter prior to tree propagation - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - - //!Returns -1, as range file cache size is dependant upon input. - virtual size_t numBytesForCache(size_t nObjects) const; - //!Returns FILTER_TYPE_SPATIAL_ANALYSIS - unsigned int getType() const { return FILTER_TYPE_SPATIAL_ANALYSIS;}; - //update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - //!Get the type string for this fitler - virtual std::string typeString() const { return std::string(TRANS("Spat. Analysis"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be possibly used during ::refresh - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; -#ifdef DEBUG - bool runUnitTests(); -#endif -}; - -#endif diff -Nru 3depict-0.0.12/src/filters/spectrumPlot.cpp 3depict-0.0.13/src/filters/spectrumPlot.cpp --- 3depict-0.0.12/src/filters/spectrumPlot.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/spectrumPlot.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,943 +0,0 @@ -#include "spectrumPlot.h" - -#include "../xmlHelper.h" -#include "../plot.h" - -#include "../translation.h" - -//!Error codes -enum -{ - SPECTRUM_BAD_ALLOC=1, - SPECTRUM_BAD_BINCOUNT, - SPECTRUM_ABORT_FAIL, -}; - -enum -{ - KEY_SPECTRUM_BINWIDTH, - KEY_SPECTRUM_AUTOEXTREMA, - KEY_SPECTRUM_MIN, - KEY_SPECTRUM_MAX, - KEY_SPECTRUM_LOGARITHMIC, - KEY_SPECTRUM_PLOTTYPE, - KEY_SPECTRUM_COLOUR -}; - -//Limit user to one :million: bins -const unsigned int SPECTRUM_MAX_BINS=1000000; - -const unsigned int SPECTRUM_AUTO_MAX_BINS=25000; - -SpectrumPlotFilter::SpectrumPlotFilter() -{ - minPlot=0; - maxPlot=150; - autoExtrema=true; - binWidth=0.5; - plotStyle=0; - logarithmic=1; - - //Default to blue plot - r=g=0; - b=a=1; -} - -Filter *SpectrumPlotFilter::cloneUncached() const -{ - SpectrumPlotFilter *p = new SpectrumPlotFilter(); - - p->minPlot=minPlot; - p->maxPlot=maxPlot; - p->binWidth=binWidth; - p->autoExtrema=autoExtrema; - p->r=r; - p->g=g; - p->b=b; - p->a=a; - p->plotStyle=plotStyle; - p->logarithmic = logarithmic; - - - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -//!Get approx number of bytes for caching output -size_t SpectrumPlotFilter::numBytesForCache(size_t nObjects) const -{ - //Check that we have good plot limits, and bin width. if not, we cannot estmate cache size - if(minPlot ==std::numeric_limits::max() || - maxPlot==-std::numeric_limits::max() || - binWidth < sqrt(std::numeric_limits::epsilon())) - { - return (size_t)(-1); - } - - return (size_t)((float)(maxPlot- minPlot)/(binWidth))*2*sizeof(float); -} - -unsigned int SpectrumPlotFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - - if(cacheOK) - { - //Only report the spectrum plot - for(unsigned int ui=0;ui::max(); - maxPlot =-std::numeric_limits::max(); - //Loop through each type of data - - unsigned int curProg=NUM_CALLBACK; - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - IonStreamData *ions; - ions = (IonStreamData *)dataIn[ui]; - for(unsigned int uj=0;ujdata.size(); uj++) - { - minPlot = std::min(minPlot, - ions->data[uj].getMassToCharge()); - maxPlot = std::max(maxPlot, - ions->data[uj].getMassToCharge()); - - - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - return SPECTRUM_ABORT_FAIL; - } - } - - } - - } - - //Check that the plot values hvae been set (ie not same as initial values) - if(minPlot !=std::numeric_limits::max() && - maxPlot!=-std::numeric_limits::max() ) - { - //push them out a bit to make the edges visible - maxPlot=maxPlot+1; - minPlot=minPlot-1; - } - - //Time to move to phase 2 - progress.step=2; - progress.stepName=TRANS("count"); - } - - - - double delta = ((double)maxPlot - (double)(minPlot))/(double)binWidth; - - - //Check that we have good plot limits. - if(minPlot ==std::numeric_limits::max() || - minPlot ==-std::numeric_limits::max() || - fabs(delta) > std::numeric_limits::max() || // Check for out-of-range - binWidth < sqrt(std::numeric_limits::epsilon()) ) - { - //If not, then simply set it to "1". - minPlot=0; maxPlot=1.0; binWidth=0.1; - } - - - - //Estimate number of bins in floating point, and check for potential overflow . - float tmpNBins = (float)((maxPlot-minPlot)/binWidth); - - //If using autoextrema, use a lower limit for max bins, - //as we may just hit a nasty data point - if(autoExtrema) - tmpNBins = std::min(SPECTRUM_AUTO_MAX_BINS,(unsigned int)tmpNBins); - else - tmpNBins = std::min(SPECTRUM_MAX_BINS,(unsigned int)tmpNBins); - - nBins = (unsigned int)tmpNBins; - - if (!nBins) - { - nBins = 10; - binWidth = (maxPlot-minPlot)/nBins; - } - } - - - PlotStreamData *d; - d=new PlotStreamData; - try - { - d->xyData.resize(nBins); - } - catch(std::bad_alloc) - { - - delete d; - return SPECTRUM_BAD_ALLOC; - } - - - d->r = r; - d->g = g; - d->b = b; - d->a = a; - - d->logarithmic=logarithmic; - d->plotStyle = plotStyle; - d->plotMode=PLOT_MODE_1D; - - d->index=0; - d->parent=this; - d->dataLabel = getUserString(); - d->yLabel= TRANS("Count"); - - //Check all the incoming ion data's type name - //and if it is all the same, use it for the plot X-axis - std::string valueName; - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *ionD; - ionD=(const IonStreamData *)dataIn[ui]; - if(!valueName.size()) - valueName=ionD->valueType; - else - { - if(ionD->valueType != valueName) - { - valueName=TRANS("Mixed data"); - break; - } - } - } - } - } - - d->xLabel=valueName; - - - //Look for any ranges in input stream, and add them to the plot - //while we are doing that, count the number of ions too - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_RANGE: - { - const RangeStreamData *rangeD; - rangeD=(const RangeStreamData *)dataIn[ui]; - for(unsigned int uj=0;ujrangeFile->getNumRanges();uj++) - { - unsigned int ionId; - ionId=rangeD->rangeFile->getIonID(uj); - //Only append the region if both the range - //and the ion are enabled - if((rangeD->enabledRanges)[uj] && - (rangeD->enabledIons)[ionId]) - { - //save the range as a "region" - d->regions.push_back(rangeD->rangeFile->getRange(uj)); - d->regionID.push_back(uj); - d->parent=this; - //FIXME: Const correctness - d->regionParent=(Filter*)rangeD->parent; - - RGBf colour; - //Use the ionID to set the range colouring - colour=rangeD->rangeFile->getColour(ionId); - - //push back the range colour - d->regionR.push_back(colour.red); - d->regionG.push_back(colour.green); - d->regionB.push_back(colour.blue); - } - } - break; - } - default: - break; - } - } - -#pragma omp parallel for - for(unsigned int ui=0;uixyData[ui].first = minPlot + ui*binWidth; - d->xyData[ui].second=0; - } - //Compute the plot bounds - d->autoSetHardBounds(); - //Limit them to 1.0 or greater (due to log) - d->hardMinY=std::min(1.0f,d->hardMaxY); - - - //Number of ions currently procesed - size_t n=0; - unsigned int curProg=NUM_CALLBACK; - //Loop through each type of data - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *ions; - ions = (const IonStreamData *)dataIn[ui]; - - - - //Sum the data bins as needed - for(unsigned int uj=0;ujdata.size(); uj++) - { - unsigned int bin; - bin = (unsigned int)((ions->data[uj].getMassToCharge()-minPlot)/binWidth); - //Dependant upon the bounds, - //actual data could be anywhere. - if( bin < d->xyData.size()) - d->xyData[bin].second++; - - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)(((float)(n)/((float)totalSize))*100.0f); - curProg=NUM_CALLBACK; - if(!(*callback)(false)) - { - delete d; - return SPECTRUM_ABORT_FAIL; - } - } - } - - break; - } - default: - //Don't propagate any type. - break; - } - - } - - if(cache) - { - d->cached=1; //IMPORTANT: cached must be set PRIOR to push back - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - - return 0; -} - -void SpectrumPlotFilter::getProperties(FilterPropGroup &propertyList) const -{ - - FilterProperty p; - size_t curGroup=0; - string str; - - stream_cast(str,binWidth); - p.name=TRANS("Bin width"); - p.data=str; - p.key=KEY_SPECTRUM_BINWIDTH; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Step size for spectrum"); - propertyList.addProperty(p,curGroup); - - if(autoExtrema) - str = "1"; - else - str = "0"; - - - p.name=TRANS("Auto Min/max"); - p.data=str; - p.key=KEY_SPECTRUM_AUTOEXTREMA; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Automatically compute spectrum upper and lower bound"); - propertyList.addProperty(p,curGroup); - - stream_cast(str,minPlot); - p.data=str; - p.name=TRANS("Min"); - p.key=KEY_SPECTRUM_MIN; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Starting position for spectrum"); - propertyList.addProperty(p,curGroup); - - stream_cast(str,maxPlot); - p.key=KEY_SPECTRUM_MAX; - p.name=TRANS("Max"); - p.data=str; - p.type=PROPERTY_TYPE_REAL; - p.helpText=TRANS("Ending position for spectrum"); - propertyList.addProperty(p,curGroup); - - if(logarithmic) - str = "1"; - else - str = "0"; - p.key=KEY_SPECTRUM_LOGARITHMIC; - p.name=TRANS("Logarithmic"); - p.data=str; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Convert the plot to logarithmic mode"); - propertyList.addProperty(p,curGroup); - - //Let the user know what the valid values for plot type are - vector > choices; - - - string tmpStr; - tmpStr=plotString(PLOT_TRACE_LINES); - choices.push_back(make_pair((unsigned int) PLOT_TRACE_LINES,tmpStr)); - tmpStr=plotString(PLOT_TRACE_BARS); - choices.push_back(make_pair((unsigned int)PLOT_TRACE_BARS,tmpStr)); - tmpStr=plotString(PLOT_TRACE_STEPS); - choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEPS,tmpStr)); - tmpStr=plotString(PLOT_TRACE_STEM); - choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEM,tmpStr)); - - - tmpStr= choiceString(choices,plotStyle); - p.name=TRANS("Plot Type"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_CHOICE; - p.helpText=TRANS("Visual style of plot"); - p.key=KEY_SPECTRUM_PLOTTYPE; - propertyList.addProperty(p,curGroup); - - string thisCol; - - //Convert the colour to a hex string - genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0), - (unsigned char)(b*255.0),(unsigned char)(a*255.0),thisCol); - - p.name=TRANS("Colour"); - p.data=thisCol; - p.type=PROPERTY_TYPE_COLOUR; - p.helpText=TRANS("Colour of plotted spectrum"); - p.key=KEY_SPECTRUM_COLOUR; - propertyList.addProperty(p,curGroup); -} - -bool SpectrumPlotFilter::setProperty( unsigned int key, - const std::string &value, bool &needUpdate) -{ - needUpdate=false; - switch(key) - { - //Bin width - case KEY_SPECTRUM_BINWIDTH: - { - float newWidth; - if(stream_cast(newWidth,value)) - return false; - - if(newWidth < std::numeric_limits::epsilon()) - return false; - - //Prevent overflow on next line - if(maxPlot == std::numeric_limits::max() || - minPlot == std::numeric_limits::min()) - return false; - - if(newWidth < 0.0f || newWidth > (maxPlot - minPlot)) - return false; - - - - needUpdate=true; - binWidth=newWidth; - clearCache(); - - break; - } - //Auto min/max - case KEY_SPECTRUM_AUTOEXTREMA: - { - //Only allow valid values - unsigned int valueInt; - if(stream_cast(valueInt,value)) - return false; - - //Only update as needed - if(valueInt ==0 || valueInt == 1) - { - if((int)autoExtrema != valueInt) - { - needUpdate=true; - autoExtrema=valueInt; - } - else - needUpdate=false; - - } - else - return false; - - clearCache(); - - break; - - } - //Plot min - case KEY_SPECTRUM_MIN: - { - if(autoExtrema) - return false; - - float newMin; - if(stream_cast(newMin,value)) - return false; - - if(newMin >= maxPlot) - return false; - - needUpdate=true; - minPlot=newMin; - - clearCache(); - break; - } - //Plot max - case KEY_SPECTRUM_MAX: - { - if(autoExtrema) - return false; - float newMax; - if(stream_cast(newMax,value)) - return false; - - if(newMax <= minPlot) - return false; - - needUpdate=true; - maxPlot=newMax; - clearCache(); - - break; - } - case KEY_SPECTRUM_LOGARITHMIC: - { - //Only allow valid values - unsigned int valueInt; - if(stream_cast(valueInt,value)) - return false; - - //Only update as needed - if(valueInt ==0 || valueInt == 1) - { - if((int)logarithmic != valueInt) - { - needUpdate=true; - logarithmic=valueInt; - } - else - needUpdate=false; - - } - else - return false; - - if(cacheOK) - { - //Change the output of the plot streams that - //we cached, in order to avoid recomputation - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - PlotStreamData *p; - p =(PlotStreamData*)filterOutputs[ui]; - - p->logarithmic=logarithmic; - } - } - - } - - break; - - } - //Plot type - case KEY_SPECTRUM_PLOTTYPE: - { - unsigned int tmpPlotType; - - tmpPlotType=plotID(value); - - if(tmpPlotType >= PLOT_TRACE_ENDOFENUM) - return false; - - plotStyle = tmpPlotType; - needUpdate=true; - - - //Perform introspection on - //cache - if(cacheOK) - { - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - PlotStreamData *p; - p =(PlotStreamData*)filterOutputs[ui]; - - p->plotStyle=plotStyle; - } - } - - } - - break; - } - case KEY_SPECTRUM_COLOUR: - { - unsigned char newR,newG,newB,newA; - - parseColString(value,newR,newG,newB,newA); - - if(newB != b || newR != r || - newG !=g || newA != a) - needUpdate=true; - r=newR/255.0; - g=newG/255.0; - b=newB/255.0; - a=newA/255.0; - if(cacheOK) - { - for(size_t ui=0;uigetStreamType() == STREAM_TYPE_PLOT) - { - PlotStreamData *p; - p =(PlotStreamData*)filterOutputs[ui]; - - p->r=r; - p->g=g; - p->b=b; - } - } - - } - break; - } - default: - ASSERT(false); - break; - - } - - - return true; -} - -void SpectrumPlotFilter::setUserString(const std::string &s) -{ - if(userString !=s) - { - userString=s; - clearCache(); - cacheOK=false; - } -} - - -std::string SpectrumPlotFilter::getErrString(unsigned int code) const -{ - switch(code) - { - case SPECTRUM_BAD_ALLOC: - return string(TRANS("Insufficient memory for spectrum filter.")); - case SPECTRUM_BAD_BINCOUNT: - return string(TRANS("Bad bincount value in spectrum filter.")); - } - return std::string("BUG: (SpectrumPlotFilter::getErrString) Shouldn't see this!"); -} - -bool SpectrumPlotFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" <" << endl; - - f << tabs(depth+1) << "" << endl; - - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool SpectrumPlotFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - using std::string; - string tmpStr; - - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - //Retrieve Extrema - //=== - float tmpMin,tmpMax; - if(XMLHelpFwdToElem(nodePtr,"extrema")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"min"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //convert from string to digit - if(stream_cast(tmpMin,tmpStr)) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"max"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //convert from string to digit - if(stream_cast(tmpMax,tmpStr)) - return false; - - - if(tmpMin >=tmpMax) - return false; - - minPlot=tmpMin; - maxPlot=tmpMax; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"auto"); - if(!xmlString) - return false; - - tmpStr=(char *)xmlString; - if(tmpStr == "1") - autoExtrema=true; - else if(tmpStr== "0") - autoExtrema=false; - else - { - xmlFree(xmlString); - return false; - } - - xmlFree(xmlString); - //=== - - //Retrieve bin width - //==== - // - if(!XMLGetNextElemAttrib(nodePtr,binWidth,"binwidth","value")) - return false; - if(binWidth <= 0.0) - return false; - - if(!autoExtrema && binWidth > maxPlot - minPlot) - return false; - //==== - //Retrieve colour - //==== - if(XMLHelpFwdToElem(nodePtr,"colour")) - return false; - if(!parseXMLColour(nodePtr,r,g,b,a)) - return false; - //==== - - //Retrieve logarithmic mode - //==== - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"logarithmic","value")) - return false; - if(tmpStr == "0") - logarithmic=false; - else if(tmpStr == "1") - logarithmic=true; - else - return false; - //==== - - //Retrieve plot type - //==== - if(!XMLGetNextElemAttrib(nodePtr,plotStyle,"plottype","value")) - return false; - if(plotStyle >= PLOT_TRACE_ENDOFENUM) - return false; - //==== - - return true; -} - -unsigned int SpectrumPlotFilter::getRefreshBlockMask() const -{ - //Absolutely nothing can go through this filter. - return STREAMTYPE_MASK_ALL; -} - -unsigned int SpectrumPlotFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_PLOT; -} - -unsigned int SpectrumPlotFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS; -} - -#ifdef DEBUG - -IonStreamData *synDataPoints(const unsigned int span[], unsigned int numPts) -{ - IonStreamData *d = new IonStreamData; - - for(unsigned int ui=0;uidata.push_back(h); - } - - return d; -} - -bool countTest() -{ - IonStreamData* d; - const unsigned int VOL[]={ - 10,10,10 - }; - const unsigned int NUMPTS=100; - d = synDataPoints(VOL,NUMPTS); - - SpectrumPlotFilter *f; - f = new SpectrumPlotFilter; - - - bool needUp; - std::string s; - f->setProperty(KEY_SPECTRUM_LOGARITHMIC,"0",needUp); - - genColString(255,0,0,s); - f->setProperty(KEY_SPECTRUM_COLOUR,s,needUp); - - vector streamIn,streamOut; - - streamIn.push_back(d); - - //OK, so now do the rotation - //Do the refresh - ProgressData p; - f->setCaching(false); - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - delete f; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_PLOT,"stream type"); - - PlotStreamData *plot; - plot = (PlotStreamData*)streamOut[0]; - - - //Check the plot colour is what we want. - TEST(fabs(plot->r -1.0f) < sqrt(std::numeric_limits::epsilon()),"colour (r)"); - TEST(plot->g< - sqrt(std::numeric_limits::epsilon()),"colour (g)"); - TEST(plot->b < sqrt(std::numeric_limits::epsilon()),"colour (b)"); - - //Count the number of ions in the plot, and check that it is equal to the number of ions we put in. - float sumV=0; - - for(unsigned int ui=0;uixyData.size();ui++) - sumV+=plot->xyData[ui].second; - - TEST(fabs(sumV - (float)NUMPTS) < - std::numeric_limits::epsilon(),"ion count"); - - - delete plot; - delete d; - return true; -} - -bool SpectrumPlotFilter::runUnitTests() -{ - if(!countTest()) - return false; - - return true; -} - -#endif - diff -Nru 3depict-0.0.12/src/filters/spectrumPlot.h 3depict-0.0.13/src/filters/spectrumPlot.h --- 3depict-0.0.12/src/filters/spectrumPlot.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/spectrumPlot.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -#ifndef SPECTRUMPLOT_H -#define SPECTRUMPLOT_H -#include "../filter.h" -#include "../translation.h" - - -//!Spectrum plot filter -class SpectrumPlotFilter : public Filter -{ - private: - float minPlot,maxPlot; - float binWidth; - bool autoExtrema; - bool logarithmic; - - - //Vector of spectra. Each spectra is comprised of a sorted Y data - std::vector< std::vector > spectraCache; - float r,g,b,a; - unsigned int plotStyle; - public: - SpectrumPlotFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - //!Returns FILTER_TYPE_SPECTRUMPLOT - unsigned int getType() const { return FILTER_TYPE_SPECTRUMPLOT;}; - - //!Get approx number of bytes for caching output - size_t numBytesForCache(size_t nObjects) const; - - //!update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - virtual std::string typeString() const { return std::string(TRANS("Spectrum"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter. Returns true if prop set OK - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Set the user string. - void setUserString(const std::string &s); - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, unsigned int depth=0) const; - - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be possibly used during ::refresh - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b) {ASSERT(false);} ; - -#ifdef DEBUG - bool runUnitTests() ; - -#endif -}; - -#endif - diff -Nru 3depict-0.0.12/src/filters/transform.cpp 3depict-0.0.13/src/filters/transform.cpp --- 3depict-0.0.12/src/filters/transform.cpp 2012-11-18 00:43:41.000000000 +0000 +++ 3depict-0.0.13/src/filters/transform.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2028 +0,0 @@ -#include "transform.h" - -#include "../xmlHelper.h" - -#include "../translation.h" - -#include - -enum -{ - KEY_MODE, - KEY_SCALEFACTOR, - KEY_ORIGIN, - KEY_TRANSFORM_SHOWORIGIN, - KEY_ORIGINMODE, - KEY_NOISELEVEL, - KEY_NOISETYPE, - KEY_ROTATE_ANGLE, - KEY_ROTATE_AXIS, - KEY_ORIGIN_VALUE -}; - -//Possible transform modes (scaling, rotation etc) -enum -{ - MODE_TRANSLATE, - MODE_SCALE, - MODE_ROTATE, - MODE_VALUE_SHUFFLE, - MODE_SPATIAL_NOISE, - MODE_TRANSLATE_VALUE, - MODE_ENUM_END -}; - -//!Possible mode for selection of origin in transform filter -enum -{ - ORIGINMODE_SELECT, - ORIGINMODE_CENTREBOUND, - ORIGINMODE_MASSCENTRE, - ORIGINMODE_END, // Not actually origin mode, just end of enum -}; - -//!Possible noise modes -enum -{ - NOISETYPE_GAUSSIAN, - NOISETYPE_WHITE, - NOISETYPE_END -}; - -//!Error codes -enum -{ - ERR_CALLBACK_FAIL=1, - ERR_NOMEM -}; - -const char *TRANSFORM_MODE_STRING[] = { NTRANS("Translate"), - NTRANS("Scale"), - NTRANS("Rotate"), - NTRANS("Value Shuffle"), - NTRANS("Spatial Noise"), - NTRANS("Translate Value") - }; - -const char *TRANSFORM_ORIGIN_STRING[]={ - NTRANS("Specify"), - NTRANS("Boundbox Centre"), - NTRANS("Mass Centre") - }; - - - -//=== Transform filter === -TransformFilter::TransformFilter() -{ - COMPILE_ASSERT(ARRAYSIZE(TRANSFORM_MODE_STRING) == MODE_ENUM_END); - COMPILE_ASSERT(ARRAYSIZE(TRANSFORM_ORIGIN_STRING) == ORIGINMODE_END); - - randGen.initTimer(); - transformMode=MODE_TRANSLATE; - originMode=ORIGINMODE_SELECT; - noiseType=NOISETYPE_WHITE; - //Set up default value - vectorParams.resize(1); - vectorParams[0] = Point3D(0,0,0); - - showPrimitive=true; - showOrigin=false; - - cacheOK=false; - cache=false; -} - -Filter *TransformFilter::cloneUncached() const -{ - TransformFilter *p=new TransformFilter(); - - //Copy the values - p->vectorParams.resize(vectorParams.size()); - p->scalarParams.resize(scalarParams.size()); - - std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin()); - std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin()); - - p->showPrimitive=showPrimitive; - p->originMode=originMode; - p->transformMode=transformMode; - p->showOrigin=showOrigin; - p->noiseType=noiseType; - //We are copying wether to cache or not, - //not the cache itself - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -size_t TransformFilter::numBytesForCache(size_t nObjects) const -{ - //Say we don't know, we are not going to cache anyway. - return (size_t)-1; -} - -DrawStreamData* TransformFilter::makeMarkerSphere(SelectionDevice* &s) const -{ - //construct a new primitive, do not cache - DrawStreamData *drawData=new DrawStreamData; - drawData->parent=this; - //Add drawable components - DrawSphere *dS = new DrawSphere; - dS->setOrigin(vectorParams[0]); - dS->setRadius(1); - //FIXME: Alpha blending is all screwed up. May require more - //advanced drawing in scene. (front-back drawing). - //I have set alpha=1 for now. - dS->setColour(0.2,0.2,0.8,1.0); - dS->setLatSegments(40); - dS->setLongSegments(40); - dS->wantsLight=true; - drawData->drawables.push_back(dS); - - s=0; - //Set up selection "device" for user interaction - //Note the order of s->addBinding is critical, - //as bindings are selected by first match. - //==== - //The object is selectable - if (originMode == ORIGINMODE_SELECT ) - { - dS->canSelect=true; - - s=new SelectionDevice(this); - SelectionBinding b; - - b.setBinding(SELECT_BUTTON_LEFT,FLAG_CMD,DRAW_SPHERE_BIND_ORIGIN, - BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS); - b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE); - s->addBinding(b); - - } - drawData->cached=0; - - return drawData; -} - -unsigned int TransformFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - //Clear selection devices FIXME: Is this a memory leak??? - clearDevices(); - //use the cached copy if we have it. - if(cacheOK) - { - ASSERT(filterOutputs.size()); - for(unsigned int ui=0;uigetStreamType() != STREAM_TYPE_IONS) - getOut.push_back(dataIn[ui]); - } - - for(unsigned int ui=0;ui *s; - getOut.push_back(makeMarkerSphere(s)); - if(s) - devices.push_back(s); - } - - } - - return 0; - } - - - //The user is allowed to choose the mode by which the origin is computed - //so set the origin variable depending upon this - switch(originMode) - { - case ORIGINMODE_CENTREBOUND: - { - BoundCube masterB; - masterB.setInverseLimits(); - #pragma omp parallel for - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - const IonStreamData* ions; - ions = (const IonStreamData*)dataIn[ui]; - if(ions->data.size()) - { - thisB = getIonDataLimits(ions->data); - #pragma omp critical - masterB.expand(thisB); - } - } - } - - if(!masterB.isValid()) - vectorParams[0]=Point3D(0,0,0); - else - vectorParams[0]=masterB.getCentroid(); - break; - } - case ORIGINMODE_MASSCENTRE: - { - Point3D massCentre(0,0,0); - size_t numCentres=0; - #pragma omp parallel for - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_IONS) - { - const IonStreamData* ions; - ions = (const IonStreamData*)dataIn[ui]; - - if(ions->data.size()) - { - Point3D thisCentre; - thisCentre=Point3D(0,0,0); - for(unsigned int uj=0;ujdata.size();uj++) - thisCentre+=ions->data[uj].getPosRef(); - massContrib=thisCentre*1.0/(float)ions->data.size(); - #pragma omp critical - massCentre+=massContrib; - numCentres++; - } - } - } - vectorParams[0]=massCentre*1.0/(float)numCentres; - break; - - } - case ORIGINMODE_SELECT: - break; - default: - ASSERT(false); - } - - //If the user is using a transform mode that requires origin selection - if(showOrigin && (transformMode == MODE_ROTATE || - transformMode == MODE_SCALE) ) - { - SelectionDevice *s; - getOut.push_back(makeMarkerSphere(s)); - if(s) - devices.push_back(s); - } - - //Apply the transformations to the incoming - //ion streams, generating new outgoing ion streams with - //the modified positions - size_t totalSize=numElements(dataIn); - if( transformMode != MODE_VALUE_SHUFFLE) - { - //Dont cross the streams. Why? It would be bad. - // - Im fuzzy on the whole good-bad thing, what do you mean bad?" - // - Every ion in the data body can be operated on independantly. - // - // OK, important safety tip. - for(unsigned int ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - //Set up scaling output ion stream - IonStreamData *d=new IonStreamData; - d->parent=this; - const IonStreamData *src = (const IonStreamData *)dataIn[ui]; - - try - { - d->data.resize(src->data.size()); - } - catch(std::bad_alloc) - { - delete d; - return ERR_NOMEM; - } - d->r = src->r; - d->g = src->g; - d->b = src->b; - d->a = src->a; - d->ionSize = src->ionSize; - d->valueType=src->valueType; - - ASSERT(src->data.size() <= totalSize); - unsigned int curProg=NUM_CALLBACK; -#ifdef _OPENMP - //Parallel version - bool spin=false; - #pragma omp parallel for shared(spin) - for(unsigned int ui=0;uidata.size();ui++) - { - unsigned int thisT=omp_get_thread_num(); - if(spin) - continue; - - if(!curProg--) - { - #pragma omp critical - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - } - - - if(thisT == 0) - { - if(!(*callback)(false)) - spin=true; - } - } - - - //set the position for the given ion - d->data[ui].setPos((src->data[ui].getPosRef() - origin)*scaleFactor+origin); - d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); - } - if(spin) - { - delete d; - return ERR_CALLBACK_FAIL; - } - -#else - //Single threaded version - size_t pos=0; - //Copy across the ions into the target - for(vector::const_iterator it=src->data.begin(); - it!=src->data.end(); ++it) - { - //set the position for the given ion - d->data[pos].setPos((it->getPosRef() - origin)*scaleFactor+origin); - d->data[pos].setMassToCharge(it->getMassToCharge()); - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - curProg=NUM_CALLBACK; - } - pos++; - } - - ASSERT(pos == d->data.size()); -#endif - ASSERT(d->data.size() == src->data.size()); - - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - break; - } - default: - //Just copy across the ptr, if we are unfamiliar with this type - getOut.push_back(dataIn[ui]); - break; - } - break; - } - case MODE_TRANSLATE: - { - //We are going to scale the incoming point data - //around the specified origin. - ASSERT(vectorParams.size() == 1); - ASSERT(scalarParams.size() == 0); - Point3D origin =vectorParams[0]; - size_t n=0; - switch(dataIn[ui]->getStreamType()) - { - case STREAM_TYPE_IONS: - { - //Set up scaling output ion stream - IonStreamData *d=new IonStreamData; - d->parent=this; - - const IonStreamData *src = (const IonStreamData *)dataIn[ui]; - try - { - d->data.resize(src->data.size()); - } - catch(std::bad_alloc) - { - delete d; - return ERR_NOMEM; - } - d->r = src->r; - d->g = src->g; - d->b = src->b; - d->a = src->a; - d->ionSize = src->ionSize; - d->valueType=src->valueType; - - ASSERT(src->data.size() <= totalSize); - unsigned int curProg=NUM_CALLBACK; -#ifdef _OPENMP - //Parallel version - bool spin=false; -#pragma omp parallel for shared(spin) - for(unsigned int ui=0;uidata.size();ui++) - { - unsigned int thisT=omp_get_thread_num(); - if(spin) - continue; - - if(!curProg--) - { -#pragma omp critical - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - } - - - if(thisT == 0) - { - if(!(*callback)(false)) - spin=true; - } - } - - - //set the position for the given ion - d->data[ui].setPos((src->data[ui].getPosRef() - origin)); - d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); - } - if(spin) - { - delete d; - return ERR_CALLBACK_FAIL; - } - -#else - //Single threaded version - size_t pos=0; - //Copy across the ions into the target - for(vector::const_iterator it=src->data.begin(); - it!=src->data.end(); ++it) - { - //set the position for the given ion - d->data[pos].setPos((it->getPosRef() - origin)); - d->data[pos].setMassToCharge(it->getMassToCharge()); - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - curProg=NUM_CALLBACK; - } - pos++; - } - ASSERT(pos == d->data.size()); -#endif - ASSERT(d->data.size() == src->data.size()); - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - break; - } - default: - //Just copy across the ptr, if we are unfamiliar with this type - getOut.push_back(dataIn[ui]); - break; - } - break; - } - case MODE_TRANSLATE_VALUE: - { - //We are going to scale the incoming point data - //around the specified origin. - ASSERT(vectorParams.size() == 0); - ASSERT(scalarParams.size() == 1); - float origin =scalarParams[0]; - size_t n=0; - switch(dataIn[ui]->getStreamType()) - { - case STREAM_TYPE_IONS: - { - //Set up scaling output ion stream - IonStreamData *d=new IonStreamData; - d->parent=this; - - const IonStreamData *src = (const IonStreamData *)dataIn[ui]; - try - { - d->data.resize(src->data.size()); - } - catch(std::bad_alloc) - { - delete d; - return ERR_NOMEM; - } - d->r = src->r; - d->g = src->g; - d->b = src->b; - d->a = src->a; - d->ionSize = src->ionSize; - d->valueType=src->valueType; - - ASSERT(src->data.size() <= totalSize); - unsigned int curProg=NUM_CALLBACK; -#ifdef _OPENMP - //Parallel version - bool spin=false; -#pragma omp parallel for shared(spin) - for(unsigned int ui=0;uidata.size();ui++) - { - unsigned int thisT=omp_get_thread_num(); - if(spin) - continue; - - if(!curProg--) - { -#pragma omp critical - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - } - - - if(thisT == 0) - { - if(!(*callback)(false)) - spin=true; - } - } - - - //set the position for the given ion - d->data[ui].setPos((src->data[ui].getPosRef())); - d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()+origin); - } - if(spin) - { - delete d; - return ERR_CALLBACK_FAIL; - } - -#else - //Single threaded version - size_t pos=0; - //Copy across the ions into the target - for(vector::const_iterator it=src->data.begin(); - it!=src->data.end(); ++it) - { - //set the position for the given ion - d->data[pos].setPos((it->getPosRef())); - d->data[pos].setMassToCharge(it->getMassToCharge() + origin); - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - curProg=NUM_CALLBACK; - } - pos++; - } - ASSERT(pos == d->data.size()); -#endif - ASSERT(d->data.size() == src->data.size()); - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - break; - } - default: - //Just copy across the ptr, if we are unfamiliar with this type - getOut.push_back(dataIn[ui]); - break; - } - break; - } - case MODE_ROTATE: - { - Point3D origin=vectorParams[0]; - switch(dataIn[ui]->getStreamType()) - { - case STREAM_TYPE_IONS: - { - - const IonStreamData *src = (const IonStreamData *)dataIn[ui]; - //Set up output ion stream - IonStreamData *d=new IonStreamData; - d->parent=this; - try - { - d->data.resize(src->data.size()); - } - catch(std::bad_alloc) - { - delete d; - return ERR_NOMEM; - } - d->r = src->r; - d->g = src->g; - d->b = src->b; - d->a = src->a; - d->ionSize = src->ionSize; - d->valueType=src->valueType; - - //We are going to rotate the incoming point data - //around the specified origin. - ASSERT(vectorParams.size() == 2); - ASSERT(scalarParams.size() == 1); - Point3D axis =vectorParams[1]; - axis.normalise(); - float angle=scalarParams[0]*M_PI/180.0f; - - unsigned int curProg=NUM_CALLBACK; - size_t n=0; - - Point3f rotVec,p; - rotVec.fx=axis[0]; - rotVec.fy=axis[1]; - rotVec.fz=axis[2]; - - Quaternion q1; - - //Generate the rotating quaternion - quat_get_rot_quat(&rotVec,-angle,&q1); - ASSERT(src->data.size() <= totalSize); - - - size_t pos=0; - - //TODO: Parallelise rotation - //Copy across the ions into the target - for(vector::const_iterator it=src->data.begin(); - it!=src->data.end(); ++it) - { - p.fx=it->getPosRef()[0]-origin[0]; - p.fy=it->getPosRef()[1]-origin[1]; - p.fz=it->getPosRef()[2]-origin[2]; - quat_rot_apply_quat(&p,&q1); - //set the position for the given ion - d->data[pos].setPos(p.fx+origin[0], - p.fy+origin[1],p.fz+origin[2]); - d->data[pos].setMassToCharge(it->getMassToCharge()); - //update progress every CALLBACK ions - if(!curProg--) - { - n+=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - curProg=NUM_CALLBACK; - } - pos++; - } - - ASSERT(d->data.size() == src->data.size()); - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - break; - } - default: - getOut.push_back(dataIn[ui]); - break; - } - - break; - } - case MODE_SPATIAL_NOISE: - { - ASSERT(scalarParams.size() ==1 && - vectorParams.size()==0); - switch(dataIn[ui]->getStreamType()) - { - case STREAM_TYPE_IONS: - { - //Set up scaling output ion stream - IonStreamData *d=new IonStreamData; - d->parent=this; - - const IonStreamData *src = (const IonStreamData *)dataIn[ui]; - try - { - d->data.resize(src->data.size()); - } - catch(std::bad_alloc) - { - delete d; - return ERR_NOMEM; - } - d->r = src->r; - d->g = src->g; - d->b = src->b; - d->a = src->a; - d->ionSize = src->ionSize; - d->valueType=src->valueType; - - float scaleFactor=scalarParams[0]; - ASSERT(src->data.size() <= totalSize); - unsigned int curProg=NUM_CALLBACK; - - //NOTE: This *cannot* be parallelised without parallelising the random - // number generator safely. If using multiple random number generators, - // one would need to ensure sufficient entropy in EACH generator. This - // is not trivial to prove, and so has not been done here. Bootstrapping - // each random number generator using non-random seeds could be problematic - // same as feeding back a random number into other rng instances - // - // One solution is to use the unix /dev/urandom interface or the windows - // cryptographic API, alternatively use the TR1 header's mersenne twister with - // multi-seeding: - // http://theo.phys.sci.hiroshima-u.ac.jp/~ishikawa/PRNG/mt_stream_en.html - switch(noiseType) - { - case NOISETYPE_WHITE: - { - for(size_t ui=0;uidata.size();ui++) - { - Point3D pt; - - pt.setValue(0,randGen.genUniformDev()-0.5f); - pt.setValue(1,randGen.genUniformDev()-0.5f); - pt.setValue(2,randGen.genUniformDev()-0.5f); - - pt*=scaleFactor; - - //set the position for the given ion - d->data[ui].setPos(src->data[ui].getPosRef() + pt); - d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); - - - if(!curProg--) - { - curProg=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(ui)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - } - } - break; - } - case NOISETYPE_GAUSSIAN: - { - for(size_t ui=0;uidata.size();ui++) - { - Point3D pt; - - pt.setValue(0,randGen.genGaussDev()); - pt.setValue(1,randGen.genGaussDev()); - pt.setValue(2,randGen.genGaussDev()); - - pt*=scaleFactor; - - //set the position for the given ion - d->data[ui].setPos(src->data[ui].getPosRef() + pt); - d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()); - - - if(!curProg--) - { - curProg=NUM_CALLBACK; - progress.filterProgress= (unsigned int)((float)(ui)/((float)totalSize)*100.0f); - if(!(*callback)(false)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - } - } - - break; - } - } - - ASSERT(d->data.size() == src->data.size()); - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - break; - } - default: - getOut.push_back(dataIn[ui]); - break; - } - break; - } - } - } - } - else - { - progress.step=1; - progress.filterProgress=0; - progress.stepName=TRANS("Collate"); - progress.maxStep=3; - if(!(*callback)(true)) - return ERR_CALLBACK_FAIL; - //we have to cross the streams (I thought that was bad?) - // - Each dataset is no longer independant, and needs to - // be mixed with the other datasets. Bugger; sounds mem. expensive. - - //Set up output ion stream - IonStreamData *d=new IonStreamData; - d->parent=this; - - //TODO: Better output colouring/size - //Set up ion metadata - d->r = 0.5; - d->g = 0.5; - d->b = 0.5; - d->a = 0.5; - d->ionSize = 2.0; - d->valueType=TRANS("Mass-to-Charge (amu/e)"); - - size_t curPos=0; - - vector massData; - - //TODO: Ouch. Memory intensive -- could do a better job - //of this? - try - { - massData.resize(totalSize); - d->data.resize(totalSize); - } - catch(std::bad_alloc) - { - return ERR_NOMEM; - } - - //merge the datasets - for(size_t ui=0;uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - - const IonStreamData *src = (const IonStreamData *)dataIn[ui]; - - //Loop through the ions in this stream, and copy its data value -#pragma omp parallel for shared(massData,d,curPos,src) - for(size_t uj=0;ujdata.size();uj++) - { - massData[uj+curPos] = src->data[uj].getMassToCharge(); - d->data[uj+curPos].setPos(src->data[uj].getPos()); - } - - if(!(*callback)(true)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - - curPos+=src->data.size(); - break; - } - default: - getOut.push_back(dataIn[ui]); - break; - } - } - - - progress.step=2; - progress.filterProgress=0; - progress.stepName=TRANS("Shuffle"); - if(!(*callback)(true)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - //Shuffle the value data.TODO: callback functor - std::random_shuffle(massData.begin(),massData.end()); - if(!(*callback)(true)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - - progress.step=3; - progress.filterProgress=0; - progress.stepName=TRANS("Splice"); - if(!(*callback)(true)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - - - - //Set the output data by splicing together the - //shuffled values and the original position info -#pragma omp parallel for shared(d,massData) - for(size_t uj=0;ujdata[uj].setMassToCharge(massData[uj]); - - if(!(*callback)(true)) - { - delete d; - return ERR_CALLBACK_FAIL; - } - - massData.clear(); - - if(cache) - { - d->cached=1; - filterOutputs.push_back(d); - cacheOK=true; - } - else - d->cached=0; - - getOut.push_back(d); - - } - return 0; -} - - -void TransformFilter::getProperties(FilterPropGroup &propertyList) const -{ - - FilterProperty p; - size_t curGroup=0; - string tmpStr; - vector > choices; - for(unsigned int ui=0;ui > choices; - for(unsigned int ui=0;ui::epsilon()) - return false; - - if(!(vectorParams[1] == newPt )) - { - vectorParams[1] = newPt; - needUpdate=true; - clearCache(); - } - - return true; - } - break; - case KEY_ORIGINMODE: - { - size_t i; - for (i = 0; i < MODE_ENUM_END; i++) - if (value == getOriginTypeString(i)) break; - - if( i == MODE_ENUM_END) - return false; - - if(originMode != i) - { - originMode = i; - needUpdate=true; - clearCache(); - } - return true; - } - case KEY_TRANSFORM_SHOWORIGIN: - { - string stripped=stripWhite(value); - - if(!(stripped == "1"|| stripped == "0")) - return false; - - showOrigin=(stripped=="1"); - - needUpdate=true; - - break; - } - case KEY_NOISETYPE: - { - size_t i; - for (i = 0; i < NOISETYPE_END; i++) - if (value == getNoiseTypeString(i)) break; - - if( i == NOISETYPE_END) - return false; - - if(noiseType != i) - { - noiseType = i; - needUpdate=true; - clearCache(); - } - break; - } - default: - ASSERT(false); - } - return true; -} - - -std::string TransformFilter::getErrString(unsigned int code) const -{ - - switch(code) - { - //User aborted in a callback - case ERR_CALLBACK_FAIL: - return std::string(TRANS("Aborted")); - //Caught a memory issue - case ERR_NOMEM: - return std::string(TRANS("Unable to allocate memory")); - } - ASSERT(false); -} - -bool TransformFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << ""<"<"<"<" << endl; - for(unsigned int ui=0; ui" << endl; - } - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - for(unsigned int ui=0; ui" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth) << "" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool TransformFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - std::string tmpStr; - //Retrieve transformation type - //==== - if(!XMLGetNextElemAttrib(nodePtr,transformMode,"transformmode","value")) - return false; - if(transformMode>= MODE_ENUM_END) - return false; - //==== - - //Retrieve origination type - //==== - if(!XMLGetNextElemAttrib(nodePtr,originMode,"originmode","value")) - return false; - if(originMode>= ORIGINMODE_END) - return false; - //==== - - //Retrieve origination type - //==== - if(!XMLGetNextElemAttrib(nodePtr,originMode,"noisetype","value")) - return false; - if(noiseType>= NOISETYPE_END) - return false; - //==== - - //Retrieve origination type - //==== - if(!XMLGetNextElemAttrib(nodePtr,originMode,"showorigin","value")) - return false; - //==== - - //Retreive vector parameters - //=== - if(XMLHelpFwdToElem(nodePtr,"vectorparams")) - return false; - xmlNodePtr tmpNode=nodePtr; - - nodePtr=nodePtr->xmlChildrenNode; - - vectorParams.clear(); - while(!XMLHelpFwdToElem(nodePtr,"point3d")) - { - float x,y,z; - //--Get X value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(x,tmpStr)) - return false; - - //--Get Z value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(y,tmpStr)) - return false; - - //--Get Y value-- - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(z,tmpStr)) - return false; - - vectorParams.push_back(Point3D(x,y,z)); - } - //=== - - nodePtr=tmpNode; - //Retreive scalar parameters - //=== - if(XMLHelpFwdToElem(nodePtr,"scalarparams")) - return false; - - tmpNode=nodePtr; - nodePtr=nodePtr->xmlChildrenNode; - - scalarParams.clear(); - while(!XMLHelpFwdToElem(nodePtr,"scalar")) - { - float v; - //Get value - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - xmlFree(xmlString); - - //Check it is streamable - if(stream_cast(v,tmpStr)) - return false; - scalarParams.push_back(v); - } - //=== - - //Check the scalar params match the selected primitive - switch(transformMode) - { - case MODE_TRANSLATE: - if(vectorParams.size() != 1 || scalarParams.size() !=0) - return false; - break; - case MODE_SCALE: - if(vectorParams.size() != 1 || scalarParams.size() !=1) - return false; - break; - case MODE_ROTATE: - if(vectorParams.size() != 2 || scalarParams.size() !=1) - return false; - break; - case MODE_TRANSLATE_VALUE: - if(vectorParams.size() != 0 || scalarParams.size() !=1) - return false; - break; - case MODE_VALUE_SHUFFLE: - case MODE_SPATIAL_NOISE: - break; - default: - ASSERT(false); - return false; - } - return true; -} - - -unsigned int TransformFilter::getRefreshBlockMask() const -{ - //Only ions cannot go through this filter. - return STREAM_TYPE_IONS; -} - -unsigned int TransformFilter::getRefreshEmitMask() const -{ - if(showPrimitive) - return STREAM_TYPE_IONS | STREAM_TYPE_DRAW; - else - return STREAM_TYPE_IONS; -} - -unsigned int TransformFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS; -} - -void TransformFilter::setPropFromBinding(const SelectionBinding &b) -{ - switch(b.getID()) - { - case BINDING_SPHERE_ORIGIN: - b.getValue(vectorParams[0]); - break; - default: - ASSERT(false); - } - clearCache(); -} - -std::string TransformFilter::getOriginTypeString(unsigned int i) -{ - ASSERT(ispan. -//span must be a 3-wide array, and numPts will be generated. -//each entry in the array should be coprime for optimal results. -//filter pointer must be deleted. -IonStreamData *synthDataPoints(unsigned int span[],unsigned int numPts); -bool rotateTest(); -bool translateTest(); -bool scaleTest(); -bool shuffleTest(); - - -class MassCompare -{ - public: - inline bool operator()(const IonHit &h1,const IonHit &h2) const - {return h1.getMassToCharge()data.push_back(h); - } - - return d; -} - -bool rotateTest() -{ - //Simulate some data to send to the filter - vector streamIn,streamOut; - IonStreamData *d= new IonStreamData; - - RandNumGen rng; - rng.initTimer(); - - const unsigned int NUM_PTS=10000; - - - //Build a sphere of data points - //by rejection method - d->data.reserve(NUM_PTS/2.0); - for(unsigned int ui=0;uidata.push_back(h); - } - } - - streamIn.push_back(d); - - //Set up the filter itself - //--- - TransformFilter *f=new TransformFilter; - f->setCaching(false); - - - bool needUp; - string s; - f->setProperty(KEY_MODE,TRANS(TRANSFORM_MODE_STRING[MODE_ROTATE]),needUp); - float tmpVal; - tmpVal=rng.genUniformDev()*M_PI*2.0; - stream_cast(s,tmpVal); - f->setProperty(KEY_ROTATE_ANGLE,s,needUp); - Point3D tmpPt; - - //NOTE: Technically there is a nonzero chance of this failing. - tmpPt=Point3D(rng.genUniformDev()-0.5f, - rng.genUniformDev()-0.5f, - rng.genUniformDev()-0.5f); - stream_cast(s,tmpPt); - f->setProperty(KEY_ROTATE_AXIS,s,needUp); - - f->setProperty(KEY_ORIGINMODE,TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE],needUp); - f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp); - //--- - - - //OK, so now do the rotation - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - delete f; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); - - const IonStreamData *outData=(IonStreamData*)streamOut[0]; - - Point3D massCentre[2]; - massCentre[0]=massCentre[1]=Point3D(0,0,0); - //Now check that the mass centre has not moved - for(unsigned int ui=0;uidata.size();ui++) - massCentre[0]+=d->data[ui].getPos(); - - for(unsigned int ui=0;uidata.size();ui++) - massCentre[1]+=outData->data[ui].getPos(); - - - TEST((massCentre[0]-massCentre[1]).sqrMag() < - 2.0*sqrt(std::numeric_limits::epsilon()),"mass centre invariance"); - - //Rotating a sphere around its centre of mass - // should not massively change the bounding box - // 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); - - float volumeRat; - volumeRat = bc[0].volume()/bc[1].volume(); - - TEST(volumeRat > 0.5f && volumeRat < 2.0f, "volume ratio test"); - - delete streamOut[0]; - delete d; - return true; -} - -bool translateTest() -{ - RandNumGen rng; - rng.initTimer(); - - //Simulate some data to send to the filter - vector streamIn,streamOut; - IonStreamData *d; - const unsigned int NUM_PTS=10000; - - unsigned int span[]={ - 5, 7, 9 - }; - d=synthDataPoints(span,NUM_PTS); - streamIn.push_back(d); - - Point3D offsetPt; - - //Set up the filter itself - //--- - TransformFilter *f=new TransformFilter; - - bool needUp; - string s; - f->setProperty(KEY_MODE,TRANSFORM_MODE_STRING[MODE_TRANSLATE],needUp); - - //NOTE: Technically there is a nonzero chance of this failing. - offsetPt=Point3D(rng.genUniformDev()-0.5f, - rng.genUniformDev()-0.5f, - rng.genUniformDev()-0.5f); - offsetPt[0]*=span[0]; - offsetPt[1]*=span[1]; - offsetPt[2]*=span[2]; - - stream_cast(s,offsetPt); - f->setProperty(KEY_ORIGIN,s,needUp); - f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp); - //--- - - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - delete f; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); - - const IonStreamData *outData=(IonStreamData*)streamOut[0]; - - //Bound cube should move exactly as per the translation - BoundCube bc[2]; - bc[0]=getIonDataLimits(d->data); - bc[1]=getIonDataLimits(outData->data); - - for(unsigned int ui=0;ui<3;ui++) - { - for(unsigned int uj=0;uj<2;uj++) - { - float f; - f=bc[0].getBound(ui,uj) -bc[1].getBound(ui,uj); - TEST(fabs(f-offsetPt[ui]) < sqrt(std::numeric_limits::epsilon()), "bound translation"); - } - } - - delete d; - delete streamOut[0]; - - return true; -} - - -bool scaleTest() -{ - //Simulate some data to send to the filter - vector streamIn,streamOut; - IonStreamData *d; - - RandNumGen rng; - rng.initTimer(); - - const unsigned int NUM_PTS=10000; - - unsigned int span[]={ - 5, 7, 9 - }; - d=synthDataPoints(span,NUM_PTS); - streamIn.push_back(d); - - //Set up the filter itself - //--- - TransformFilter *f=new TransformFilter; - - bool needUp; - string s; - //Switch to scale mode - f->setProperty(KEY_MODE, - TRANS(TRANSFORM_MODE_STRING[MODE_SCALE]),needUp); - - - //Switch to mass-centre origin - f->setProperty(KEY_ORIGINMODE, - TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp); - - float scaleFact; - //Pick some scale, both positive and negative. - if(rng.genUniformDev() > 0.5) - scaleFact=rng.genUniformDev()*10; - else - scaleFact=0.1f/(0.1f+rng.genUniformDev()); - - stream_cast(s,scaleFact); - - f->setProperty(KEY_SCALEFACTOR,s,needUp); - //Don't show origin marker - f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp); - //--- - - - //OK, so now do the rotation - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - delete f; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); - - const IonStreamData *outData=(IonStreamData*)streamOut[0]; - - //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); - - float cubeOfScale=scaleFact*scaleFact*scaleFact; - - float volumeDelta; - volumeDelta=fabs(bc[1].volume()/cubeOfScale - bc[0].volume() ); - - TEST(volumeDelta < 100.0f*sqrt(std::numeric_limits::epsilon()), "scaled volume test"); - - delete streamOut[0]; - delete d; - return true; -} - -bool shuffleTest() -{ - //Simulate some data to send to the filter - vector streamIn,streamOut; - IonStreamData *d; - - RandNumGen rng; - rng.initTimer(); - - const unsigned int NUM_PTS=1000; - - unsigned int span[]={ - 5, 7, 9 - }; - d=synthDataPoints(span,NUM_PTS); - streamIn.push_back(d); - - //Set up the filter itself - //--- - TransformFilter *f=new TransformFilter; - - bool needUp; - //Switch to shuffle mode - TEST(f->setProperty(KEY_MODE, - TRANS(TRANSFORM_MODE_STRING[MODE_VALUE_SHUFFLE]),needUp),"refresh error code"); - //--- - - - //OK, so now run the shuffle - //Do the refresh - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code"); - delete f; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type"); - TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); - - TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance"); - - IonStreamData *outData=(IonStreamData*)streamOut[0]; - - //Check to see that the output masses each exist in the input, - //but are not in the same sequence - //--- - - - bool sequenceDifferent=false; - for(size_t ui=0;uidata.size();ui++) - { - if(d->data[ui].getMassToCharge() != outData->data[ui].getMassToCharge()) - { - sequenceDifferent=true; - break; - } - } - TEST(sequenceDifferent, - "Should be shuffled - Prob. of sequence being identical in both orig & shuffled cases is very low"); - //Sort masses - MassCompare cmp; - std::sort(outData->data.begin(),outData->data.end(),cmp); - std::sort(d->data.begin(),d->data.end(),cmp); - - - for(size_t ui=0;uidata.size();ui++) - { - TEST(d->data[ui].getMassToCharge() == outData->data[ui].getMassToCharge(),"Shuffle + Sort mass should be the same"); - - } - - - - delete streamOut[0]; - delete d; - return true; -} - -#endif diff -Nru 3depict-0.0.12/src/filters/transform.h 3depict-0.0.13/src/filters/transform.h --- 3depict-0.0.12/src/filters/transform.h 2012-11-18 00:43:41.000000000 +0000 +++ 3depict-0.0.13/src/filters/transform.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -#ifndef TRANSFORM_H -#define TRANSFORM_H - -#include "../filter.h" -#include "../translation.h" - -//!Affine transformation filter -class TransformFilter : public Filter -{ - private: - //!Transform mode (scale, rotate, translate) - unsigned int transformMode; - - //!Show origin if needed; - bool showOrigin; - //!Mode for selection of origin for transform - unsigned int originMode; - //!Mode for particular noise type - unsigned int noiseType; - //!Scalar values for transformation (scaling factors, rotation angle ) - std::vector scalarParams; - //!Vector values for transformation (translation or rotation vectors) - std::vector vectorParams; - - //!Should we show the origin primitive markers? - bool showPrimitive; - - static std::string getOriginTypeString(unsigned int i); - - static std::string getNoiseTypeString(unsigned int i); - - //!Make the marker sphere - DrawStreamData* makeMarkerSphere(SelectionDevice* &s) const; - - //!random number generator - RandNumGen randGen; - public: - TransformFilter(); - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - - //!Returns -1, as range file cache size is dependant upon input. - virtual size_t numBytesForCache(size_t nObjects) const; - - - //!Returns FILTER_TYPE_TRANSFORM - unsigned int getType() const { return FILTER_TYPE_TRANSFORM;}; - //update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - //!Force a re-read of the rangefile Return value is range file reading error code - unsigned int updateRng(); - virtual std::string typeString() const { return std::string(TRANS("Ion. Transform"));}; - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshUseMask() const; - - //!Set internal property value using a selection binding (Disabled, this filter has no bindings) - void setPropFromBinding(const SelectionBinding &b); - -#ifdef DEBUG - bool runUnitTests(); -#endif -}; -#endif - diff -Nru 3depict-0.0.12/src/filters/voxelise.cpp 3depict-0.0.13/src/filters/voxelise.cpp --- 3depict-0.0.12/src/filters/voxelise.cpp 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/voxelise.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1675 +0,0 @@ - -#include "voxelise.h" -#include "../xmlHelper.h" - -#include "../translation.h" - -enum -{ - KEY_FIXEDWIDTH, - KEY_NBINSX, - KEY_NBINSY, - KEY_NBINSZ, - KEY_WIDTHBINSX, - KEY_WIDTHBINSY, - KEY_WIDTHBINSZ, - KEY_COUNT_TYPE, - KEY_NORMALISE_TYPE, - KEY_SPOTSIZE, - KEY_TRANSPARANCY, - KEY_COLOUR, - KEY_ISOLEVEL, - KEY_VOXEL_REPRESENTATION_MODE, - KEY_FILTER_MODE, - KEY_FILTER_BOUNDARY_MODE, - KEY_FILTER_BINS, - KEY_ENABLE_NUMERATOR, - KEY_ENABLE_DENOMINATOR -}; - -//!Normalisation method -enum -{ - VOXELISE_NORMALISETYPE_NONE,// straight count - VOXELISE_NORMALISETYPE_VOLUME,// density - VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL, // concentration - VOXELISE_NORMALISETYPE_COUNT2INVOXEL,// ratio count1/count2 - VOXELISE_NORMALISETYPE_MAX // keep this at the end so it's a bookend for the last value -}; - -//!Filtering mode -enum -{ - VOXELISE_FILTERTYPE_NONE, - VOXELISE_FILTERTYPE_GAUSS, - VOXELISE_FILTERTYPE_MAX // keep this at the end so it's a bookend for the last value -}; - - -//Boundary behaviour for filtering -enum -{ - VOXELISE_FILTERBOUNDMODE_ZERO, - VOXELISE_FILTERBOUNDMODE_BOUNCE, - VOXELISE_FILTERBOUNDMODE_MAX// keep this at the end so it's a bookend for the last value -}; - -enum -{ - VOXELISE_ABORT_ERR, - VOXELISE_MEMORY_ERR, - VOXELISE_CONVOLVE_ERR, - VOXELISE_BOUNDS_INVALID_ERR -}; - -const char *NORMALISE_TYPE_STRING[] = { - NTRANS("None (Raw count)"), - NTRANS("Volume (Density)"), - NTRANS("All Ions (conc)"), - NTRANS("Ratio (Num/Denom)"), - }; - -const char *REPRESENTATION_TYPE_STRING[] = { - NTRANS("Point Cloud"), - NTRANS("Isosurface") - }; - -const char *VOXELISE_FILTER_TYPE_STRING[]={ - NTRANS("None"), - NTRANS("Gaussian (2𝜎)"), - }; - -const char *VOXELISE_FILTER_BOUND_STRING[] ={ - NTRANS("Zero"), - NTRANS("Bounce") - }; - -//This is not a member of voxels.h, as the voxels do not have any concept of the IonHit -int countPoints(Voxels &v, const std::vector &points, - bool noWrap,bool (*callback)(bool)) -{ - - size_t x,y,z; - size_t binCount[3]; - v.getSize(binCount[0],binCount[1],binCount[2]); - - unsigned int downSample=MAX_CALLBACK; - for (size_t ui=0; ui v.getData(x,y,z)) - v.setData(x,y,z,value); - } else { - v.setData(x,y,z,value); - } - } - } - } - return 0; -} - -// == Voxels filter == -VoxeliseFilter::VoxeliseFilter() -: fixedWidth(false), normaliseType(VOXELISE_NORMALISETYPE_NONE) -{ - COMPILE_ASSERT(ARRAYSIZE(NORMALISE_TYPE_STRING) == VOXELISE_NORMALISETYPE_MAX); - COMPILE_ASSERT(ARRAYSIZE(VOXELISE_FILTER_TYPE_STRING) == VOXELISE_FILTERTYPE_MAX ); - COMPILE_ASSERT(ARRAYSIZE(VOXELISE_FILTER_BOUND_STRING) == VOXELISE_FILTERBOUNDMODE_MAX); - - COMPILE_ASSERT(ARRAYSIZE(REPRESENTATION_TYPE_STRING) == VOXEL_REPRESENT_END); - - splatSize=1.0f; - a=0.9f; - r=g=b=0.5; - isoLevel=0.5; - - filterBins=3; - filterMode=VOXELISE_FILTERTYPE_NONE; - filterBoundaryMode=VOXELISE_FILTERBOUNDMODE_BOUNCE; - gaussDev=0.5; - - representation=VOXEL_REPRESENT_POINTCLOUD; - - - //Ficticious bounds. - bc.setBounds(Point3D(0,0,0),Point3D(1,1,1)); - - for (unsigned int i = 0; i < INDEX_LENGTH; i++) - nBins[i] = 50; - - calculateWidthsFromNumBins(binWidth,nBins); - - numeratorAll = false; - denominatorAll = true; - - cacheOK=false; - cache=true; //By default, we should cache, but decision is made higher up - - - rsdIncoming=0; -} - - -Filter *VoxeliseFilter::cloneUncached() const -{ - VoxeliseFilter *p=new VoxeliseFilter(); - p->splatSize=splatSize; - p->a=a; - p->r=r; - p->g=g; - p->b=b; - - p->isoLevel=isoLevel; - - p->filterMode=filterMode; - p->filterBoundaryMode=filterBoundaryMode; - p->filterBins=filterBins; - p->gaussDev=gaussDev; - - p->representation=representation; - p->splatSize=splatSize; - - p->normaliseType=normaliseType; - p->numeratorAll=numeratorAll; - p->denominatorAll=denominatorAll; - - p->bc=bc; - - for(size_t ui=0;uinBins[ui] = nBins[ui]; - p->binWidth[ui] = binWidth[ui]; - } - - p->enabledIons[0].resize(enabledIons[0].size()); - std::copy(enabledIons[0].begin(),enabledIons[0].end(),p->enabledIons[0].begin()); - - p->enabledIons[1].resize(enabledIons[1].size()); - std::copy(enabledIons[1].begin(),enabledIons[1].end(),p->enabledIons[1].begin()); - - if(rsdIncoming) - { - p->rsdIncoming=new RangeStreamData(); - *(p->rsdIncoming) = *rsdIncoming; - } - else - p->rsdIncoming=0; - - p->cache=cache; - p->cacheOK=false; - p->userString=userString; - return p; -} - -size_t VoxeliseFilter::numBytesForCache(size_t nObjects) const -{ - //if we are using fixed width, we know the answer. - //otherwise we dont until we are presetned with the boundcube. - //TODO: Modify the function description to pass in the boundcube - if(!fixedWidth) - return nBins[0]*nBins[1]*nBins[2]*sizeof(float); - else - return 0; -} - -void VoxeliseFilter::initFilter(const std::vector &dataIn, - std::vector &dataOut) -{ - const RangeStreamData *c=0; - //Determine if we have an incoming range - for (size_t i = 0; i < dataIn.size(); i++) - { - if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE) - { - c=(const RangeStreamData *)dataIn[i]; - - break; - } - } - - //we no longer (or never did) have any incoming ranges. Not much to do - if(!c) - { - //delete the old incoming range pointer - if(rsdIncoming) - delete rsdIncoming; - rsdIncoming=0; - - enabledIons[0].clear(); //clear numerator options - enabledIons[1].clear(); //clear denominator options - - //Prevent normalisation type being set incorrectly - // if we have no incoming range data - if(normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL || normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL) - normaliseType= VOXELISE_NORMALISETYPE_NONE; - } - else - { - - - //If we didn't have an incoming rsd, then make one up! - if(!rsdIncoming) - { - rsdIncoming = new RangeStreamData; - *rsdIncoming=*c; - - //set the numerator to all disabled - enabledIons[0].resize(rsdIncoming->rangeFile->getNumIons(),0); - //set the denominator to have all enabled - enabledIons[1].resize(rsdIncoming->rangeFile->getNumIons(),1); - } - else - { - - //OK, so we have a range incoming already (from last time) - //-- the question is, is it the same - //one we had before - //Do a pointer comparison (its a hack, yes, but it should work) - if(rsdIncoming->rangeFile != c->rangeFile) - { - //hmm, it is different. well, trash the old incoming rng - delete rsdIncoming; - - rsdIncoming = new RangeStreamData; - *rsdIncoming=*c; - - //set the numerator to all disabled - enabledIons[0].resize(rsdIncoming->rangeFile->getNumIons(),0); - //set the denominator to have all enabled - enabledIons[1].resize(rsdIncoming->rangeFile->getNumIons(),1); - } - } - - } -} - -unsigned int VoxeliseFilter::refresh(const std::vector &dataIn, - std::vector &getOut, ProgressData &progress, bool (*callback)(bool)) -{ - for(size_t ui=0;uigetStreamType() & getRefreshBlockMask() )) - getOut.push_back(dataIn[ui]); - } - - //use the cached copy if we have it. - if(cacheOK) - { - for(size_t ui=0;uigetStreamType() != 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; - bcTmp=getIonDataLimits(is->data); - - //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.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; - - 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 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) - { - - for (size_t i = 0; i < dataIn.size(); i++) - { - - //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 = 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 datset - 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); - } - - if(!(*callback)(false)) - { - delete vs; - return VOXELISE_ABORT_ERR; - } - } - - //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++) - { - - if(dataIn[i]->getStreamType() == STREAM_TYPE_IONS) - { - is= (const IonStreamData *)dataIn[i]; - - countPoints(vs->data,is->data,true,callback); - - if(!(*callback)(false)) - { - delete vs; - return VOXELISE_ABORT_ERR; - } - - } - } - ASSERT(normaliseType != VOXELISE_NORMALISETYPE_COUNT2INVOXEL - && normaliseType!=VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL); - if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME) - vs->data.calculateDensity(); - } - - vsDenom.clear(); - - - //Perform voxel filtering - switch(filterMode) - { - case VOXELISE_FILTERTYPE_NONE: - break; - case VOXELISE_FILTERTYPE_GAUSS: - { - Voxels kernel,res; - - map modeMap; - - - 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 - - //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; - - //Gaussian kernel is separable (rank 1) - if(vs->data.separableConvolve(kernel,res,modeMap[filterBoundaryMode])) - return VOXELISE_CONVOLVE_ERR; - - vs->data.swap(res); - - res.clear(); - break; - } - default: - ASSERT(false); - } - - - float min,max; - vs->data.minMax(min,max); - - - string sMin,sMax; - stream_cast(sMin,min); - stream_cast(sMax,max); - consoleOutput.push_back(std::string(TRANS("Voxel Limits (min,max): (") + sMin + string(",")) - + sMax + ")"); - 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); - - //Copy the inputs into the outputs, provided they are not voxels - return 0; -} - -std::string VoxeliseFilter::getNormaliseTypeString(int type){ - ASSERT(type < VOXELISE_NORMALISETYPE_MAX); - return TRANS(NORMALISE_TYPE_STRING[type]); -} - -std::string VoxeliseFilter::getRepresentTypeString(int type) { - ASSERT(type > choices; - tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_NONE); - choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_NONE,tmpStr)); - tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_VOLUME); - choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_VOLUME,tmpStr)); - if(rsdIncoming) - { - //Concentration mode - tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL); - choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL,tmpStr)); - //Ratio is only valid if we have a way of separation for the ions i.e. range - tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_COUNT2INVOXEL); - choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_COUNT2INVOXEL,tmpStr)); - } - - tmpStr= choiceString(choices,normaliseType); - p.name=TRANS("Normalise by"); - p.data=tmpStr; - p.type=PROPERTY_TYPE_CHOICE; - p.helpText=TRANS("Method to use to normalise scalar value in each voxel"); - p.key=KEY_NORMALISE_TYPE; - propertyList.addProperty(p,curGroup); - propertyList.setGroupTitle(curGroup,TRANS("Computation")); - - curGroup++; - - // numerator - if (rsdIncoming) - { - p.name=TRANS("Numerator"); - p.data=numeratorAll ? "1" : "0"; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Parmeter \"a\" used in fraction (a/b) to get voxel value"); - p.key=KEY_ENABLE_NUMERATOR; - propertyList.addProperty(p,curGroup); - - ASSERT(rsdIncoming->enabledIons.size()==enabledIons[0].size()); - ASSERT(rsdIncoming->enabledIons.size()==enabledIons[1].size()); - - //Look at the numerator - for(unsigned int ui=0; uienabledIons.size(); ui++) - { - string str; - if(enabledIons[0][ui]) - str="1"; - else - str="0"; - - //Append the ion name with a checkbox - p.name=rsdIncoming->rangeFile->getName(ui); - p.data=str; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Enable this ion for numerator"); - p.key=KEY_ENABLE_NUMERATOR*1000+ui; - propertyList.addProperty(p,curGroup); - } - - curGroup++; - } - - - if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL && rsdIncoming) - { - p.name=TRANS("Denominator"); - p.data=denominatorAll ? "1" : "0"; - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Parameter \"b\" used in fraction (a/b) to get voxel value"); - p.key=KEY_ENABLE_DENOMINATOR; - - for(unsigned int ui=0; uienabledIons.size(); ui++) - { - string str; - if(enabledIons[1][ui]) - str="1"; - else - str="0"; - - //Append the ion name with a checkbox - p.key=KEY_ENABLE_DENOMINATOR*1000 + ui; - p.data=str; - p.name=rsdIncoming->rangeFile->getName(ui); - p.type=PROPERTY_TYPE_BOOL; - p.helpText=TRANS("Enable this ion for denominator contribution"); - - propertyList.addProperty(p,curGroup); - } - curGroup++; - } - - //Start a new set for filtering - //---- - //TODO: Other filtering? threshold/median? laplacian? etc - - choices.clear(); - - //Post-filtering method - for(unsigned int ui=0;uisplatSize=splatSize; - } - } - - } - break; - } - case KEY_TRANSPARANCY: - { - float f; - if(stream_cast(f,value)) - return false; - if(f < 0.0f || f > 1.0) - return false; - needUpdate=true; - //Alpha is opacity, which is 1-transparancy - a=1.0f-f; - //Go in and manually adjust the cached - //entries to have the new value, rather - //than doing a full recomputation - if(cacheOK) - { - for(unsigned int ui=0;uia=a; - } - } - break; - } - case KEY_ISOLEVEL: - { - float f; - if(stream_cast(f,value)) - return false; - if(f <= 0.0f) - return false; - needUpdate=true; - isoLevel=f; - //Go in and manually adjust the cached - //entries to have the new value, rather - //than doing a full recomputation - if(cacheOK) - { - for(unsigned int ui=0;uiisoLevel=isoLevel; - } - } - break; - } - case KEY_COLOUR: - { - unsigned char newR,newG,newB,newA; - - parseColString(value,newR,newG,newB,newA); - - if(newB != b || newR != r || - newG !=g || newA != a) - needUpdate=true; - r=newR/255.0; - g=newG/255.0; - b=newB/255.0; - //Go in and manually adjust the cached - //entries to have the new value, rather - //than doing a full recomputation - if(cacheOK) - { - for(unsigned int ui=0;uir=r; - d->g=g; - d->b=b; - } - } - break; - } - case KEY_VOXEL_REPRESENTATION_MODE: - { - 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) - { - for(unsigned int ui=0;uirepresentationType=representation; - } - } - break; - } - case KEY_ENABLE_NUMERATOR: - { - bool b; - if(stream_cast(b,value)) - return false; - //Set them all to enabled or disabled as a group - for (size_t i = 0; i < enabledIons[0].size(); i++) - enabledIons[0][i] = b; - numeratorAll = b; - needUpdate=true; - clearCache(); - break; - } - case KEY_ENABLE_DENOMINATOR: - { - bool b; - if(stream_cast(b,value)) - return false; - - //Set them all to enabled or disabled as a group - for (size_t i = 0; i < enabledIons[1].size(); i++) - enabledIons[1][i] = b; - - denominatorAll = b; - needUpdate=true; - clearCache(); - break; - } - case KEY_FILTER_MODE: - { - unsigned int i; - for (i = 0; i < VOXEL_REPRESENT_END; i++) - if (value == getFilterTypeString(i)) break; - if (i == VOXEL_REPRESENT_END) - return false; - if(i!=filterMode) - { - needUpdate=true; - filterMode=i; - clearCache(); - } - break; - } - case KEY_FILTER_BOUNDARY_MODE: - { - unsigned int i; - for (i = 0; i < VOXELISE_FILTERBOUNDMODE_MAX; i++) - if (value == getFilterBoundTypeString(i)) break; - if (i == VOXELISE_FILTERTYPE_MAX) - return false; - - if(i != filterBoundaryMode) - { - filterBoundaryMode=i; - needUpdate=true; - clearCache(); - } - break; - } - case KEY_FILTER_BINS: - { - unsigned int i; - if(stream_cast(i,value)) - return false; - - //FIXME: Min restriction is artificial and imposed due to incomplete separable convolution filter implementation - if(i == 0 || i > std::min(nBins[0],std::min(nBins[1],nBins[2]))) - return false; - if(i != filterBins) - { - needUpdate=true; - filterBins=i; - clearCache(); - } - break; - } - default: - { - if (key >= KEY_ENABLE_DENOMINATOR*1000) { - bool b; - if(stream_cast(b,value)) - return false; - - enabledIons[1][key - KEY_ENABLE_DENOMINATOR*1000]=b; - if (!b) { - denominatorAll = false; - } - needUpdate=true; - clearCache(); - } else if (key >= KEY_ENABLE_NUMERATOR*1000) { - bool b; - if(stream_cast(b,value)) - return false; - - enabledIons[0][key - KEY_ENABLE_NUMERATOR*1000]=b; - if (!b) { - numeratorAll = false; - } - needUpdate=true; - clearCache(); - } - else - { - ASSERT(false); - } - break; - } - } - return true; -} - -std::string VoxeliseFilter::getErrString(unsigned int code) const -{ - switch(code) - { - case VOXELISE_ABORT_ERR: - return std::string(TRANS("Voxelisation aborted")); - case VOXELISE_MEMORY_ERR: - return std::string(TRANS("Out of memory")); - case VOXELISE_CONVOLVE_ERR: - return std::string(TRANS("Unable to perform filter convolution")); - case VOXELISE_BOUNDS_INVALID_ERR: - return std::string(TRANS("Voxelisation bounds are invalid")); - } - - return std::string("BUG! Should not see this (VoxeliseFilter)"); -} - -bool VoxeliseFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const -{ - using std::endl; - switch(format) - { - case STATE_FORMAT_XML: - { - f << tabs(depth) << "<" << trueName() << ">" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+2) << "" << endl; - for(unsigned int ui=0;ui" << endl; - f << tabs(depth+2) << "" << endl; - - f << tabs(depth+2) << "" << endl; - for(unsigned int ui=0;ui" << endl; - f << tabs(depth+2) << "" << endl; - - f << tabs(depth+1) << "" << endl; - - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" << endl; - f << tabs(depth+1) << "" <" << endl; - break; - } - default: - ASSERT(false); - return false; - } - - return true; -} - -bool VoxeliseFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir) -{ - using std::string; - string tmpStr; - xmlChar *xmlString; - stack nodeStack; - - //Retrieve user string - //=== - if(XMLHelpFwdToElem(nodePtr,"userstring")) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); - if(!xmlString) - return false; - userString=(char *)xmlString; - xmlFree(xmlString); - //=== - - //Retrieve fixedWidth mode - if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixedwidth","value")) - return false; - if(tmpStr == "1") - fixedWidth=true; - else if(tmpStr== "0") - fixedWidth=false; - else - return false; - - //Retrieve nBins - if(XMLHelpFwdToElem(nodePtr,"nbins")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values"); - if(!xmlString) - return false; - std::vector v1; - splitStrsRef((char *)xmlString,',',v1); - for (size_t i = 0; i < INDEX_LENGTH && i < v1.size(); i++) - { - if(stream_cast(nBins[i],v1[i])) - return false; - - if(nBins[i] <= 0) - return false; - } - xmlFree(xmlString); - - //Retrieve bin width - if(XMLHelpFwdToElem(nodePtr,"binwidth")) - return false; - xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values"); - if(!xmlString) - return false; - std::vector v2; - splitStrsRef((char *)xmlString,',',v2); - for (size_t i = 0; i < INDEX_LENGTH && i < v2.size(); i++) - { - if(stream_cast(binWidth[i],v2[i])) - return false; - - if(binWidth[i] <= 0) - return false; - } - xmlFree(xmlString); - - //Retrieve normaliseType - if(!XMLGetNextElemAttrib(nodePtr,normaliseType,"normalisetype","value")) - return false; - if(normaliseType >= VOXELISE_NORMALISETYPE_MAX) - return false; - - //Look for the enabled ions bit - //------- - // - - if(!XMLHelpFwdToElem(nodePtr,"enabledions")) - { - - nodeStack.push(nodePtr); - if(!nodePtr->xmlChildrenNode) - return false; - nodePtr=nodePtr->xmlChildrenNode; - - //enabled ions for numerator - if(XMLHelpFwdToElem(nodePtr,"numerator")) - return false; - - nodeStack.push(nodePtr); - - if(!nodePtr->xmlChildrenNode) - return false; - - nodePtr=nodePtr->xmlChildrenNode; - - while(nodePtr) - { - char c; - //Retrieve representation - if(!XMLGetNextElemAttrib(nodePtr,c,"enabled","value")) - break; - - if(c == '1') - enabledIons[0].push_back(true); - else - enabledIons[0].push_back(false); - - - nodePtr=nodePtr->next; - } - - nodePtr=nodeStack.top(); - nodeStack.pop(); - - //enabled ions for demerator - if(XMLHelpFwdToElem(nodePtr,"denominator")) - return false; - - - if(!nodePtr->xmlChildrenNode) - return false; - - nodeStack.push(nodePtr); - nodePtr=nodePtr->xmlChildrenNode; - - while(nodePtr) - { - char c; - //Retrieve representation - if(!XMLGetNextElemAttrib(nodePtr,c,"enabled","value")) - break; - - if(c == '1') - enabledIons[1].push_back(true); - else - enabledIons[1].push_back(false); - - - nodePtr=nodePtr->next; - } - - - nodeStack.pop(); - nodePtr=nodeStack.top(); - nodeStack.pop(); - - //Check that the enabled ions size makes at least some sense... - if(enabledIons[0].size() != enabledIons[1].size()) - return false; - - } - - //------- - //Retrieve representation - if(!XMLGetNextElemAttrib(nodePtr,representation,"representation","value")) - return false; - if(representation >=VOXEL_REPRESENT_END) - return false; - - //------- - //Retrieve representation - if(!XMLGetNextElemAttrib(nodePtr,isoLevel,"isovalue","value")) - return false; - - //Retrieve colour - //==== - if(XMLHelpFwdToElem(nodePtr,"colour")) - return false; - if(!parseXMLColour(nodePtr,r,g,b,a)) - return false; - - //==== - return true; - -} - -unsigned int VoxeliseFilter::getRefreshBlockMask() const -{ - //Ions, plots and voxels cannot pass through this filter - return STREAM_TYPE_IONS | STREAM_TYPE_PLOT | STREAM_TYPE_VOXEL; -} - -unsigned int VoxeliseFilter::getRefreshEmitMask() const -{ - return STREAM_TYPE_VOXEL | STREAM_TYPE_DRAW; -} - -unsigned int VoxeliseFilter::getRefreshUseMask() const -{ - return STREAM_TYPE_IONS | STREAM_TYPE_RANGE; -} - -void VoxeliseFilter::setPropFromBinding(const SelectionBinding &b) -{ -} - -#ifdef DEBUG -bool voxelSingleCountTest() -{ - //Test counting a single vector - - vector ionVec; - - ionVec.resize(5); - ionVec[0].setPos(Point3D(0.1,0.1,0.1)); - ionVec[1].setPos(Point3D(0.1,0.0,0.1)); - ionVec[2].setPos(Point3D(0.0,0.1,0.1)); - ionVec[3].setPos(Point3D(0.1,0.1,0.0)); - ionVec[4].setPos(Point3D(0.0,0.1,0.0)); - - for(unsigned int ui=0;uidata,ionVec); - - size_t numIons=ionData->data.size(); - - VoxeliseFilter *f = new VoxeliseFilter; - f->setCaching(false); - - bool needUpdate; - TEST(f->setProperty(KEY_NBINSX,"4",needUpdate),"num bins x"); - TEST(f->setProperty(KEY_NBINSY,"4",needUpdate),"num bins y"); - TEST(f->setProperty(KEY_NBINSZ,"4",needUpdate),"num bins z"); - - - vector streamIn,streamOut; - streamIn.push_back(ionData); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - delete f; - - TEST(streamOut.size() == 1,"stream count"); - TEST(streamOut[0]->getStreamType() == STREAM_TYPE_VOXEL,"Stream type"); - - - const VoxelStreamData *v= (const VoxelStreamData*)streamOut[0]; - - TEST(v->data.max() <=numIons, - "voxel max less than input stream") - - TEST(v->data.min() >= 0.0f,"voxel counting minimum sanity"); - - - float dataSum; - sumVoxels(v->data,dataSum); - TEST(fabs(dataSum - (float)numIons ) < - sqrt(std::numeric_limits::epsilon()),"voxel counting all input ions "); - - delete ionData; - delete streamOut[0]; - - return true; -} - -bool voxelMultiCountTest() -{ - //Test counting multiple data streams containing ranged data - - vector streamIn,streamOut; - vector ionVec; - - ionVec.resize(5); - ionVec[0].setPos(Point3D(0.1,0.1,0.1)); - ionVec[1].setPos(Point3D(0.1,0.0,0.1)); - ionVec[2].setPos(Point3D(0.0,0.1,0.1)); - ionVec[3].setPos(Point3D(0.1,0.1,0.0)); - ionVec[4].setPos(Point3D(0.0,0.1,0.0)); - - IonStreamData *ionData[2]; - RangeStreamData *rngStream; - rngStream = new RangeStreamData; - rngStream->rangeFile= new RangeFile; - - RGBf col; col.red=col.green=col.blue=1.0f; - - const unsigned int MAX_NUM_RANGES=2; - for(unsigned int ui=0;uirangeFile->addIon(sTmp,sTmp,col); - rngStream->rangeFile->addRange((float)ui-0.5f,(float)ui+0.5f,ionNum); - - //Change m/c value for ion - for(unsigned int uj=0;ujdata.resize(ionVec.size()); - std::copy(ionVec.begin(),ionVec.end(),ionData[ui]->data.begin()); - streamIn.push_back(ionData[ui]); - } - - rngStream->enabledIons.resize(rngStream->rangeFile->getNumIons()); - rngStream->enabledRanges.resize(rngStream->rangeFile->getNumRanges()); - - streamIn.push_back(rngStream); - - VoxeliseFilter *f = new VoxeliseFilter; - - //Initialise range data - f->initFilter(streamIn,streamOut); - - - f->setCaching(false); - - bool needUpdate; - TEST(f->setProperty(KEY_NBINSX,"4",needUpdate),"num bins x"); - TEST(f->setProperty(KEY_NBINSY,"4",needUpdate),"num bins y"); - TEST(f->setProperty(KEY_NBINSZ,"4",needUpdate),"num bins z"); - - - TEST(f->setProperty(KEY_NORMALISE_TYPE, - TRANS(NORMALISE_TYPE_STRING[VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL]),needUpdate), - "Set normalise mode"); - - ProgressData p; - TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code"); - delete f; - for(unsigned int ui=0;uigetStreamType() == STREAM_TYPE_VOXEL,"Stream type"); - - const VoxelStreamData *v= (const VoxelStreamData*)streamOut[1]; - - TEST(v->data.max() <=1.0f, - "voxel max less than input stream") - TEST(v->data.min() >= 0.0f,"voxel counting minimum sanity"); - - - for(unsigned int ui=0;uidata.getSize();ui++) - { - float delta; - delta=(v->data.getData(ui) - v->data.getData(0) ); - ASSERT( v->data.getData(ui) == 0 || delta < std::numeric_limits::epsilon()); - } - - delete v; - - delete rngStream->rangeFile; - delete rngStream; - - return true; -} - -bool voxelConvolveTest() -{ - WARN(false,"Voxel convolve test not implemented"); - return true; -} - -bool VoxeliseFilter::runUnitTests() -{ - - if(!voxelSingleCountTest()) - return false; - - if(!voxelMultiCountTest()) - return false; - - - if(!voxelConvolveTest()) - return false; - - return true; -} - -#endif diff -Nru 3depict-0.0.12/src/filters/voxelise.h 3depict-0.0.13/src/filters/voxelise.h --- 3depict-0.0.12/src/filters/voxelise.h 2012-11-11 19:54:12.000000000 +0000 +++ 3depict-0.0.13/src/filters/voxelise.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -#ifndef VOXELISE_H -#define VOXELISE_H -#include "../filter.h" -#include "../translation.h" - -//!Filter that does voxelisation for various primitives (copid from CompositionFilter) -class VoxeliseFilter : public Filter -{ -private: - const static size_t INDEX_LENGTH = 3; - - //Enabled ions for numerator/denom - std::vector enabledIons[2]; - - //!Stepping mode - fixed width or fixed number of bins - bool fixedWidth; - - //!number of bins (if using fixed bins) - unsigned long long nBins[INDEX_LENGTH]; - //!Width of each bin (if using fixed wdith) - Point3D binWidth; - //!boundcube for the input data points - BoundCube bc; - - //!density-based or count-based - unsigned int normaliseType; - bool numeratorAll, denominatorAll; - //This is filter's enabled ranges - RangeStreamData *rsdIncoming; - - float r,g,b,a; - - //!Filter mode to apply to data before output - unsigned int filterMode; - - //!How do we treat boundaries when applying filters - unsigned int filterBoundaryMode; - - //!Filter size - unsigned int filterBins; - - //!Gaussian filter standard deviation - float gaussDev; - - //!3D Point Representation size - float splatSize; - - //!Isosurface level - float isoLevel; - //!Default output representation mode - unsigned int representation; -public: - VoxeliseFilter(); - ~VoxeliseFilter() { if(rsdIncoming) delete rsdIncoming;} - //!Duplicate filter contents, excluding cache. - Filter *cloneUncached() const; - - - - //!Get approx number of bytes for caching output - size_t numBytesForCache(size_t nObjects) const; - - unsigned int getType() const { return FILTER_TYPE_VOXELS;}; - - virtual void initFilter(const std::vector &dataIn, - std::vector &dataOut); - //!update filter - unsigned int refresh(const std::vector &dataIn, - std::vector &getOut, - ProgressData &progress, bool (*callback)(bool)); - - virtual std::string typeString() const { return std::string(TRANS("Voxelisation"));}; - - //!Get the human-readable options for the normalisation, based upon enum - static std::string getNormaliseTypeString(int type); - //!Get the human-readable options for filtering, based upon enum - static std::string getFilterTypeString(int type); - //!Get the human-readable options for the visual representation (enum) - static std::string getRepresentTypeString(int type); - //!Get the human-readable options for boundary behaviour during filtering, based upon enum - static std::string getFilterBoundTypeString(int type); - - //!Get the properties of the filter, in key-value form. First vector is for each output. - void getProperties(FilterPropGroup &propertyList) const; - - //!Set the properties for the nth filter. Returns true if prop set OK - bool setProperty(unsigned int key, - const std::string &value, bool &needUpdate); - //!Get the human readable error string associated with a particular error code during refresh(...) - std::string getErrString(unsigned int code) const; - - //!Dump state to output stream, using specified format - bool writeState(std::ostream &f,unsigned int format, - unsigned int depth=0) const; - //!Read the state of the filter from XML file. If this - //fails, filter will be in an undefined state. - bool readState(xmlNodePtr &node, const std::string &packDir); - - //!Get the stream types that will be dropped during ::refresh - unsigned int getRefreshBlockMask() const; - - //!Get the stream types that will be generated during ::refresh - unsigned int getRefreshEmitMask() const; - - //!Get the stream types that will be possibly ued during ::refresh - unsigned int getRefreshUseMask() const; - //!Set internal property value using a selection binding - void setPropFromBinding(const SelectionBinding &b) ; - - - //!calculate the widths of the bins in 3D - void calculateWidthsFromNumBins(Point3D &widths, unsigned long long *nb) const{ - Point3D low, high; - bc.getBounds(low, high); - for (unsigned int i = 0; i < 3; i++) { - widths[i] = (high[i] - low[i])/(float)nb[i]; - } - } - //!set the number of the bins in 3D - void calculateNumBinsFromWidths(Point3D &widths, unsigned long long *nb) const{ - Point3D low, high; - bc.getBounds(low, high); - for (unsigned int i = 0; i < 3; i++) { - if (low[i] == high[i]) nb[i] = 1; - else nb[i] = (unsigned long long)((high[i] - low[i])/(float)widths[i]) + 1; - } - } - -#ifdef DEBUG - bool runUnitTests(); -#endif - -}; - -#endif - diff -Nru 3depict-0.0.12/src/filtertree.cpp 3depict-0.0.13/src/filtertree.cpp --- 3depict-0.0.12/src/filtertree.cpp 2012-11-18 00:03:53.000000000 +0000 +++ 3depict-0.0.13/src/filtertree.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1757 +0,0 @@ -/* - * filtertree.cpp - Filter tree topology and data propagation handling - * Copyright (C) 2012, 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 . -*/ - - - -#include "filtertree.h" -#include "filters/allFilter.h" - -#include "xmlHelper.h" - - -using std::string; - -enum -{ - CACHE_DEPTH_FIRST=1, - CACHE_NEVER, -}; - -const float DEFAULT_MAX_CACHE_PERCENT=50; - -//!Internal function for pointer deletion from stack during refreshing filter tree -void popPointerStack(std::list &pointerTrackList, - std::stack > &inDataStack, - unsigned int depth) -{ - - while(inDataStack.size() > depth) - { - //Look at each filter pointer on this stack level. - for(unsigned int ui=0; ui::iterator it; - it=find(pointerTrackList.begin(),pointerTrackList.end(),thisData); - if(it!=pointerTrackList.end()) - { - ASSERT(thisData->cached ==0); - - delete thisData; - - //Remove from tracking list. This has been erased - pointerTrackList.erase(it); - //Pointer should be only in the track list once. - ASSERT(find(pointerTrackList.begin(), - pointerTrackList.end(),thisData) == pointerTrackList.end()); - } - } - //We no longer need this level - inDataStack.pop(); - } -} - -FilterTree::FilterTree() -{ - maxCachePercent=DEFAULT_MAX_CACHE_PERCENT; - cacheStrategy=CACHE_DEPTH_FIRST; -} - -FilterTree::~FilterTree() -{ - clear(); -} - -FilterTree::FilterTree(const FilterTree &orig) : - cacheStrategy(orig.cacheStrategy), maxCachePercent(orig.maxCachePercent), - filters(orig.filters) -{ - //Don't grab a direct copy of the tree, but rather an cloned duplicate, - // without the internal cache data - for(tree::pre_order_iterator it=filters.begin(); - it!=filters.end();++it) - (*it)=(*it)->cloneUncached(); -} - -void FilterTree::swap(FilterTree &other) -{ - std::swap(cacheStrategy,other.cacheStrategy); - std::swap(maxCachePercent,other.maxCachePercent); - std::swap(filters,other.filters); -} - -const FilterTree &FilterTree::operator=(const FilterTree &orig) -{ - cacheStrategy=orig.cacheStrategy; - maxCachePercent=orig.maxCachePercent; - - filters=orig.filters; - - //Don't grab a direct copy of the tree, but rather an cloned duplicate, - // without the internal cache data - for(tree::pre_order_iterator it=filters.begin(); - it!=filters.end();++it) - (*it)=(*it)->cloneUncached(); - - return *this; -} - -size_t FilterTree::maxDepth() const -{ - return filters.max_depth(); -} - -void FilterTree::initFilterTree() const -{ - - //TODO: This shares a lot of code with the refresh function. Could - // share better (i.e. not cut and paste) - vector< const FilterStreamData *> curData; - stack > inDataStack; - list > outData; - - list pointerTrackList; - - //Do not allow stack to empty - inDataStack.push(curData); - //Depth-first search from root node, refreshing filters as we proceed. - for(tree::pre_order_iterator filtIt=filters.begin(); - filtIt!=filters.end(); ++filtIt) - { - //Step 0 : Pop the cache until we reach our current level, - // deleting any pointers that would otherwise be lost. - //--- - popPointerStack(pointerTrackList, - inDataStack,filters.depth(filtIt)+1); - //--- - - //Step 1: Take the stack top, and turn it into "curdata" using the filter - // record the result on the stack - //--- - //Take the stack top, filter it and generate "curData" - (*filtIt)->initFilter(inDataStack.top(),curData); - - //Step 2: Track pointers as needed. Leaves need to be placed in - //outdata. Missing pointers need to be garbage collected. New non-leaf - //pointers need to be tracked - - //is this node a leaf of the tree? - bool isLeaf; - isLeaf=false; - for(tree::leaf_iterator leafIt=filters.begin_leaf(); - leafIt!=filters.end_leaf(); ++leafIt) - { - if(*leafIt == *filtIt) - { - isLeaf=true; - break; - } - } - - //If this is not a leaf, keep track of intermediary pointers - if(!isLeaf) - { - //The filter will generate a list of new pointers. If any out-going data - //streams are un-cached, track them - for(unsigned int ui=0;ui::iterator it; - it = find(pointerTrackList.begin(),pointerTrackList.end(),curData[ui]); - //Caching is *Forbidden* in filter initialisation - ASSERT(!curData[ui]->cached); - - //Check that we are not already tracking it. - if(it==pointerTrackList.end()) - { - //track pointer. - pointerTrackList.push_back(curData[ui]); - } - } - - //Put this in the intermediary stack, - //so it is available for any other children at this level. - inDataStack.push(curData); - } - else - { - //The filter has created an ouput. Record it for passing to updateScene - outData.push_back(curData); - for(unsigned int ui=0;ui::iterator it; - it=find(pointerTrackList.begin(),pointerTrackList.end(), - curData[ui]); - - if(it!=pointerTrackList.end()) - pointerTrackList.erase(it); - - //Pointer should be only in the track list once. - ASSERT(find(pointerTrackList.begin(),pointerTrackList.end(), - curData[ui]) == pointerTrackList.end()); - - } - } - - //Cur data is recorded either in outDta or on the data stack - curData.clear(); - //--- - - } - - popPointerStack(pointerTrackList,inDataStack,0); - - //Pointer tracking list should be empty. - ASSERT(pointerTrackList.empty()); - ASSERT(inDataStack.empty()); - - //mop up the output - list deletedPtrs; - for(list >::iterator - it=outData.begin();it!=outData.end(); ++it) - - { - - //Only delete things once. - for(size_t ui=0; uisize();ui++) - { - if(find(deletedPtrs.begin(),deletedPtrs.end(),(*it)[ui]) == deletedPtrs.end()) - { - deletedPtrs.push_back((*it)[ui]); - delete (*it)[ui]; - } - } - } -} - -void FilterTree::clear() -{ - for(tree::iterator filterIt=filters.begin(); - filterIt!=filters.end();++filterIt) - delete (*filterIt); - - filters.clear(); -} - -void FilterTree::getAccumulatedPropagationMaps(map &emitTypes, map &blockTypes) const -{ - //Build the emit type map. This describes - //what possible types can be emitted at any point in the tree. - for(tree::iterator it=filters.begin_breadth_first(); - it!=filters.end_breadth_first(); ++it) - { - //FIXME: HACK -- why does the BFS not terminate correctly? - if(!filters.is_valid(it)) - break; - - size_t curEmit; - //Root node is special, does not combine with the - //previous filter - if(!filters.depth(it)) - curEmit=(*it)->getRefreshEmitMask(); - else - { - //Normal child. We need to remove any types that - //are blocked (& (~blocked)), then add any types that are emitted - //(|) - curEmit=emitTypes[*(filters.parent(it))]; - curEmit&=(~(*it)->getRefreshBlockMask() )& STREAMTYPE_MASK_ALL; - curEmit|=(*it)->getRefreshEmitMask(); - } - - ASSERT(curEmit < STREAMTYPE_MASK_ALL); - emitTypes.insert(make_pair(*it,curEmit)); - - } - - - - - //Build the accumulated block map; this describes - //what types, if emitted, will NOT be propagated to the final output - //Nor affect any downstream filters - for(size_t ui=filters.max_depth()+1; ui; ) - { - ui--; - - for(tree::iterator it=filters.begin(); it!=filters.end(); ++it) - { - //Check to see if we are at the correct depth - if(filters.depth(it) != ui) - continue; - - - //Initially assume that everything is passed through - //filter - int blockMask=0x0; - - - if((*it)->haveCache()) - { - //Loop over the children of this filter, grab their block masks - for(tree::sibling_iterator itJ=it.begin(); itJ!=it.end(); ++itJ) - { - - if((*itJ)->haveCache()) - { - int curBlockMask; - curBlockMask=(*itJ)->getRefreshBlockMask(); - blockMask= (blockMask & curBlockMask); - - } - else - { - blockMask&=0; - //The only reason to keep looping is to - //alter the blockmask. If it is at any point zero, - //then the answer will be zero, due to the & operator. - break; - } - - } - - //OK, so we now know which filters the children will ALL block. - //Combine this with our block list for this filter, and we this will give ush - //the blocklist for this subtree section - blockMask|=(*it)->getRefreshBlockMask(); - } - else - blockMask=0; - - blockTypes.insert(make_pair(*it,blockMask)); - } - - } - - - -} - - -void FilterTree::getFilterRefreshStarts(vector::iterator > &propStarts) const -{ - - if(!filters.size()) - return; - - const bool STUPID_ALGORITHM=false; - if(STUPID_ALGORITHM) - { - //Stupid version - //start at root every time - propStarts.push_back(filters.begin()); - } - else - { - //Do something hopefully non-stupid. Here we examine the types of data that are - //propagated through the tree, and which filters emit, or block transmission - //of any given type (ie their output is influenced only by certain data types). - - //From this information, and the cache status of each filter - //(recall caches only cache data generated inside the filter), it is possible to - //skip certain initial element refreshes. - - //Block and emit adjuncts for tree - map accumulatedEmitTypes,accumulatedBlockTypes; - getAccumulatedPropagationMaps(accumulatedEmitTypes,accumulatedBlockTypes); - - vector::iterator > seedFilts; - - - - - for(tree::iterator it=filters.begin_breadth_first(); - it!=filters.end_breadth_first(); ++it) - { - //FIXME: HACK -- why does the BFS not terminate correctly? - if(!filters.is_valid(it)) - break; - - //Check to see if we have an insertion point above us. - //if so, we cannot press on, as we have determined that - //we must start higher up. - bool isChildFilt; - isChildFilt=false; - for(unsigned int ui=0; ui::leaf_iterator itJ= filters.begin_leaf(); - itJ!=filters.end_leaf(); ++itJ) - - { - if(itJ == it) - { - isLeaf=true; - seedFilts.push_back(it); - break; - } - } - - if(isLeaf) - continue; - - //Check to see if we can use these children as insertion - //points in the tree - //i.e., ask, "Do all subtrees block everything we emit from here?" - int emitMask,blockMask; - emitMask=accumulatedEmitTypes[*it]; - blockMask=~0; - for(tree::sibling_iterator itJ=filters.begin(it); itJ!=filters.end(it); ++itJ) - blockMask&=accumulatedBlockTypes[*itJ]; - - - - - - if( emitMask & ((~blockMask) & STREAMTYPE_MASK_ALL)) - { - - //Oh noes! we don't block, we will have to stop here, - // for this subtree. We cannot go further down. - seedFilts.push_back(it); - } - - } - - propStarts.swap(seedFilts); - } - -#ifdef DEBUG - for(unsigned int ui=0; ui > > &outData, - std::vector *> &devices,vector > &consoleMessages, - ProgressData &curProg, bool (*callback)(bool)) -{ - - unsigned int errCode=0; - - if(!filters.size()) - { - return 0; - } - - //Destroy any caches that belong to monitored filters that need - //refreshing. Failing to do this can lead to filters being skipped - //during the refresh - for(tree::iterator filterIt=filters.begin(); - filterIt!=filters.end();++filterIt) - { - //We need to clear the cache of *all* - //downstream filters, as otherwise - //their cache's could block our update. - if((*filterIt)->monitorNeedsRefresh()) - { - for(tree::pre_order_iterator it(filterIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(filterIt) >= filters.depth(it) && it!=filterIt ) - break; - - (*it)->clearCache(); - } - } - } - - - // -- Build data streams -- - vector< const FilterStreamData *> curData; - stack > inDataStack; - - list pointerTrackList; - - //Push some dummy data onto the stack to prime first-pass (call to refresh(..) requires stack - //size to be non-zero) - inDataStack.push(curData); - - //Keep redoing the refresh until the user stops fiddling with the filter tree. - - vector::iterator> baseTreeNodes; - - baseTreeNodes.clear(); - - getFilterRefreshStarts(baseTreeNodes); - - - curProg.totalNumFilters=countChildFilters(filters,baseTreeNodes)+baseTreeNodes.size(); - - - (*callback)(false); - - for(unsigned int itPos=0;itPos::pre_order_iterator filtIt=baseTreeNodes[itPos]; - filtIt!=filters.end(); ++filtIt) - { - //Check to see if this node is a child of the base node. - //if not, move on. - if( filtIt!= baseTreeNodes[itPos] && - !isChild(filters,baseTreeNodes[itPos],filtIt)) - continue; - - - //Step 0 : Pop the cache until we reach our current level, - // deleting any pointers that would otherwise be lost. - // Recall that the zero size in the stack may not correspond to the - // tree root, but rather corresponds to our insertion level - //--- - popPointerStack(pointerTrackList, - inDataStack,filters.depth(filtIt) - filters.depth(baseTreeNodes[itPos])+1); - //--- - - //Step 1: Set up the progress system - //--- - curProg.clock(); - curProg.curFilter=*filtIt; - //--- - - //Step 2: Check if we should cache this filter or not. - //Get the number of bytes that the filter expects to use - //--- - unsigned long long cacheBytes; - if(inDataStack.empty()) - cacheBytes=(*filtIt)->numBytesForCache(0); - else - cacheBytes=(*filtIt)->numBytesForCache(numElements(inDataStack.top())); - - if(cacheBytes != (unsigned long long)(-1)) - { - //As long as we have caching enabled, let us cache according to the - //selected strategy - switch(cacheStrategy) - { - case CACHE_NEVER: - (*filtIt)->setCaching(false); - break; - case CACHE_DEPTH_FIRST: - (*filtIt)->setCaching(cacheBytes/(1024*1024) < maxCachePercent*getAvailRAM()); - break; - - } - } - else - (*filtIt)->setCaching(false); - - //--- - - //Step 3: Take the stack top, and turn it into "curdata" and refresh using the filter. - // Record the result on the stack. - // We also record any Selection devices that are generated by the filter. - // This is the guts of the system. - //--- - // - (*callback)(false); - - - //Take the stack top, filter it and generate "curData" - errCode=(*filtIt)->refresh(inDataStack.top(), - curData,curProg,callback); - -#ifdef DEBUG - //Perform sanity checks on filter output - checkRefreshValidity(curData,*filtIt); - ASSERT(curProg.step == curProg.maxStep || errCode); -#endif - //Ensure that (1) yield is called, regardless of what filter does - //(2) yield is called after 100% update - curProg.filterProgress=100; - (*callback)(false); - - - vector *> curDevices; - //Retrieve the user interaction "devices", and send them to the scene - (*filtIt)->getSelectionDevices(curDevices); - - //Add them to the total list of devices - for(size_t ui=0;ui tmpMessages; - (*filtIt)->getConsoleStrings(tmpMessages); - //Accumulate the messages - consoleMessages.reserve(consoleMessages.size()+tmpMessages.size()); - for(size_t ui=0;uiupdateOutputInfo(curData); - - - //is this node a leaf of the tree? - bool isLeaf; - isLeaf=false; - for(tree::leaf_iterator leafIt=filters.begin_leaf(); - leafIt!=filters.end_leaf(); ++leafIt) - { - if(*leafIt == *filtIt) - { - isLeaf=true; - break; - } - } - - if(curData.size()) - { - //If this is not a leaf, keep track of intermediary pointers - if(!isLeaf) - { - //The filter will generate a list of new pointers. If any out-going data - //streams are un-cached, track them - for(unsigned int ui=0;ui::iterator it; - it = find(pointerTrackList.begin(),pointerTrackList.end(),curData[ui]); - //Check it is not cached, and that we are not already tracking it. - if(!curData[ui]->cached && it==pointerTrackList.end()) - { - //track pointer. - pointerTrackList.push_back(curData[ui]); - } - } - - //Put this in the intermediary stack, - //so it is available for any other children at this leve. - inDataStack.push(curData); - } - else - { - //The filter has created an ouput. Record it for passing to updateScene - outData.push_back(make_pair(*filtIt,curData)); - for(unsigned int ui=0;ui::iterator it; - it=find(pointerTrackList.begin(),pointerTrackList.end(), - curData[ui]); - - //The pointer is an output from the filter, so we don't need to track it - if(it!=pointerTrackList.end()) - pointerTrackList.erase(it); - - //Pointer should be only in the track list once. - ASSERT(find(pointerTrackList.begin(),pointerTrackList.end(), - curData[ui]) == pointerTrackList.end()); - - } - } - //Cur data is recorded either in outDta or on the data stack - curData.clear(); - } - //--- - - } - - } - - popPointerStack(pointerTrackList,inDataStack,0); - - - //Pointer tracking list should be empty. - ASSERT(pointerTrackList.empty()); - ASSERT(inDataStack.empty()); - - //====Output scrubbing === - - //Should be no duplicate pointers in output data. - //(this makes preventing double frees easier, and - // minimises unneccesary output) - //Construct a single list of all pointers in output, - //checking for uniqueness. Delete duplicates - list flatList; - - for(list > >::iterator - it=outData.begin();it!=outData.end(); ++it) - { - vector::iterator itJ; - - itJ=it->second.begin(); - while(itJ!=it->second.end()) - { - //Each stream data pointer should only occur once in the entire lot. - if(find(flatList.begin(),flatList.end(),*itJ) == flatList.end()) - { - flatList.push_back(*itJ); - ++itJ; - } - else - itJ=it->second.erase(itJ); - } - } - - //outData List is complete, and contains only unique entries. clear the checking list. - flatList.clear(); - - //====== - - - - return 0; -} - -bool FilterTree::setFilterProperty(Filter *targetFilter, unsigned int key, - const std::string &value, bool &needUpdate) -{ - ASSERT(std::find(filters.begin(),filters.end(),targetFilter) != filters.end()); - if(!targetFilter->setProperty(key,value,needUpdate)) - return false; - - //If we no longer have a cache, and the filter needs an update, then we must - //modify the downstream objects - if(needUpdate) - { - for(tree::pre_order_iterator filtIt=filters.begin(); - filtIt!=filters.end(); ++filtIt) - { - if(targetFilter == *filtIt) - { - //Kill all cache below filtIt - for(tree::pre_order_iterator it(filtIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(filtIt) >= filters.depth(it) && it!=filtIt ) - break; - - //Do not clear the cache for the target filter. - //This is the respnsibility of the setProperty function for the filter - if(*it !=targetFilter) - (*it)->clearCache(); - } - break; - } - } - - } - - initFilterTree(); - return true; - -} - -unsigned int FilterTree::loadXML(const xmlNodePtr &treeParent, std::ostream &errStream,const std::string &stateFileDir) - -{ - clear(); - - //Parse the filter tree in the XML file. - //generating a filter tree - bool inTree=true; - tree::iterator lastFilt=filters.begin(); - tree::iterator lastTop=filters.begin(); - stack::iterator> treeNodeStack; - - xmlNodePtr nodePtr = treeParent->xmlChildrenNode; - - - //push root tag - std::stack nodeStack; - nodeStack.push(nodePtr); - - bool needCleanup=false; - while (inTree) - { - //Jump to the next XML node at this depth - if (XMLHelpNextType(nodePtr,XML_ELEMENT_NODE)) - { - //If there is not one, pop the tree stack - if (treeNodeStack.size()) - { - //Pop the node stack for the XML and filter trees. - nodePtr=nodeStack.top(); - nodeStack.pop(); - lastFilt=treeNodeStack.top(); - treeNodeStack.pop(); - } - else - { - //Did we run out of stack? - //then we have finished the tree. - inTree=false; - } - continue; - } - - Filter *newFilt; - bool nodeUnderstood; - newFilt=0; - nodeUnderstood=true; //assume by default we understand, and set false if not - - //If we encounter a "children" node. then we need to look at the children of this filter - if (!xmlStrcmp(nodePtr->name,(const xmlChar*)"children")) - { - //Can't have children without parent - if (!filters.size()) - { - needCleanup=true; - break; - } - - //Child node should have its own child - if (!nodePtr->xmlChildrenNode) - { - needCleanup=true; - break; - } - - nodeStack.push(nodePtr); - treeNodeStack.push(lastFilt); - - nodePtr=nodePtr->xmlChildrenNode; - continue; - } - else - { - //Well, its not a "children" node, so it could - //be a filter... Lets find out - std::string tmpStr; - tmpStr=(char *)nodePtr->name; - - newFilt=makeFilter(tmpStr); - if(newFilt) - { - if (!newFilt->readState(nodePtr->xmlChildrenNode,stateFileDir)) - { - needCleanup=true; - break; - } - } - else - { - errStream << TRANS("WARNING: Skipping node ") << (const char *)nodePtr->name << TRANS(" as it was not recognised") << endl; - nodeUnderstood=false; - } - } - - - //Skip this item - if (nodeUnderstood) - { - ASSERT(newFilt); - - //Add the new item the tree - if (!filters.size()) - lastFilt=filters.insert(filters.begin(),newFilt); - else - { - if (treeNodeStack.size()) - lastFilt=filters.append_child(treeNodeStack.top(),newFilt); - else - { - lastTop=filters.insert(lastTop,newFilt); - lastFilt=lastTop; - } - - - } - - } - } - - - //All good? - if(!needCleanup) - return 0; - - //OK, we hit an error, we need to delete any pointers on the - //cleanup list - if(nodePtr) - errStream << TRANS("Error processing node: ") << (const char *)nodePtr->name << endl; - - clear(); - - //No good.. - return 1; - -} - -bool FilterTree::saveXML(std::ofstream &f,std::map &fileMapping, - bool writePackage, bool useRelativePaths, unsigned int minTabDepth) const -{ - f << tabs(minTabDepth+1) << "" << endl; - //Depth-first search, enumerate all filters in depth-first fashion - unsigned int depthLast=0; - unsigned int child=0; - for(tree::pre_order_iterator filtIt=filters.begin(); - filtIt!=filters.end(); ++filtIt) - { - unsigned int depth; - depth = filters.depth(filtIt); - if(depth >depthLast) - { - while(depthLast++ < depth) - { - f << tabs(minTabDepth+depthLast+1); - f << "" << endl; - child++; - } - } - else if (depth < depthLast) - { - while(depthLast-- > depth) - { - f << tabs(minTabDepth+depthLast+2); - f << "" << endl; - child--; - } - } - - //If we are writing a package, override the filter storage values - if(writePackage || useRelativePaths) - { - vector valueOverrides; - (*filtIt)->getStateOverrides(valueOverrides); - - //The overrides, at the moment, only are files. - //So lets find them & move them - for(unsigned int ui=0;ui::const_iterator it; - it =fileMapping.find(valueOverrides[ui]); - - if(it == fileMapping.end()) - { - //map does not exist, so make it! - fileMapping[newFilename]=valueOverrides[ui]; - } - else if (it->second !=valueOverrides[ui]) - { - //Keep adding a prefix until we find a valid new filename - while(fileMapping.find(newFilename) != fileMapping.end()) - newFilename="remap"+newFilename; - //map does not exist, so make it! - fileMapping[newFilename]=valueOverrides[ui]; - } - valueOverrides[ui] = newFilename; - } - - if(!(*filtIt)->writePackageState(f,STATE_FORMAT_XML,valueOverrides,depth+2)) - return false; - } - else - { - if(!(*filtIt)->writeState(f,STATE_FORMAT_XML,depth+2)) - return false; - } - depthLast=depth; - } - - //Close out filter tree. - while(child--) - { - f << tabs(minTabDepth+child+2) << "" << endl; - } - f << tabs(minTabDepth+1) << "" << endl; - - return true; -} - - -bool FilterTree::hasHazardousContents() const -{ - //Check the filter system for "hazardous" contents. - // each filter defines what it believes is "hazardous" - for(tree::pre_order_iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if ((*it)->canBeHazardous()) - return true; - } - - return false; -} - -void FilterTree::stripHazardousContents() -{ - for(tree::pre_order_iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if ((*it)->canBeHazardous()) - { - //delete filters from this branch - for(tree::pre_order_iterator itj(it); itj!=filters.end(); itj++) - delete *itj; - - - //nuke this branch - it=filters.erase(it); - --it; - } - } - -} - -bool FilterTree::isChild(const tree &treeInst, - tree::iterator testParent, - tree::iterator testChild) -{ - // NOTE: A comparison against tree root (treeInst.begin())is INVALID - // for trees that have multiple base nodes. - while(treeInst.depth(testChild)) - { - testChild=treeInst.parent(testChild); - - if(testChild== testParent) - return true; - } - - return false; -} - -bool FilterTree::contains(const Filter *f) const -{ - return std::find(filters.begin(),filters.end(),f) != filters.end(); -} - -size_t FilterTree::countChildFilters(const tree &treeInst, - const vector::iterator> &nodes) -{ - set childIts; - for(size_t ui=0;ui::pre_order_iterator it=nodes[ui]; - it!=treeInst.end();++it) - childIts.insert(*it); - - } - - return childIts.size()-nodes.size(); -} - - -#ifdef DEBUG -void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &curData, - const Filter *refreshFilter) const -{ - - //Filter outputs should - // - never be null pointers. - for(size_t ui=0; ui::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if(*it == curData[ui]->parent) - found=true; - } - - ASSERT(found); - } - - //Filter outputs should - // - never contain duplicate pointers - for(size_t ui=0; uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *ionData; - ionData=((const IonStreamData *)f); - - ASSERT(ionData->data.size()); - break; - } - default: - ; - } - - } - - //Filter outputs should - // - Always have isCached set to 0 or 1. - // - Filter should report that it has a cache, if it is emitting cached objects - // - If caching is disabled, filter should not be caching objects - bool hasSomeCached=false; - for(size_t ui=0; uicached == 1 || - curData[ui]->cached == 0); - - if(curData[ui]->parent == refreshFilter) - { - if(!(refreshFilter->cacheEnabled()) ) - { - ASSERT(curData[ui]->cached==0); - } - hasSomeCached|=curData[ui]->cached; - } - } - - ASSERT(!(hasSomeCached == false && refreshFilter->haveCache())); - - //Filter outputs for this filter should - // -only be from those specified in filter emit mask - for(size_t ui=0; uiparent) - { - cerr << "Warning: orphan filter stream (FilterStreamData::parent == 0)." << - "This must be set when creating new filter streams in the ::refresh function for the filter." << endl; - cerr << "Filter :" << refreshFilter->getUserString() << "Stream Type: " << - STREAM_NAMES[getBitNum(curData[ui]->getStreamType())] << endl; - } - else if(curData[ui]->parent == refreshFilter) - { - //Check we emitted something that our parent's emit mask said we should - // by performing bitwise ops - ASSERT(curData[ui]->getStreamType() & - refreshFilter->getRefreshEmitMask()); - } - } - - //plot output streams should only have known types - //for various identfiers - for(size_t ui=0; uigetStreamType() != STREAM_TYPE_PLOT) - continue; - - const PlotStreamData *p; - p =(const PlotStreamData*)curData[ui]; - -#ifdef DEBUG - p->checkSelfConsistent(); -#endif - } - - //Voxel output streams should only have known types - for(size_t ui=0; uigetStreamType() != STREAM_TYPE_VOXEL) - continue; - - const VoxelStreamData *p; - p =(const VoxelStreamData*)curData[ui]; - - //Must have valid representation - ASSERT(p->representationType< VOXEL_REPRESENT_END); - } - -} -#endif - -void FilterTree::safeDeleteFilterList( - std::list > > &outData, - size_t typeMask, bool maskPrevents) const -{ - //Loop through the list of vectors of filterstreamdata, then drop any elements that are deleted - for(list > > ::iterator it=outData.begin(); - it!=outData.end(); ) - { - //Note the No-op at the loop iterator. this is needed so we can safely .erase() - for(size_t ui=0;uisecond.size();ui++) - { - //Don't operate on streams if we have a nonzero mask, and the (mask is active XOR mask mode) - //NOTE: the XOR flips the action of the mask. if maskprevents is true, then this logical switch - //prevents the masked item from being deleted. if not, ONLY the maked types are deleted. - //In any case, a zero mask makes this whole thing not do anything, and everything gets deleted. - if(typeMask && ( ((bool)(it->second[ui]->getStreamType() & typeMask)) ^ !maskPrevents)) - continue; - - switch(it->second[ui]->getStreamType()) - { - case STREAM_TYPE_IONS: - { - //Iterator points to vector. Typecast elements in vector to IonStreamData - const IonStreamData *ionData; - ionData=((const IonStreamData *)(it->second[ui])); - - ASSERT(ionData->cached == 1 || - ionData->cached == 0); - - if(!ionData->cached) - delete ionData; - break; - } - case STREAM_TYPE_PLOT: - { - const PlotStreamData *plotData; - plotData=((PlotStreamData *)it->second[ui]); - - ASSERT(plotData->cached == 1 || - plotData->cached == 0); - if(!plotData->cached) - delete plotData; - - break; - } - case STREAM_TYPE_DRAW: - { - DrawStreamData *drawData; - drawData=((DrawStreamData *)it->second[ui]); - - ASSERT(drawData->cached == 1 || - drawData->cached == 0); - if(drawData->cached) - delete drawData; - break; - } - case STREAM_TYPE_RANGE: - //Range data has no allocated pointer - break; - case STREAM_TYPE_VOXEL: - { - //Iterator points to vector. Typecast elements in vector to VoxelStreamData - const VoxelStreamData *voxelData; - voxelData=((const VoxelStreamData *)(it->second[ui])); - - ASSERT(voxelData->cached == 1 || - voxelData->cached == 0); - - if(!voxelData->cached) - delete voxelData; - break; - } - default: - ASSERT(false); - } - - - std::swap((it->second[ui]),it->second.back()); - it->second.pop_back(); - } - - //Check to see if this element still has any items in its vector. if not, - //then discard the element - if(!(it->second.size())) - it=outData.erase(it); - else - ++it; - - } -} - -void FilterTree::getFiltersByType(std::vector &filtersOut, unsigned int type) const -{ - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if((*it)->getType() == type) - filtersOut.push_back(*it); - } -} - -void FilterTree::purgeCache() -{ - for(tree::iterator it=filters.begin();it!=filters.end();++it) - (*it)->clearCache(); -} - -bool FilterTree::hasStateOverrides() const -{ - for(tree::iterator it=filters.begin(); it!=filters.end(); ++it) - { - vector overrides; - (*it)->getStateOverrides(overrides); - - if(overrides.size()) - return true; - } - - return false; -} - - -void FilterTree::addFilter(Filter *f,const Filter *parentFilter) -{ - if(parentFilter) - { - tree::iterator it= std::find(filters.begin(),filters.end(),parentFilter); - - ASSERT(it != filters.end()); - - //Add the child to the tree - filters.append_child(it,f); - } - else - { - if(filters.empty()) - filters.insert(filters.begin(),f); - else - filters.insert_after(filters.begin(),f); - } - - //Topology has changed, notify filters - initFilterTree(); -} - -void FilterTree::addFilterTree(FilterTree &f, const Filter *parent) -{ - //The insert_subtree and insert_subtree_after algorithms - // apparently work across multiple trees, I think, after examining tree::merge - if(parent) - { - tree::pre_order_iterator it; - it=std::find(filters.begin(),filters.end(),parent); - ASSERT(it!=filters.end()); - - it=filters.append_child(it,0); - filters.insert_subtree(it,f.filters.begin()); - filters.erase(it); - } - else - { - if(filters.empty()) - filters.insert_subtree(filters.begin(),f.filters.begin()); - else - filters.insert_subtree_after(filters.begin(),f.filters.begin()); - } - - f.filters.clear(); -} - -bool FilterTree::copyFilter(Filter *toCopy,const Filter *newParent) -{ - //Copy a filter child to a filter child - if(newParent) - { - - ASSERT(toCopy && newParent && - !(toCopy==newParent)); - - //Look for both newparent and sibling iterators - bool found[2] = {false,false}; - tree::iterator moveFilterIt,parenterIt; - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if(!found[0]) - { - if(*it == toCopy) - { - moveFilterIt=it; - found[0]=true; - } - } - if(!found[1]) - { - if(*it == newParent) - { - parenterIt=it; - found[1]=true; - } - } - - if(found[0] && found[1] ) - break; - } - - ASSERT(found[0] && found[1] ); - - //ensure that this is actually a parent-child relationship - for(tree::pre_order_iterator it(moveFilterIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(moveFilterIt) >= filters.depth(it) && it!=moveFilterIt ) - break; - - if(it == parenterIt) - return false; - } - - //Move the "tomove" filter, and its children to be a child of the - //newly nominated parent (DoCS* "adoption" you might say.) - //*DoCs : Department of Child Services (bad taste .au joke) - if(parenterIt != moveFilterIt) - { - //Create a temporary tree and copy the contents into here - tree tmpTree; - tree::iterator node= tmpTree.insert(tmpTree.begin(),0); - tmpTree.replace(node,moveFilterIt); //Note this doesn't kill the original - - //Replace each of the filters in the temporary_tree with a clone of the original - for(tree::iterator it=tmpTree.begin();it!=tmpTree.end(); ++it) - *it= (*it)->cloneUncached(); - - //In the original tree, create a new null node - node = filters.append_child(parenterIt,0); - //Replace the node with the tmpTree's contents - filters.replace(node,tmpTree.begin()); - - } - - initFilterTree(); - return parenterIt != moveFilterIt; - } - else - { - //copy a selected base of the tree to a new base component - - //Look for both newparent and sibling iterators - bool found = false; - tree::iterator moveFilterIt; - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if(*it == toCopy) - { - moveFilterIt=it; - found=true; - break; - } - } - - if(!found) - return false; - - //Create a temporary tree and copy the contents into here - tree tmpTree; - tree::iterator node= tmpTree.insert(tmpTree.begin(),0); - tmpTree.replace(node,moveFilterIt); //Note this doesn't kill the original - - //Replace each of the filters in the temporary_tree with a clone of the original - for(tree::iterator it=tmpTree.begin();it!=tmpTree.end(); ++it) - *it= (*it)->cloneUncached(); - - //In the original tree, create a new null node - node = filters.insert_after(filters.begin(),0); - //Replace the node with the tmpTree's contents - filters.replace(node,tmpTree.begin()); - initFilterTree(); - return true; - } - - ASSERT(false); -} - - -void FilterTree::removeSubtree(Filter *removeFilt) -{ - ASSERT(removeFilt); - - //Remove element and all children - for(tree::pre_order_iterator filtIt=filters.begin(); - filtIt!=filters.end(); ++filtIt) - { - if(removeFilt == *filtIt) - { - - for(tree::pre_order_iterator it(filtIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(filtIt) >= filters.depth(it) && it!=filtIt ) - break; - - //Delete the children filters. - delete *it; - } - - //Remove the children from the tree - filters.erase_children(filtIt); - filters.erase(filtIt); - break; - } - - } - - //Topology has changed, notify filters - initFilterTree(); -} - -void FilterTree::cloneSubtree(FilterTree &f,Filter *targetFilt) const -{ - ASSERT(!f.filters.size()); //Should only be passing empty trees - - tree::iterator targetIt=std::find(filters.begin(),filters.end(),targetFilt); - //Filter should exist. - ASSERT(targetIt!=filters.end()); - - tree::iterator node= f.filters.insert(f.filters.begin(),0); - f.filters.replace(node,targetIt); //Note this doesn't kill the original - - - //Replace each of the filters in the output tree with a clone of the original - //rather than the actual subtree - for(tree::iterator it=f.filters.begin();it!=f.filters.end(); ++it) - *it= (*it)->cloneUncached(); - - -} - -void FilterTree::setCachePercent(unsigned int newCache) -{ - ASSERT(newCache <= 100); - if(!newCache) - cacheStrategy=CACHE_NEVER; - else - { - cacheStrategy=CACHE_DEPTH_FIRST; - maxCachePercent=newCache; - } -} - -bool FilterTree::hasUpdates() const -{ - for(tree::iterator it=filters.begin();it!=filters.end();++it) - { - if((*it)->monitorNeedsRefresh()) - return true; - } - - return false; -} - - -bool FilterTree::reparentFilter(Filter *f, const Filter *newParent) -{ - - ASSERT(f && !(f==newParent)); - - tree::iterator replaceNode,parentFilterIt ; - tree::iterator moveFilterIt=filters.end(); - //If we are moing to the base, then that is a special case. - if(!newParent) - { - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if(*it == f) - { - moveFilterIt=it; - break; - } - } - - } - else - { - - //Look for both newparent and sibling iterators - bool found[2] = {false,false}; - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if(!found[0]) - { - if(*it == f) - { - moveFilterIt=it; - found[0]=true; - } - } - if(!found[1]) - { - if(*it == newParent) - { - parentFilterIt=it; - found[1]=true; - } - } - - if(found[0] && found[1] ) - break; - } - - ASSERT(parentFilterIt!=moveFilterIt); - ASSERT(found[0] && found[1] ); - - //ensure that this is actually a parent-child relationship, and not the other way around! - for(tree::pre_order_iterator it(moveFilterIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(moveFilterIt) >= filters.depth(it) && it!=moveFilterIt ) - break; - - if(it == parentFilterIt) - return false; - } - - } - - ASSERT(moveFilterIt!=filters.end()); - - //clear the cache of filters - //---- - //clear children - for(tree::pre_order_iterator it(moveFilterIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(moveFilterIt) == filters.depth(it)) - continue; - (*it)->clearCache(); - } - - //Erase the cache of moveFilterIt, and then move it to a new location - (*moveFilterIt)->clearCache(); - if(!newParent) - { - //create a dummy node, ready to be replaced - replaceNode=filters.insert_after(filters.begin(),0); - } - else - { - //Set the new target location to replace - replaceNode= filters.append_child(parentFilterIt,0); - } - //---- - - //Create a dummy node after this parent - //This doesn't actually nuke the original subtree, but rather copies it, - //replacing the dummy node. - filters.replace(replaceNode,moveFilterIt); - //Nuke the original subtree - filters.erase(moveFilterIt); - //-------- - - //Topology of filter tree has changed. - //some filters may need to know about this - initFilterTree(); - - return true; -} - - -void FilterTree::clearCache(const Filter *filter) -{ - if(!filter) - { - //Invalidate everything - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - (*it)->clearCache(); - } - else - { - //Find the filter in the tree - tree::iterator filterIt; - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if(*it == filter) - { - filterIt=it; - break; - } - } - - for(tree::pre_order_iterator it(filterIt);it!= filters.end(); ++it) - { - //Do not traverse siblings - if(filters.depth(filterIt) >= filters.depth(it) && it!=filterIt ) - break; - - (*it)->clearCache(); - } - } -} - -void FilterTree::clearCacheByType(unsigned int type) -{ - //Build a list of all filters who we need to invalidate - // Note that we cannot do this directly on the filter ptr, - // as we also need to invalidate children, so re-use the clearCache function - for(tree::iterator it=filters.begin(); - it!=filters.end(); ++it) - { - if((*it)->getType() == type) - clearCache(*it); - } - -} diff -Nru 3depict-0.0.12/src/filtertree.h 3depict-0.0.13/src/filtertree.h --- 3depict-0.0.12/src/filtertree.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/filtertree.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -/* - * filtertree.h - Filter tree topology and data propagation handling - * Copyright (C) 2012, 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 . -*/ - -#ifndef FILTERTREE_H -#define FILTERTREE_H - -#include "tree.hh" -#include "select.h" -#include "filter.h" - - -class FilterTree -{ - private: - - - //!Caching strategy - unsigned int cacheStrategy; - - //!Maximum size for cache (percent of available ram). - float maxCachePercent; - - //!Filters that provide and act upon datastreams. - tree filters; - - - //!Get the filter refresh seed points in tree, by examination of tree caches, block/emit of filters - //and tree topology - void getFilterRefreshStarts(vector::iterator > &propStarts) const; - - - //Retrieve the filter's pointer from its ID value - Filter* getFilterByIdNonConst(unsigned long long filterId) const; - -#ifdef DEBUG - //!Check that the output of filter refresh functions - void checkRefreshValidity(const vector< const FilterStreamData *> &curData, - const Filter *refreshFilter) const; -#endif - - - //TODO: Move me to tree.hh - //!Returns true if the testChild is a child of testParent. - // returns false if testchild == testParent, or if the testParent - // is not a parent of testChild. - static bool isChild(const tree &treeInst, - tree::iterator testParent, - tree::iterator testChild); - - - static size_t countChildFilters(const tree &treeInst, - const vector::iterator> &nodes); - public: - FilterTree(); - ~FilterTree(); - - FilterTree(const FilterTree &orig); - - void swap(FilterTree &); - //Note that the = operator creates a *CLONE* of the orignal tree, - // not an exact duplicate. underlying pointers will not be the same - const FilterTree &operator=(const FilterTree &orig); - - //Return iterator to tree contents begin. - tree::pre_order_iterator depthBegin() const { return filters.begin();}; - //Return iterator to tree contents end - tree::pre_order_iterator depthEnd() const { return filters.end();} - //Return depth of a given iterator - size_t maxDepth() const; - - size_t depth(const tree::pre_order_iterator &it) const - { ASSERT(std::find(filters.begin(),filters.end(),*it)!=filters.end()); return filters.depth(it);}; - - //Get a reference to the underlying tree - const tree &getTree() const { return filters;} - - //!Return the number of filters - size_t size() const {return filters.size();}; - - //!Remove all tree contents - void clear(); - - bool contains(const Filter *f) const; - - //Refresh functions - //--- - //!Run the initialisation stage of the filter processing - void initFilterTree() const; - - bool setFilterProperty(Filter *f, unsigned int key, - const std::string &value, bool &needUpdate); - - //!Refresh the entire filter tree. Whilst this is public, great care must be taken in - // deleting the filterstream data correctly. To do this, use the "safeDeleteFilterList" function. - unsigned int refreshFilterTree( - std::list > > &outData, - std::vector *> &devices,std::vector > &consoleMessages, - ProgressData &curProg, bool (*callback)(bool)); - - //!Safely delete data generated by refreshFilterTree(...). - //a mask can be used to *prevent* STREAM_TYPE_blah from being deleted. Deleted items are removed from the list. - void safeDeleteFilterList(std::list > > &outData, - size_t typeMask=STREAMTYPE_MASK_ALL, bool maskPrevents=false) const; - - void getAccumulatedPropagationMaps(map &emitTypes, map &blockTypes) const; - //--- - - - //!function for the loading of a filter tree from its XML representation - unsigned int loadXML(const xmlNodePtr &treeParent, - std::ostream &errStream, const std::string &stateDir); - - - //Write out the filters into their XML representation - bool saveXML(std::ofstream &f, std::map &fileMapping, - bool writePackage, bool useRelativePaths, unsigned int minTabDepth=0) const; - - - //Topological alteration & examination functions - //---------- - //!Remove an element and all sub elements from the tree, - void removeSubtree(Filter *f); - - //!Add a new filter to the tree. Note that pointer will be released - // by filter destructor - void addFilter(Filter *f, const Filter *parent); - - //!Add a new tree as a subtree to a node - void addFilterTree(FilterTree &f, const Filter *parent); - - //!Move a branch of the tree to a new position - bool reparentFilter(Filter *f, const Filter *newParent); - //!Duplicate a branch of the tree to a new position. Do not copy cache, - bool copyFilter(Filter *id, const Filter *newParent); - - //Obtain a copy of the filters in the specified subtree - void cloneSubtree(FilterTree &f,Filter *targetFilt) const; - //--------- - - - //Filter alteration functions - //--------- - //!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 type of filter - // and all their children. - void clearCacheByType(unsigned int type); - - //!Return all of a given type of filter from the filter tree - void getFiltersByType(std::vector &filters, unsigned int type) const; - - //!Make the filter system safe (non-hazardous) - void removeHazardousContents(); - - - //!Used to remove potentially hazardous filters - //(filters that can do nasty things to computers, like executing commands) - //which may have come from unsafe sources - void stripHazardousContents(); - - //!return true if the tree contains hazardous filters - bool hasHazardousContents() const ; - - //!Force a wipe of all caches in the filter tree - void purgeCache(); - - - //!Returns true if any of the filters (incl. stash) - //return a state override (i.e. refer to external entities, such as files) - bool hasStateOverrides() const ; - - bool hasUpdates() const ; - - //--------- - - void setCachePercent(unsigned int newCache); -}; - -#endif diff -Nru 3depict-0.0.12/src/filtertreeAnalyse.cpp 3depict-0.0.13/src/filtertreeAnalyse.cpp --- 3depict-0.0.12/src/filtertreeAnalyse.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/filtertreeAnalyse.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,451 +0,0 @@ -#include "filtertreeAnalyse.h" - -#include "translation.h" - -#include "filter.h" - -//Needed to obtain filter data keys -//---- -#include "filters/dataLoad.h" -#include "filters/ionDownsample.h" -#include "filters/compositionProfile.h" -#include "filters/ionInfo.h" -//---- - -void FilterTreeAnalyse::getAnalysisResults(std::vector &errs) const -{ - errs.resize(analysisResults.size()); - std::copy(analysisResults.begin(),analysisResults.end(),errs.begin()); -} - -void FilterTreeAnalyse::analyse(const FilterTree &f) -{ - f.getAccumulatedPropagationMaps(emitTypes,blockTypes); - - //Check for a data pair where the output is entirely blocked, - // rendering computation of filter useless - blockingPairError(f); - - //Check for spatial sampling altering some results in later analyses - spatialSampling(f); - - //Check for compositional biasing altering some later anaylsis - compositionAltered(f); - - emitTypes.clear(); - blockTypes.clear(); - -} - - - - -void FilterTreeAnalyse::blockingPairError(const FilterTree &f) -{ - //Examine the emit and block/use masks for each filter's parent (emit) - // child relationship(block/use), such that in the case of a child filter that is expecting - // a particular input, but the parent cannot generate it - - const tree &treeFilt=f.getTree(); - for(tree::pre_order_iterator it = treeFilt.begin(); it!=treeFilt.end(); ++it) - { - - tree_node_ *myNode=it.node->first_child; - - size_t parentEmit; - parentEmit = emitTypes[(*it) ]| (*it)->getRefreshEmitMask(); - - while(myNode) - { - Filter *childFilter; - childFilter = myNode->data; - - size_t curBlock,curUse; - curBlock=blockTypes[childFilter] | childFilter->getRefreshBlockMask(); - curUse=childFilter->getRefreshUseMask(); - - //If the child filter cannot use and blocks all parent emit values - // emission of the all possible output filters, - // then this is a bad filter pairing - bool passedThrough; - passedThrough=parentEmit & ~curBlock; - - if(!parentEmit && curUse) - { - FILTERTREE_ERR treeErr; - treeErr.reportedFilters.push_back(childFilter); - treeErr.reportedFilters.push_back(*it); - treeErr.verboseReportMessage = TRANS("Parent filter has no output, but filter requires input -- there is no point in placing a child filter here."); - treeErr.shortReportMessage = TRANS("Leaf-only filter with child"); - treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing. - - analysisResults.push_back(treeErr); - } - else if(!(parentEmit & curUse) && !passedThrough ) - { - FILTERTREE_ERR treeErr; - treeErr.reportedFilters.push_back(childFilter); - treeErr.reportedFilters.push_back(*it); - treeErr.verboseReportMessage = TRANS("Parent filters' output will be blocked by child, without use. Parent results will be dropped."); - treeErr.shortReportMessage = TRANS("Bad parent->child pair"); - treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing. - - analysisResults.push_back(treeErr); - } - //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()) - { - FILTERTREE_ERR treeErr; - treeErr.reportedFilters.push_back(childFilter); - treeErr.reportedFilters.push_back(*it); - treeErr.verboseReportMessage = TRANS("First filter does not output anything useable by child filter. Child filter not useful."); - treeErr.shortReportMessage = TRANS("Bad parent->child pair"); - treeErr.severity=ANALYSE_SEVERITY_ERROR; //This is definitely a bad thing. - - analysisResults.push_back(treeErr); - - } - - - //Move to next sibling - myNode = myNode->next_sibling; - } - - - } - -} - -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: - { - affected=true; - break; - } - } - - return affected; -} - - -void FilterTreeAnalyse::spatialSampling(const FilterTree &f) -{ - //True if spatial sampling is (probably) happening for children of - //filter. - vector affectedFilters; - affectedFilters.push_back(FILTER_TYPE_CLUSTER_ANALYSIS); //If have range parent - affectedFilters.push_back(FILTER_TYPE_COMPOSITION); //If using density - affectedFilters.push_back(FILTER_TYPE_SPATIAL_ANALYSIS); //If using density - - const tree &treeFilt=f.getTree(); - for(tree::pre_order_iterator it(treeFilt.begin()); it!=treeFilt.end(); it++) - { - //Check to see if we have a filter that can cause sampling - if(filterIsSampling(*it)) - { - tree_node_ *childNode=it.node->first_child; - - if(childNode) - { - - //TODO: Not the most efficient method of doing this... - //shouldn't need to continually compute depth to iterate over children - size_t minDepth=treeFilt.depth(it); - for(tree::pre_order_iterator itJ(childNode); treeFilt.depth(itJ) > minDepth;itJ++) - { - //ignore filters that are not affected by spatial sampling - size_t filterType; - filterType=(*itJ)->getType(); - if(std::find(affectedFilters.begin(),affectedFilters.end(),filterType)== affectedFilters.end()) - continue; - - childNode=itJ.node; - - //Check to see if we have a "range" type ancestor - // - we will need to know this in a second - bool haveRngParent=false; - { - tree_node_ *ancestor; - ancestor = childNode->parent; - while(true) - { - if(ancestor->data->getType() == FILTER_TYPE_RANGEFILE) - { - haveRngParent=true; - break; - } - - if(!ancestor->parent) - break; - - ancestor=ancestor->parent; - - } - } - - if(affectedBySampling(*itJ,haveRngParent)) - { - FILTERTREE_ERR treeErr; - treeErr.reportedFilters.push_back(*it); - treeErr.reportedFilters.push_back(*itJ); - treeErr.shortReportMessage=TRANS("Spatial results possibly altered"); - treeErr.verboseReportMessage=TRANS("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."); treeErr.severity=ANALYSE_SEVERITY_WARNING; - - analysisResults.push_back(treeErr); - } - } - } - - //No need to walk child nodes - it.skip_children(); - } - - - - } -} - - -bool filterAltersComposition(const Filter *f) -{ - bool affectsComposition=false; - - - FilterPropGroup props; - f->getProperties(props); - - - - switch(f->getType()) - { - case FILTER_TYPE_IONDOWNSAMPLE: - { - FilterProperty p; - if(!props.hasProp(KEY_IONDOWNSAMPLE_PERSPECIES)) - return false; - - p=props.getPropValue(KEY_IONDOWNSAMPLE_PERSPECIES); - - - if(p.data== "1") - { - vector propVec; - const int GROUP_SAMPLING=1; - props.getGroup(GROUP_SAMPLING,propVec); - - //If using per-species mode, then - // we may affect the output ion composition - // if we have differing values - for(size_t ui=1;uigetProperties(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); - - //Affected if using normalise mode, and we do have a range parent - affected= (p.data== "1" && haveRngParent); - break; - } - case FILTER_TYPE_SPATIAL_ANALYSIS: - { - affected=true; - break; - } - } - - return affected; -} - -//FIXME: This is largely a cut and paste of ::spatialSampling - could be unified through -// function pointers and friends -void FilterTreeAnalyse::compositionAltered(const FilterTree &f) -{ - //True if composition biasing is (probably) happening for children of - //filter. - vector affectedFilters; - affectedFilters.push_back(FILTER_TYPE_CLUSTER_ANALYSIS); //If have range parent - affectedFilters.push_back(FILTER_TYPE_COMPOSITION); //By definition - affectedFilters.push_back(FILTER_TYPE_IONINFO); //If using composition - - const tree &treeFilt=f.getTree(); - for(tree::pre_order_iterator it(treeFilt.begin()); it!=treeFilt.end(); it++) - { - //Check to see if we have a filter that can cause sampling - if(filterAltersComposition(*it)) - { - tree_node_ *childNode=it.node->first_child; - - if(childNode) - { - - //TODO: Not the most efficient method of doing this... - //shouldn't need to continually compute depth to iterate over children - size_t minDepth=treeFilt.depth(it); - for(tree::pre_order_iterator itJ(childNode); treeFilt.depth(itJ) > minDepth;itJ++) - { - //ignore filters that are not affected by spatial sampling - size_t filterType; - filterType=(*itJ)->getType(); - if(std::find(affectedFilters.begin(),affectedFilters.end(),filterType)== affectedFilters.end()) - continue; - - childNode=itJ.node; - - //Check to see if we have a "range" type ancestor - // - we will need to know this in a second - bool haveRngParent=false; - { - tree_node_ *ancestor; - ancestor = childNode->parent; - while(true) - { - if(ancestor->data->getType() == FILTER_TYPE_RANGEFILE) - { - haveRngParent=true; - break; - } - - if(!ancestor->parent) - break; - - ancestor=ancestor->parent; - - } - } - - if(filterAffectedByComposition(*itJ,haveRngParent)) - { - FILTERTREE_ERR treeErr; - treeErr.reportedFilters.push_back(*it); - treeErr.reportedFilters.push_back(*itJ); - treeErr.shortReportMessage=TRANS("Composition results possibly altered"); - treeErr.verboseReportMessage=TRANS("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."); - treeErr.severity=ANALYSE_SEVERITY_WARNING; - - analysisResults.push_back(treeErr); - } - } - } - - //No need to walk child nodes - it.skip_children(); - } - - - - } -} diff -Nru 3depict-0.0.12/src/filtertreeAnalyse.h 3depict-0.0.13/src/filtertreeAnalyse.h --- 3depict-0.0.12/src/filtertreeAnalyse.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/filtertreeAnalyse.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* - * filtertree.h - Filter tree topology and data propagation handling - * Copyright (C) 2012, 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 . -*/ - -#ifndef FILTERTREEANALYSE_H -#define FILTERTREEANALYSE_H - -#include "filtertree.h" - -#include -#include -#include - -enum -{ - ANALYSE_SEVERITY_WARNING, // Probable warning - ANALYSE_SEVERITY_ERROR, // definite error - ANALYSE_SEVERITY_END_ENUM // Not a severity, just end of enum -}; - -struct FILTERTREE_ERR -{ - //The filters that are associated with the error messages - std::vector reportedFilters; - //Error messages associated with the reported filters - std::string verboseReportMessage,shortReportMessage; - - unsigned int severity; -}; - - -class FilterTreeAnalyse -{ - private: - std::vector analysisResults; - - - //Accumulated emit and block masks for the filter tree - // these are only valid during the call to ::analyse - std::map emitTypes; //Whatever types can be emitted from this filer, considering this filter's ancestors in tree, not incl. self - std::map blockTypes; //Whatever types can be blocked by this filter, considering this filter's children in tree, not incl. self - - //!Detect misconfiguration of the filter tree - // where parent emits something that the child - // cannot use - void blockingPairError( const FilterTree &f); - - //!Detect case where algorithms that depend - // upon there being no spatial sampling - // are being used with sampling. - void spatialSampling(const FilterTree &f); - - void compositionAltered(const FilterTree &f); - public: - void analyse(const FilterTree &f); - - void getAnalysisResults(std::vector &errs) const; - - void clear() {analysisResults.clear();}; -}; - - -#endif - diff -Nru 3depict-0.0.12/src/gl/cameras.cpp 3depict-0.0.13/src/gl/cameras.cpp --- 3depict-0.0.12/src/gl/cameras.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/cameras.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1109 @@ +/* + * cameras.cpp - opengl camera implementations + * 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 . +*/ + +#include "cameras.h" + +#include "common/xmlHelper.h" +#include "common/stringFuncs.h" +#include "common/constants.h" + +//MacOS is "special" and puts it elsewhere +#ifdef __APPLE__ + #include +#else + #include +#endif +#include "common/translation.h" + + +//TODO: FIXME: Orthogonal camera zooming is very slow, compared to +// perspective camera dolly. Check equations of motion for equivalence +const float ORTHO_SPEED_HACK=1.05; + + +//!Key types for property setting and getting via property grids +enum +{ + KEY_LOOKAT_LOCK, + KEY_LOOKAT_ORIGIN, + KEY_LOOKAT_TARGET, + KEY_LOOKAT_UPDIRECTION, + KEY_LOOKAT_FOV, + KEY_LOOKAT_PROJECTIONMODE, + KEY_LOOKAT_ORTHOSCALE +}; + + + +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() +{ +} + + +Point3D Camera::getOrigin() const +{ + return origin; +} + +Point3D Camera::getViewDirection() const +{ + return viewDirection; +} + +Point3D Camera::getUpDirection() const +{ + return upDirection; +} + +void Camera::setOrigin(const Point3D &pt) +{ + if(lock) + return; + origin=pt; +} + +void Camera::setViewDirection(const Point3D &pt) +{ + if(lock) + return; + viewDirection=pt; + viewDirection.normalise(); +} + +void Camera::setUpDirection(const Point3D &pt) +{ + if(lock) + return; + upDirection = pt; + upDirection.normalise(); +} + +void Camera::forwardsDolly(float moveRate) +{ + if(lock) + return; + origin=origin+ viewDirection*moveRate; +} + +void Camera::move(float moveLR, float moveUD) +{ + if(lock) + return; + //Right is the cross product of up and + //view direction (check sign) + //Up is simply the up vector + origin+=upDirection*moveUD + (upDirection.crossProd(viewDirection))*moveLR; +} + +void Camera::translate(float moveLR, float moveUD) +{ + if(lock) + return; + //This camera has no target. Just do plain move + move(moveLR,moveUD); +} + +void Camera::pivot(float lrRad, float udRad) +{ + if(lock) + return; + Point3f viewNew, rotateAxis; + + //rotate normalised rOrig around axis one then two + viewNew.fx=viewDirection[0]; + viewNew.fy=viewDirection[1]; + viewNew.fz=viewDirection[2]; + + //rotate around "right" axis + Point3D tmp = upDirection.crossProd(viewDirection); + rotateAxis.fx=tmp[0]; + rotateAxis.fy=tmp[1]; + rotateAxis.fz=tmp[2]; + quat_rot(&viewNew,&rotateAxis,udRad); + + //rotate around original "up" axis + rotateAxis.fx=upDirection[0]; + rotateAxis.fy=upDirection[1]; + rotateAxis.fz=upDirection[2]; + quat_rot(&viewNew,&rotateAxis,lrRad); + + viewDirection[0] = rotateAxis.fx; + viewDirection[1] = rotateAxis.fy; + viewDirection[2] = rotateAxis.fz; + +} + +//===== + + +//===== + +CameraLookAt::CameraLookAt() : target(Point3D(0,0,0)),fovAngle(90.0f), + nearPlane(1.0f), frustumDistortion(0.0f) +{ + origin=Point3D(0.0f,0.0f,1.0f); + viewDirection=Point3D(0.0f,0.0f,-1.0f); + upDirection=Point3D(0.0f,1.0f,0.0f); + + typeNum=CAM_LOOKAT; + projectionMode=PROJECTION_MODE_PERSPECTIVE; +} + +Camera *CameraLookAt::clone() const +{ + CameraLookAt *retCam = new CameraLookAt; + + retCam->origin =origin; + retCam->viewDirection=viewDirection; + retCam->upDirection =upDirection; + retCam->projectionMode=projectionMode; + retCam->orthoScale=orthoScale; + retCam->typeNum=typeNum; + retCam->userString=userString; + retCam->lock=lock; + + retCam->target = target; + retCam->fovAngle = fovAngle; + retCam->nearPlane=nearPlane; + retCam->farPlane=farPlane; + + + return retCam; +} + +CameraLookAt::~CameraLookAt() +{ +} + +void CameraLookAt::setTarget(const Point3D &pt) +{ + ASSERT(pt.sqrDist(origin)>10.0f*std::numeric_limits::epsilon()); + target=pt; + recomputeViewDirection(); +} + +Point3D CameraLookAt::getTarget() const +{ + return target; +} + +void CameraLookAt::doPerspCalcs(float aspectRatio, const BoundCube &bc,bool loadIdentity) const +{ + ASSERT(projectionMode == PROJECTION_MODE_PERSPECTIVE); + + glMatrixMode (GL_PROJECTION); + if(loadIdentity) + glLoadIdentity(); + + //As the far plane is dynamically computed, similarly + //bring the near plane to a constant factor of the far plane + // that way, when the far plane comes in, so should the near plane + // this factor is only somewhat arbitrary, as it is based upon the + // number of significant figures in a 32 bit float + const float NEAR_PLANE_FACTOR=1.0f/10000.0f; + + farPlane = 1.5f*bc.getMaxDistanceToBox(origin); + gluPerspective(fovAngle/2.0,aspectRatio,farPlane*NEAR_PLANE_FACTOR,farPlane); + glMatrixMode(GL_MODELVIEW); + + glTranslatef(origin[0],origin[1],origin[2]); + + //As gluperspective defaults to viewing down the 0,0,-1 axis + //we must rotate the scene such that the view direction + //is brought into line with the default view vector + Point3D rotVec,defaultDir(0,0,-1.0f); + float rotAngle; + + + rotVec = viewDirection.crossProd(defaultDir); + + + rotAngle = 180.0f/M_PI * viewDirection.angle(defaultDir); + + glRotatef(-rotAngle,rotVec[0],rotVec[1],rotVec[2]); + + //Camera roll + //Default "up" direction + defaultDir[2] = 1.0f; + rotVec = upDirection.crossProd(defaultDir); + rotAngle = 180.0f/M_PI * upDirection.angle(defaultDir); + glRotatef(-rotAngle, rotVec[0], rotVec[1],rotVec[2]); + +} + +void CameraLookAt::setOrigin(const Point3D &newOrigin) +{ + if(lock) + return; + ASSERT(newOrigin.sqrDist(target)>std::numeric_limits::epsilon()); + origin=newOrigin; + recomputeViewDirection(); +} + +void CameraLookAt::apply(float aspect, const BoundCube &bc, bool loadIdentity) const +{ + + glMatrixMode (GL_PROJECTION); + if(loadIdentity) + glLoadIdentity(); + + farPlane = 1.5*bc.getMaxDistanceToBox(origin); + switch(projectionMode) + { + + case PROJECTION_MODE_PERSPECTIVE: + { + + gluPerspective(fovAngle/2.0,aspect,nearPlane,farPlane); + glMatrixMode(GL_MODELVIEW); + break; + + } + case PROJECTION_MODE_ORTHOGONAL: + { + glOrtho(-orthoScale*aspect,orthoScale*aspect,-orthoScale,orthoScale,nearPlane,farPlane); + glMatrixMode(GL_MODELVIEW); + break; + } + default: + ASSERT(false); + + } + + ASSERT(origin.sqrDist(target)>std::numeric_limits::epsilon()); + gluLookAt(origin[0],origin[1],origin[2], + target[0],target[1],target[2], + upDirection[0],upDirection[1],upDirection[2]); +} + +void CameraLookAt::apply(float aspect,const BoundCube &b,bool loadIdentity, + float leftRestrict,float rightRestrict, + float bottomRestrict,float topRestrict) const +{ + ASSERT(leftRestrict < rightRestrict); + ASSERT(bottomRestrict< topRestrict); + + glMatrixMode (GL_PROJECTION); + if(loadIdentity) + glLoadIdentity(); + + farPlane = 1.5*b.getMaxDistanceToBox(origin); + switch(projectionMode) + { + + case PROJECTION_MODE_PERSPECTIVE: + { + float width,height; + height = tan(fovAngle/2.0*M_PI/180.0f)*nearPlane; + width= height*aspect; + + + //Frustum uses eye coordinates. + if(fabs(frustumDistortion) < std::numeric_limits::epsilon()) + glFrustum(leftRestrict*width,rightRestrict*width,bottomRestrict*height, + topRestrict*height,nearPlane,farPlane); + else + { + float workingDist=farPlane;//sqrtf((target-origin).sqrMag()); + glFrustum(leftRestrict*width+frustumDistortion*nearPlane/workingDist, + rightRestrict*width+frustumDistortion*nearPlane/workingDist, + bottomRestrict*height, topRestrict*height,nearPlane,farPlane); + } + break; + } + case PROJECTION_MODE_ORTHOGONAL: + { + float l,r,b,t; + + //FIXME:I have no idea why it is 2x...AFAIK it should just be ONE. + //but this works, and one does not. + l = 2*leftRestrict*orthoScale*aspect; + r= 2*rightRestrict*orthoScale*aspect; + b= 2*bottomRestrict*orthoScale; + t = 2*topRestrict*orthoScale; + + glOrtho(l,r,b,t,nearPlane,farPlane); + break; + } + default: + ASSERT(false); + } + + glMatrixMode(GL_MODELVIEW); + + ASSERT(origin.sqrDist(target)>std::numeric_limits::epsilon()); + gluLookAt(origin[0],origin[1],origin[2], + target[0],target[1],target[2], + upDirection[0],upDirection[1],upDirection[2]); + +} + +void CameraLookAt::translate(float moveLR, float moveUD) +{ + if(lock) + return; + float fovMultiplier=1.0f; + if(projectionMode== PROJECTION_MODE_PERSPECTIVE) + { + + //Try to move such that the target sweeps our field of view + //at a constant rate. Standard normaliser is view length at + //a 90* camera + //Use tan.. to normalise motion rate + //Prevent numerical error near tan( 90*) + if(fovAngle < 175.0f) + fovMultiplier = tan(fovAngle/2.0*M_PI/180.0); + else + fovMultiplier = tan(175.0f/2.0*M_PI/180.0); + } + + + moveLR=moveLR*sqrtf(target.sqrDist(origin)*fovMultiplier); + moveUD=moveUD*sqrtf(target.sqrDist(origin)*fovMultiplier); + + origin+=upDirection*moveUD + (upDirection.crossProd(viewDirection))*moveLR; + target+=upDirection*moveUD + (upDirection.crossProd(viewDirection))*moveLR; +} + +void CameraLookAt::forwardsDolly(float moveRate) +{ + if(lock) + return; + + if(projectionMode == PROJECTION_MODE_PERSPECTIVE) + { + Point3D newOrigin; + + //Prevent camera orientation inversion, which occurs when moving past the target + if(moveRate > sqrt(target.sqrDist(origin))) + { + if((target-origin).sqrMag() < sqrtf(std::numeric_limits::epsilon())) + return; + + //Yes, this simplifies analytically. However i think the numerics come into play. + float moveInv = 1.0/(fabs(moveRate) + std::numeric_limits::epsilon()); + newOrigin=origin+viewDirection*moveInv/(1.0+moveInv); + + } + else + { + //scale moverate by orbit distance + moveRate = moveRate*sqrtf(target.sqrDist(origin)); + newOrigin=origin+viewDirection*moveRate; + } + + //Only accept origin change if it is sufficiently far from the target + if(newOrigin.sqrDist(target)>sqrtf(std::numeric_limits::epsilon())) + origin=newOrigin; + } + else + { + float deltaSqr; + deltaSqr = (target-origin).sqrMag(); + if(deltaSqr< sqrtf(std::numeric_limits::epsilon())) + return; + + Point3D virtualOrigin; + virtualOrigin = origin+viewDirection*moveRate; + + float factor; + factor = virtualOrigin.sqrDist(target)/deltaSqr; + if( factor > 1.0) + factor*=ORTHO_SPEED_HACK; + else + factor/=ORTHO_SPEED_HACK; + + orthoScale*=factor; + } +} + + +//Clockwise roll looking from camera view by rollRad radians +void CameraLookAt::roll(float rollRad) +{ + if(lock) + return; + Point3f rNew,rotateAxis; + + rotateAxis.fx=viewDirection[0]; + rotateAxis.fy=viewDirection[1]; + rotateAxis.fz=viewDirection[2]; + + rNew.fx=upDirection[0]; + rNew.fy=upDirection[1]; + rNew.fz=upDirection[2]; + quat_rot(&rNew,&rotateAxis,rollRad); + + upDirection=Point3D(rNew.fx,rNew.fy,rNew.fz); + recomputeUpDirection(); +} + +void CameraLookAt::pivot(float leftRightRad,float updownRad) +{ + if(lock) + return; + + Point3f rNew,rotateAxis; + Point3D tmp; + //rotate normalised rOrig around axis one then two + tmp=target-origin; + rNew.fx=tmp[0]; + rNew.fy=tmp[1]; + rNew.fz=tmp[2]; + + //rotate around "right" axis + tmp = upDirection.crossProd(viewDirection); + tmp.normalise(); + rotateAxis.fx=tmp[0]; + rotateAxis.fy=tmp[1]; + rotateAxis.fz=tmp[2]; + quat_rot(&rNew,&rotateAxis,updownRad); + + Point3D newDir; + newDir=Point3D(rNew.fx,rNew.fy,rNew.fz)+origin; + + //rotate around original "up" axis + rotateAxis.fx=upDirection[0]; + rotateAxis.fy=upDirection[1]; + rotateAxis.fz=upDirection[2]; + quat_rot(&rNew,&rotateAxis,leftRightRad); + + newDir+= Point3D(rNew.fx,rNew.fy,rNew.fz); + target = target+newDir; + target.normalise(); + target*=sqrtf((target).sqrDist(origin)); + + recomputeViewDirection(); + recomputeUpDirection(); +} + +//Make a given bounding box visible, as much as possible +void CameraLookAt::ensureVisible(const BoundCube &boundCube, unsigned int face) +{ + if(lock) + return; + //Face is defined by the following net + // 0 + // 1 2 3 + // 4 + // 5 + //2 is the face directed to the +ve x axis, + //with the "up"" vector on the 3 aligned to z, + //so "0" is parallel to the Z axis and is "visible" + //from the top +ve side of the z axis (at sufficient distance) + + //To make the camera visible, we must place the camera + //outside the box, on the correct face, + //at sufficient distance to ensure that the face closest + //to the box is visible at the current FOV. + + //Box centroid + Point3D boxCentroid = boundCube.getCentroid(); + + //Vector from box face to camera + Point3D faceOutVector, tmpUpVec; + + //I labelled a physical box to work this table out. + float boxToFrontDist,faceSize[2]; + switch(face) + { + case 0: + faceOutVector = Point3D(0,0,1); + boxToFrontDist=boundCube.getSize(2); + tmpUpVec = Point3D(0,1,0); + faceSize[0]=boundCube.getSize(0); + faceSize[1]=boundCube.getSize(1); + break; + case 1: + faceOutVector = Point3D(0,-1,0); + boxToFrontDist=boundCube.getSize(1); + tmpUpVec = Point3D(1,0,0); + faceSize[0]=boundCube.getSize(1); + faceSize[1]=boundCube.getSize(0); + break; + case 2: + faceOutVector = Point3D(0,1,0); + boxToFrontDist=boundCube.getSize(1); + tmpUpVec =Point3D(1,0,0); + faceSize[0]=boundCube.getSize(0); + faceSize[1]=boundCube.getSize(2); + break; + case 3: + faceOutVector = Point3D(1,0,0); + boxToFrontDist=boundCube.getSize(0); + tmpUpVec = Point3D(0,0,1); + faceSize[0]=boundCube.getSize(1); + faceSize[1]=boundCube.getSize(2); + break; + case 4: + faceOutVector = Point3D(0,0,-1); + boxToFrontDist=boundCube.getSize(2); + tmpUpVec = Point3D(0,1,0); + faceSize[0]=boundCube.getSize(0); + faceSize[1]=boundCube.getSize(1); + break; + case 5: + faceOutVector = Point3D(-1,0,0); + boxToFrontDist=boundCube.getSize(0); + tmpUpVec = Point3D(0,0,1); + faceSize[0]=boundCube.getSize(1); + faceSize[1]=boundCube.getSize(2); + break; + default: + ASSERT(false); + } + + + //Convert box to front distance to vector from + //centroid to front face. + boxToFrontDist/=2.0f; + float halfMaxFaceDim=std::max(faceSize[0],faceSize[1])/2.0; + + + ASSERT(fovAngle > 0); + + //Set camera target to inside box + target=boxCentroid; + + float outDistance; + if(projectionMode == PROJECTION_MODE_PERSPECTIVE) + { + //Minimal camera distance is given trigonometrically. + //Add additional 1 to ensure that nearplane does not clip object + outDistance=1.0+boxToFrontDist+halfMaxFaceDim/tan((fovAngle*M_PI/180)/2.0f); + } + else + { + outDistance=boxToFrontDist+halfMaxFaceDim; + } + + //Multiply by 1.4 to give a bit of border. + origin=boxCentroid+faceOutVector*1.4*outDistance; + + orthoScale = sqrtf(target.sqrDist(origin))/2.0; + + + //Set the default up direction + upDirection=tmpUpVec; + + //Reset the view direction + recomputeViewDirection(); + //Ensure up direction orthogonal + recomputeUpDirection(); + nearPlane = 1; +} + +void CameraLookAt::recomputeViewDirection() +{ + viewDirection=origin-target; + viewDirection.normalise(); +} +void CameraLookAt::recomputeUpDirection() +{ + //Use cross product of view and up to generate an across vector. + Point3D across; + upDirection.normalise(); + across = viewDirection.crossProd(upDirection); + across.normalise(); + + //Regenerate up vector by reversing the cross with a normalised across vector + upDirection = across.crossProd(viewDirection); + + upDirection.normalise(); +} + + +void CameraLookAt::move(float moveLRAngle, float moveUDAngle) +{ + if(lock) + return; + + //Think of the camera as moving around the surface of a sphere + Point3f curOrig; + curOrig.fx = origin[0] - target[0]; + curOrig.fy = origin[1] - target[1]; + curOrig.fz = origin[2] - target[2]; + + //Perform "up" rotation + Point3D rotateAxis; + + rotateAxis=upDirection; + Point3f r,u; + r.fx = rotateAxis[0]; + r.fy = rotateAxis[1]; + r.fz = rotateAxis[2]; + + u.fx = upDirection[0]; + u.fy = upDirection[1]; + u.fz = upDirection[2]; + + //Perform quaternion rotation around this axis + quat_rot(&curOrig,&r, moveLRAngle); + quat_rot(&curOrig,&u, moveLRAngle); + + recomputeViewDirection(); + //Perform across rotation + rotateAxis =upDirection.crossProd(viewDirection).normalise(); + r.fx = rotateAxis[0]; + r.fy = rotateAxis[1]; + r.fz = rotateAxis[2]; + quat_rot(&curOrig,&r, moveUDAngle); + //Get transformed coordinates + origin[0] = target[0] + curOrig.fx; + origin[1] = target[1] + curOrig.fy; + origin[2] = target[2] + curOrig.fz; + recomputeViewDirection(); +} + +void CameraLookAt::getProperties(CameraProperties &p) const +{ + p.data.clear(); + p.types.clear(); + p.keys.clear(); + + std::vector > s; + std::vector type,keys; + + if(lock) + s.push_back(std::make_pair(TRANS("Lock"),"1")); + else + s.push_back(std::make_pair(TRANS("Lock"),"0")); + + type.push_back(PROPERTY_TYPE_BOOL); + keys.push_back(KEY_LOOKAT_LOCK); + + string ptStr; + stream_cast(ptStr,origin); + s.push_back(std::make_pair(TRANS("Origin"), ptStr)); + type.push_back(PROPERTY_TYPE_POINT3D); + keys.push_back(KEY_LOOKAT_ORIGIN); + + stream_cast(ptStr,target); + s.push_back(std::make_pair(TRANS("Target"), ptStr)); + type.push_back(PROPERTY_TYPE_POINT3D); + keys.push_back(KEY_LOOKAT_TARGET); + + stream_cast(ptStr,upDirection); + s.push_back(std::make_pair(TRANS("Up Dir."), ptStr)); + type.push_back(PROPERTY_TYPE_POINT3D); + keys.push_back(KEY_LOOKAT_UPDIRECTION); + + std::vector > choices; + string tmp; + + + tmp=TRANS("Perspective"); + choices.push_back(make_pair((unsigned int)PROJECTION_MODE_PERSPECTIVE,tmp)); + tmp=TRANS("Orthogonal"); + choices.push_back(make_pair((unsigned int)PROJECTION_MODE_ORTHOGONAL,tmp)); + tmp= choiceString(choices,projectionMode); + + s.push_back(std::make_pair(TRANS("Projection"), tmp)); + type.push_back(PROPERTY_TYPE_CHOICE); + keys.push_back(KEY_LOOKAT_PROJECTIONMODE); + + switch(projectionMode) + { + case PROJECTION_MODE_PERSPECTIVE: + stream_cast(tmp,fovAngle); + s.push_back(std::make_pair(TRANS("Field of View (deg)"), tmp)); + type.push_back(PROPERTY_TYPE_REAL); + keys.push_back(KEY_LOOKAT_FOV); + break; + case PROJECTION_MODE_ORTHOGONAL: + stream_cast(tmp,orthoScale); + s.push_back(std::make_pair(TRANS("View size"), tmp)); + type.push_back(PROPERTY_TYPE_REAL); + keys.push_back(KEY_LOOKAT_ORTHOSCALE); + break; + + } + + p.data.push_back(s); + p.keys.push_back(keys); + p.types.push_back(type); +} + +bool CameraLookAt::setProperty(unsigned int key, const string &value) +{ + + switch(key) + { + case KEY_LOOKAT_LOCK: + { + if(value == "1") + lock=true; + else if (value == "0") + lock=false; + else + return false; + + break; + } + case KEY_LOOKAT_ORIGIN: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + //Disallow origin to be set to same as target + if(newPt.sqrDist(target) < sqrtf(std::numeric_limits::epsilon())) + return false; + + origin= newPt; + + break; + } + case KEY_LOOKAT_TARGET: + { + Point3D newPt; + if(!newPt.parse(value)) + return false; + + //Disallow origin to be set to same as target + if(newPt.sqrDist(origin) < sqrtf(std::numeric_limits::epsilon())) + return false; + target = newPt; + + break; + } + case KEY_LOOKAT_UPDIRECTION: + { + Point3D newDir; + if(!newDir.parse(value)) + return false; + + //View direction and up direction may not be the same + if(viewDirection.crossProd(newDir).sqrMag() < + sqrtf(std::numeric_limits::epsilon())) + return false; + + upDirection=newDir; + //Internal up direction should be perp. to view direction. + //use double cross product method to restore + recomputeUpDirection(); + break; + } + case KEY_LOOKAT_FOV: + { + float newFOV; + if(stream_cast(newFOV,value)) + return false; + + fovAngle=newFOV; + break; + } + case KEY_LOOKAT_PROJECTIONMODE: + { + size_t ltmp; + if(value == TRANS("Perspective")) + ltmp=PROJECTION_MODE_PERSPECTIVE; + else if( value == TRANS("Orthogonal")) + { + if(projectionMode!=PROJECTION_MODE_ORTHOGONAL) + { + //use the distance to the target as the orthographic + //scaling size (size of parallel frustrum) + orthoScale=sqrtf(target.sqrDist(origin)); + } + + ltmp=PROJECTION_MODE_ORTHOGONAL; + + } + else + { + ASSERT(false); + return false; + } + + if(ltmp>=PROJECTION_MODE_ENUM_END) + return false; + + projectionMode=ltmp; + + break; + } + case KEY_LOOKAT_ORTHOSCALE: + { + float newOrthoScale; + if(stream_cast(newOrthoScale,value)) + return false; + + orthoScale=newOrthoScale; + break; + } + + + default: + ASSERT(false); + } + return true; +} + +bool CameraLookAt::writeState(std::ostream &f, unsigned int format, + unsigned int nTabs) const +{ + switch(format) + { + case STATE_FORMAT_XML: + { + using std::endl; + + //COMPAT_BREAK: "Persplookat" is + f << tabs(nTabs) << "" << endl; + f << tabs(nTabs+1) << "" << endl; + f << tabs(nTabs+1) << "" << endl; + f << tabs(nTabs+1) << "" << endl; + + if(lock) + f<< tabs(nTabs+1) << "" << endl; + else + f<< tabs(nTabs+1) << "" << endl; + f << tabs(nTabs+1) << "" << endl; + f << tabs(nTabs+1) << "" << endl; + f << tabs(nTabs+1) << "" << endl; + + f<< tabs(nTabs+1) << "" << endl; + f<< tabs(nTabs+1) << "" << endl; + f << tabs(nTabs) << "" << endl; + + return true; + } + default: + ASSERT(false); + } +} + +bool CameraLookAt::readState(xmlNodePtr nodePtr) +{ + //Retrieve user string + if(!XMLGetNextElemAttrib(nodePtr,userString,"userstring","value")) + userString=""; + + std::string tmpStr; + + //Retrieve projection mode + if(!XMLGetNextElemAttrib(nodePtr,projectionMode,"projectionmode","value")) + return false; + if(projectionMode > PROJECTION_MODE_ENUM_END) + return false; + + //Retrieve orthographic scaling + if(!XMLGetNextElemAttrib(nodePtr,orthoScale,"orthoscale","value")) + return false; + if(orthoScale <=0 || std::isnan(orthoScale)) + return false; + + + float x,y,z; + xmlChar *xmlString; + + + //retrieve lock state + if(XMLHelpFwdToElem(nodePtr,"lock")) + return false; + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value"); + + std::string strTmp; + strTmp=(char*)xmlString; + if(strTmp == "1") + lock=true; + else if(strTmp == "0") + lock=false; + else + return false; + + //Retrieve origin + //==== + if(XMLHelpFwdToElem(nodePtr,"origin")) + return false; + //--Get X value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(x,tmpStr)) + return false; + + //--Get Z value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(y,tmpStr)) + return false; + + //--Get Y value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(z,tmpStr)) + return false; + + origin=Point3D(x,y,z); + //==== + + //Retrieve target + //==== + if(XMLHelpFwdToElem(nodePtr,"target")) + return false; + //--Get X value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(x,tmpStr)) + return false; + + //--Get Z value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(y,tmpStr)) + return false; + + //--Get Y value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(z,tmpStr)) + return false; + target=Point3D(x,y,z); + //==== + + //Retrieve up direction + //==== + if(XMLHelpFwdToElem(nodePtr,"updirection")) + return false; + //--Get X value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"x"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(x,tmpStr)) + return false; + + //--Get Z value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"y"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(y,tmpStr)) + return false; + + //--Get Y value-- + xmlString=xmlGetProp(nodePtr,(const xmlChar *)"z"); + if(!xmlString) + return false; + tmpStr=(char *)xmlString; + xmlFree(xmlString); + + //Check it is streamable + if(stream_cast(z,tmpStr)) + return false; + upDirection=Point3D(x,y,z); + //==== + + + //Get the FOV angle + //==== + if(!XMLGetNextElemAttrib(nodePtr,fovAngle,"fovangle","value")) + return false; + if(fovAngle<=0) + return false; + //==== + + //Get the near plane + //==== + if(!XMLGetNextElemAttrib(nodePtr,nearPlane,"nearplane","value")) + return false; + //==== + + recomputeViewDirection(); + return true; +} + +float CameraLookAt::getViewWidth(float depth) const +{ + if(projectionMode == PROJECTION_MODE_PERSPECTIVE) + return depth*tan(fovAngle/2.0f*M_PI/180.0); + else if(projectionMode == PROJECTION_MODE_ORTHOGONAL) + return -orthoScale*2.0f; //FIXME: Why is this negative??! + + ASSERT(false); +} + +std::ostream& operator<<(std::ostream &strm, const Camera &c) +{ + strm << "origin: " << c.origin << std::endl; + strm << "View Direction: " << c.viewDirection << std::endl; + strm << "Up Direction: "<< c.upDirection << std::endl; + return strm; +} + +std::ostream& operator<<(std::ostream &strm, const CameraLookAt &c) +{ + strm << "origin: " << c.origin << std::endl; + strm << "Target : " << c.target << std::endl; + + strm << "View Direction: " << c.viewDirection << std::endl; + strm << "Up Direction: "<< c.upDirection << std::endl; + + + strm << "FOV (deg) : " << c.fovAngle << std::endl; + strm << "Clip planes: " << c.nearPlane << " (near) " << std::endl; + return strm; +} + + + diff -Nru 3depict-0.0.12/src/gl/cameras.h 3depict-0.0.13/src/gl/cameras.h --- 3depict-0.0.12/src/gl/cameras.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/cameras.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,258 @@ +/* + * cameras.h - 3D cameras for opengl + * 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 . +*/ + +#ifndef CAMERAS_H +#define CAMERAS_H + +#include "common/basics.h" + +//libxml2 headers +#ifdef ATTRIBUTE_PRINTF + #pragma push_macro("ATTRIBUTE_PRINTF") + #include + #pragma pop_macro(" ATTRIBUTE_PRINTF") +#else + #include + #undef ATTRIBUTE_PRINTF +#endif + +enum CAM_ENUM +{ + CAM_FREE=1, + CAM_LOOKAT +}; + +enum +{ + PROJECTION_MODE_PERSPECTIVE, + PROJECTION_MODE_ORTHOGONAL, + PROJECTION_MODE_ENUM_END //not a valid mode. +}; + +class CameraProperties +{ + public: + //Filter property data, one per output, each is value then name + std::vector > > data; + //Data types for each single element + std::vector > types; + + //!Key numbers for filter. Must be unique per set + std::vector > keys; + +}; + +//!An abstract base class for a camera +class Camera +{ + protected: + + bool lock; + //!Camera location + Point3D origin; + //!Direction camera is looking in + Point3D viewDirection; + //!Up direction for camera (required to work out "roll") + Point3D upDirection; + + //!Projection mode (otho, perspective...)_ + unsigned int projectionMode; + + //!The current orthographic scaling + float orthoScale; + + //!Type number + unsigned int typeNum; + //!user string, e.g. camera name + std::string userString; + public: + //!constructor + Camera(); + //!Destructor + virtual ~Camera(); + //!Duplication routine. Must delete returned pointer manually. + virtual Camera *clone() const=0; + + //!Streaming output operator, presents human readable text + friend std::ostream &operator<<(std::ostream &stream, const Camera &); + + //!Return the origin of the camera + Point3D getOrigin() const; + //!Return the view direction for the camera + Point3D getViewDirection() const; + //!Return the up direction for the camera + Point3D getUpDirection() const; + + //!return the projection mode + unsigned int getProjectionMode() const{ return projectionMode;}; + + //!Set the camera's position + virtual void setOrigin(const Point3D &); + //!set the direction that the camera looks towards + void setViewDirection(const Point3D &); + //!set the direction that the camera considers "up" + void setUpDirection(const Point3D &); + + //!Set the user string + void setUserString(const std::string &newString){ userString=newString;}; + //!Get the user string + std::string getUserString() const { return userString;}; + + //!Do a forwards "dolly",where the camera moves along its viewing axis. In ortho mode, instead of moving along axis, a scaling is performed + virtual void forwardsDolly(float dollyAmount); + + //!Move the camera origin + virtual void move(float leftRightAmount,float UpDownAmount); + + //!Move the camera origin + virtual void translate(float leftRightAmount,float UpDownAmount); + + //!pivot the camera + /* First pivots the camera around the across direction + * second pivot sthe camera around the up direction + */ + virtual void pivot(float rollAroundAcross, float rollaroundUp); + + //!Roll around the view direction + virtual void roll(float roll) =0; + //!Applies the camera settings to openGL. Ensures the far planes + //is set to make the whole scene visible + virtual void apply(float outputRatio,const BoundCube &b,bool loadIdentity=true) const=0; + //!Applies the camera settings to openGL, restricting the viewport (range (-1, 1)) + virtual void apply(float outputRatio,const BoundCube &b,bool loadIdentity, + float leftRestrict,float rightRestrict, + float bottomRestrict, float topRestrict) const=0; + //!Ensures that the given boundingbox should look nice, and be visible + virtual void ensureVisible(const BoundCube &b, unsigned int face=3)=0; + + //!Obtain the properties specific to a camera + virtual void getProperties(CameraProperties &p) const =0; + //!Set the camera property from a key & string pair + virtual bool setProperty(unsigned int key, const std::string &value) =0; + + unsigned int type() const {return typeNum;}; + + //!Write the state of the camera + virtual bool writeState(std::ostream &f, unsigned int format, unsigned int tabs) const =0; + + //!Read the state of the camera from XML document + virtual bool readState(xmlNodePtr nodePtr)=0; + +}; + +//!A perspective camera that looks at a specific location +class CameraLookAt : public Camera +{ + protected: + //!Location for camera to look at + Point3D target; + + void recomputeViewDirection(); + + //!Perspective FOV + float fovAngle; + + //!Near clipping plane distance. + float nearPlane; + //!Far plane is computed on-the-fly. cannot be set directly. Oh no! mutable. gross! + mutable float farPlane; + + //!Distort to the viewing frustum. (eg for stero) ( a frustum is a rectangular pyramid with the top cut off) + float frustumDistortion; + + //!Do the perspective calculations + void doPerspCalcs(float aspect,const BoundCube &bc,bool loadIdentity) const; + + public: + //!Constructor + CameraLookAt(); + + //!Streaming output operator, presents human readable text + friend std::ostream &operator<<(std::ostream &stream, const CameraLookAt &); + //!clone function + Camera *clone() const; + //!Destructor + virtual ~CameraLookAt(); + //!Set the look at target + void setOrigin(const Point3D &); + //!Set the look at target + void setTarget(const Point3D &); + //!Get the look at target + Point3D getTarget() const; + + //!Get the camera's FOV angle (full angle across) + float getFOV() const {return fovAngle;} + + //!Applies the view transform + void apply(float outAspect, const BoundCube &boundCube,bool loadIdentity=true) const; + + //!Do a forwards "dolly",where the camera moves along its viewing axis + void forwardsDolly(float dollyAmount); + + //!Move the camera origin + void move(float leftRightAmount,float UpDownAmount); + //!Simulate pivot of camera + /* Actually I pivot by moving the target internally. + */ + void pivot(float lrRad,float udRad); + + void translate(float lrTrans, float udTrans); + + + + //Clockwise roll looking from camera view by rollRad radians + void roll(float rollRad); + + //!Ensure that up direction is perpendicular to view direction + void recomputeUpDirection(); + + //!Ensure that the box is visible + /*! Face is set by cube net + 0 + 1 2 3 + 4 + 5 + 2 is the face directed to the +ve x axis, + with the "up"" vector on the 3 aligned to z, + so "0" is perpendicular to the Z axis and is "visible" + */ + virtual void ensureVisible(const BoundCube &b, unsigned int face=3); + + //!Return the user-settable properties of the camera + void getProperties(CameraProperties &p) const; + //!Set the camera property from a key & string pair + bool setProperty(unsigned int key, const std::string &value); + + //!Write the state of the camera + bool writeState(std::ostream &f, unsigned int format, unsigned int tabs=0) const; + + //!Read the state of the camera + bool readState(xmlNodePtr nodePtr) ; + + //!Apply, restricting viewport to subresgion + virtual void apply(float outputRatio,const BoundCube &b,bool loadIdentity, + float leftRestrict,float rightRestrict, + float topRestrict, float bottomRestrict) const; + + float getViewWidth(float depth) const; + + void setFrustumDistort(float offset){frustumDistortion=offset;}; + +}; + +#endif diff -Nru 3depict-0.0.12/src/gl/drawables.cpp 3depict-0.0.13/src/gl/drawables.cpp --- 3depict-0.0.12/src/gl/drawables.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/drawables.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,2009 @@ +/* + * drawables.cpp - opengl drawable objects cpp file + * 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 . +*/ + +#include "drawables.h" + +#include "common/colourmap.h" + + +const float DEPTH_SORT_REORDER_EPSILON = 1e-2; + +//Static class variables +//==== +const Camera *DrawableObj::curCamera = 0; +//== + + +//Common functions +// +void drawBox(Point3D pMin, Point3D pMax, float r,float g, float b, float a) +{ + //TODO: Could speedup with LINE_STRIP/LOOP. This is + //not a bottleneck atm though. + glBegin(GL_LINES); + glColor4f(r,g,b,a); + //Bottom corner out (three lines from corner) + glVertex3f(pMin[0],pMin[1],pMin[2]); + glVertex3f(pMax[0],pMin[1],pMin[2]); + + glVertex3f(pMin[0],pMin[1],pMin[2]); + glVertex3f(pMin[0],pMax[1],pMin[2]); + + glVertex3f(pMin[0],pMin[1],pMin[2]); + glVertex3f(pMin[0],pMin[1],pMax[2]); + + //Top Corner out (three lines from corner) + glVertex3f(pMax[0],pMax[1],pMax[2]); + glVertex3f(pMin[0],pMax[1],pMax[2]); + + glVertex3f(pMax[0],pMax[1],pMax[2]); + glVertex3f(pMax[0],pMin[1],pMax[2]); + + glVertex3f(pMax[0],pMax[1],pMax[2]); + glVertex3f(pMax[0],pMax[1],pMin[2]); + + //Missing pieces - in an "across-down-across" shape + glVertex3f(pMin[0],pMax[1],pMin[2]); + glVertex3f(pMax[0],pMax[1],pMin[2]); + + glVertex3f(pMax[0],pMax[1],pMin[2]); + glVertex3f(pMax[0],pMin[1],pMin[2]); + + glVertex3f(pMax[0],pMin[1],pMin[2]); + glVertex3f(pMax[0],pMin[1],pMax[2]); + + glVertex3f(pMax[0],pMin[1],pMax[2]); + glVertex3f(pMin[0],pMin[1],pMax[2]); + + glVertex3f(pMin[0],pMin[1],pMax[2]); + glVertex3f(pMin[0],pMax[1],pMax[2]); + + glVertex3f(pMin[0],pMax[1],pMax[2]); + glVertex3f(pMin[0],pMax[1],pMin[2]); + glEnd(); +} + + +using std::vector; + +DrawableObj::DrawableObj() : active(true), haveChanged(true), canSelect(false), wantsLight(false) +{ +} + +DrawableObj::~DrawableObj() +{ +} + +void DrawableObj::explode(std::vector &simpleObjects) +{ + ASSERT(isExplodable()); +} + +Point3D DrawableObj::getCentroid() const +{ + ASSERT(!isExplodable()); +} + +//===== + +DrawPoint::DrawPoint() : origin(0.0f,0.0f,0.0f), r(1.0f), g(1.0f), b(1.0f), a(1.0f) +{ +} + +DrawPoint::DrawPoint(float x, float y, float z) : origin(x,y,z), r(1.0f), g(1.0f), b(1.0f) +{ +} + +DrawPoint::~DrawPoint() +{ +} + + + + +void DrawPoint::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + + + +void DrawPoint::setOrigin(const Point3D &pt) +{ + origin = pt; +} + + +void DrawPoint::draw() const +{ + glColor4f(r,g,b,a); + glBegin(GL_POINT); + glVertex3f(origin[0],origin[1],origin[2]); + glEnd(); +} + +DrawVector::DrawVector() : origin(0.0f,0.0f,0.0f), vector(0.0f,0.0f,1.0f),drawArrow(true), + arrowSize(1.0f),scaleArrow(true),doubleEnded(false), + r(1.0f), g(1.0f), b(1.0f), a(1.0f), lineSize(1.0f) +{ +} + +DrawVector::~DrawVector() +{ +} + + +void DrawVector::getBoundingBox(BoundCube &b) const +{ + b.setBounds(origin,vector+origin); +} + +void DrawVector::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + + +void DrawVector::setEnds(const Point3D &startNew, const Point3D &endNew) +{ + origin = startNew; + vector =endNew-startNew; +} + +void DrawVector::setOrigin(const Point3D &pt) +{ + origin = pt; +} + +void DrawVector::setVector(const Point3D &pt) +{ + vector= pt; +} + +void DrawVector::draw() const +{ + const unsigned int NUM_CONE_SEGMENTS=20; + const float numConeRadiiLen = 1.5f; + const float radius= arrowSize; + + glColor3f(r,g,b); + + //Disable lighting calculations for arrow stem + glPushAttrib(GL_LIGHTING_BIT); + glDisable(GL_LIGHTING); + float oldLineWidth; + glGetFloatv(GL_LINE_WIDTH,&oldLineWidth); + + glLineWidth(lineSize); + glBegin(GL_LINES); + + if(arrowSize < sqrt(std::numeric_limits::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(); + } + + + + + + //Now compute & draw the cone tip + //---- + + Point3D axis; + axis = vector; + + if(axis.sqrMag() < sqrt(std::numeric_limits::epsilon())) + axis=Point3D(0,0,1); + else + axis.normalise(); + + + //Tilt space to align to cone axis + Point3D zAxis(0,0,1); + float tiltAngle; + tiltAngle = zAxis.angle(axis); + + Point3D rotAxis; + rotAxis=zAxis.crossProd(axis); + + Point3D *ptArray = new Point3D[NUM_CONE_SEGMENTS]; + if(tiltAngle > sqrt(std::numeric_limits::epsilon()) && + rotAxis.sqrMag() > sqrt(std::numeric_limits::epsilon())) + { + + //Draw an angled cone + Point3f vertex,r; + rotAxis.normalise(); + + + r.fx=rotAxis[0]; + r.fy=rotAxis[1]; + r.fz=rotAxis[2]; + + + //we have to rotate the cone points around the apex point + for(unsigned int ui=0; ui sqrt(std::numeric_limits::epsilon())) + { + //Downwards pointing cone + for(unsigned int ui=0; ui &vecs, + const std::vector &scalars, unsigned int mode) +{ + switch(mode) + { + case DRAW_VECTOR_BIND_ORIENTATION: + ASSERT(vecs.size() ==1 && scalars.size() ==0); + vector=vecs[0]; + break; + case DRAW_VECTOR_BIND_ORIGIN: + ASSERT(vecs.size() == 1 && scalars.size()==0); + origin=vecs[0]; + break; + case DRAW_VECTOR_BIND_ORIGIN_ONLY: + { + ASSERT(vecs.size() == 1 && scalars.size()==0); + + Point3D dv; + dv=vector-origin; + origin=vecs[0]; + vector=origin+dv; + break; + } + case DRAW_VECTOR_BIND_TARGET: + ASSERT(vecs.size() == 1 && scalars.size()==0); + vector=vecs[0]-origin; + break; + default: + ASSERT(false); + } +} + + + +DrawTriangle::DrawTriangle() : r(1.0f), g(1.0f),b(1.0f),a(1.0f) +{ +} + +DrawTriangle::~DrawTriangle() +{ +} + +void DrawTriangle::setVertex(unsigned int ui, const Point3D &pt) +{ + ASSERT(ui < 3); + vertices[ui] = pt; +} + +void DrawTriangle::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + +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]); + glEnd(); +} + + +DrawSphere::DrawSphere() : radius(1.0f), latSegments(8),longSegments(8) +{ + q=gluNewQuadric(); +} + +DrawSphere::~DrawSphere() +{ + if(q) + gluDeleteQuadric(q); +} + + + +void DrawSphere::getBoundingBox(BoundCube &b) const +{ + for(unsigned int ui=0;ui<3;ui++) + { + b.setBound(ui,0,origin[ui] - radius); + b.setBound(ui,1,origin[ui] + radius); + } +} + +void DrawSphere::setOrigin(const Point3D &p) +{ + origin = p; +} + +void DrawSphere::setLatSegments(unsigned int ui) +{ + latSegments = ui; +} + +void DrawSphere::setLongSegments(unsigned int ui) +{ + longSegments = ui; +} + +void DrawSphere::setRadius(float rad) +{ + radius=rad; +} + +void DrawSphere::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + +void DrawSphere::draw() const +{ + if(!q) + return; + + glPushMatrix(); + glTranslatef(origin[0],origin[1],origin[2]); + glColor4f(r,g,b,a); + gluSphere(q,radius,latSegments,longSegments); + glPopMatrix(); +} + + +void DrawSphere::recomputeParams(const vector &vecs, + const vector &scalars, unsigned int mode) +{ + switch(mode) + { + case DRAW_SPHERE_BIND_ORIGIN: + ASSERT(vecs.size() ==1 && scalars.size() ==0); + origin=vecs[0]; + break; + case DRAW_SPHERE_BIND_RADIUS: + ASSERT(scalars.size() == 1 && vecs.size()==0); + radius=scalars[0]; + break; + default: + ASSERT(false); + } +} +//=========== + +DrawCylinder::DrawCylinder() : radius(1.0f), + origin(0.0f,0.0f,0.0f), direction(0.0f,0.0f,1.0f), slices(4),stacks(4) +{ + q= gluNewQuadric(); + qCap[0]= gluNewQuadric(); + if(qCap[0]) + gluQuadricOrientation(qCap[0],GLU_INSIDE); + qCap[1]= gluNewQuadric(); + if(qCap[1]) + gluQuadricOrientation(qCap[1],GLU_OUTSIDE); + radiiLocked=false; +} + +bool DrawCylinder::needsDepthSorting() const +{ + return a< 1 && a > std::numeric_limits::epsilon(); +} + +DrawCylinder::~DrawCylinder() +{ + if(q) + gluDeleteQuadric(q); + if(qCap[0]) + gluDeleteQuadric(qCap[0]); + if(qCap[1]) + gluDeleteQuadric(qCap[1]); +} + + +void DrawCylinder::setOrigin(const Point3D& pt) +{ + origin=pt; +} + + +void DrawCylinder::setDirection(const Point3D &p) +{ + direction=p; +} + + +void DrawCylinder::draw() const +{ + if(!q || !qCap[0] || !qCap[1]) + return; + + //Cross product desired direction with default + //direction to produce rotation vector + Point3D dir(0.0f,0.0f,1.0f); + + glPushMatrix(); + glTranslatef(origin[0],origin[1],origin[2]); + + Point3D dirNormal(direction); + dirNormal.normalise(); + + float length=sqrtf(direction.sqrMag()); + float angle = dir.angle(dirNormal); + if(angle < M_PI - sqrt(std::numeric_limits::epsilon()) && + angle > sqrt(std::numeric_limits::epsilon())) + { + //we need to rotate + dir = dir.crossProd(dirNormal); + + glRotatef(angle*180.0f/M_PI,dir[0],dir[1],dir[2]); + } + + //OpenGL defined cylinder starting at 0 and going to length. I want it starting at 0 and going to+-l/2 + glTranslatef(0,0,-length/2.0f); + glColor4f(r,g,b,a); + + //Draw the end cap at z=0 + if(radiiLocked) + { + gluDisk(qCap[0],0,radius,slices,1); + gluCylinder(q,radius,radius, length,slices,stacks); + + //Draw the start cap at z=l + glTranslatef(0,0,length); + gluDisk(qCap[1],0,radius,slices,1); + } + else + { + ASSERT(false); + } + + glPopMatrix(); +} + +void DrawCylinder::setSlices(unsigned int i) +{ + slices=i; +} + +void DrawCylinder::setStacks(unsigned int i) +{ + stacks=i; +} + +void DrawCylinder::setRadius(float rad) +{ + radius=rad; +} + +void DrawCylinder::recomputeParams(const vector &vecs, + const vector &scalars, unsigned int mode) +{ + switch(mode) + { + case DRAW_CYLINDER_BIND_ORIGIN: + ASSERT(vecs.size() ==1 && scalars.size() ==0); + origin=vecs[0]; + break; + + case DRAW_CYLINDER_BIND_DIRECTION: + ASSERT(vecs.size() ==1 && scalars.size() ==0); + direction=vecs[0]; + break; + case DRAW_CYLINDER_BIND_RADIUS: + ASSERT(scalars.size() == 1 && vecs.size()==0); + radius=scalars[0]; + break; + default: + ASSERT(false); + } +} + + +void DrawCylinder::setLength(float len) +{ + ASSERT(direction.sqrMag()); + direction=direction.normalise()*len; +} + +void DrawCylinder::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + +void DrawCylinder::getBoundingBox(BoundCube &b) const +{ + + float tmp; + + Point3D normAxis(direction); + normAxis.normalise(); + + //Height offset for ending circles. + //The joint bounding box of these two is the + //overall bounding box + Point3D offset; + + + + //X component + tmp=sin(acos(normAxis.dotProd(Point3D(1,0,0)))); + offset[0] = radius*tmp; + + //Y component + tmp=sin(acos(normAxis.dotProd(Point3D(0,1,0)))); + offset[1] = radius*tmp; + + //Z component + tmp=sin(acos(normAxis.dotProd(Point3D(0,0,1)))); + offset[2] = radius*tmp; + + vector p; + p.resize(4); + p[0]= offset+(direction*0.5+origin); + p[1]= -offset+(direction*0.5+origin); + p[2]= offset+(-direction*0.5+origin); + p[3]= -offset+(-direction*0.5+origin); + + b.setBounds(p); +} + + +//====== + +DrawManyPoints::DrawManyPoints() : r(1.0f),g(1.0f),b(1.0f),a(1.0f), size(1.0f) +{ + wantsLight=false; +} + +DrawManyPoints::~DrawManyPoints() +{ + wantsLight=false; + haveCachedBounds=false; +} + +void DrawManyPoints::getBoundingBox(BoundCube &b) const +{ + + //Update the cache as needed + if(!haveCachedBounds) + { + haveCachedBounds=true; + cachedBounds.setBounds(pts); + } + + b=cachedBounds; + return; +} + +void DrawManyPoints::clear() +{ + pts.clear(); +} + +void DrawManyPoints::addPoints(const vector &vp) +{ + pts.reserve(pts.size()+vp.size()); + std::copy(vp.begin(),vp.end(),pts.begin()); + haveCachedBounds=false; +} + +void DrawManyPoints::shuffle() +{ + std::random_shuffle(pts.begin(),pts.end()); +} + +void DrawManyPoints::resize(size_t resizeVal) +{ + pts.resize(resizeVal); + haveCachedBounds=false; +} + + +void DrawManyPoints::setPoint(size_t offset,const Point3D &p) +{ + ASSERT(!haveCachedBounds); + pts[offset]=p; +} + +void DrawManyPoints::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + +void DrawManyPoints::setSize(float f) +{ + size=f; +} + +void DrawManyPoints::draw() const +{ + //Don't draw transparent objects + if(a < std::numeric_limits::epsilon()) + return; + + glPointSize(size); + glBegin(GL_POINTS); + glColor4f(r,g,b,a); + //TODO: Consider Vertex buffer objects. would be faster, but less portable. + for(unsigned int ui=0; uigetBoundingBox(b); + boundBox.expand(b); + d->draw(); +} + +bool DrawDispList::endList() +{ + glEndList(); + + ASSERT(boundBox.isValid()); + listActive=false; + return (glGetError() ==0); +} + +void DrawDispList::draw() const +{ + ASSERT(!listActive); + + //Cannot select display list objects, + //as we cannot modify them without a "do-over". + ASSERT(!canSelect); + + ASSERT(glIsList(listNum)); + //Execute the list + glPushMatrix(); + glCallList(listNum); + glPopMatrix(); +} + +//======== + + +DrawGLText::DrawGLText(std::string fontFile, unsigned int mode) :font(0),fontString(fontFile), + curFontMode(mode), origin(0.0f,0.0f,0.0f), + r(0.0),g(0.0),b(0.0),a(1.0), up(0.0f,1.0f,0.0f), + textDir(1.0f,0.0f,0.0f), readDir(0.0f,0.0f,1.0f), + isOK(true),ensureReadFromNorm(true) +{ + + font=0; + switch(mode) + { + case FTGL_BITMAP: + font = new FTGLBitmapFont(fontFile.c_str()); + break; + case FTGL_PIXMAP: + font = new FTGLPixmapFont(fontFile.c_str()); + break; + case FTGL_OUTLINE: + font = new FTGLOutlineFont(fontFile.c_str()); + break; + case FTGL_POLYGON: + font = new FTGLPolygonFont(fontFile.c_str()); + break; + case FTGL_EXTRUDE: + font = new FTGLExtrdFont(fontFile.c_str()); + break; + case FTGL_TEXTURE: + font = new FTGLTextureFont(fontFile.c_str()); + break; + default: + //Don't do this. Use valid font numbers + ASSERT(false); + font=0; + } + + //In case of allocation failure or invalid font num + if(!font || font->Error()) + { + isOK=false; + return; + } + + //Try to make it 100 point + font->FaceSize(5); + font->Depth(20); + + //Use unicode + font->CharMap(ft_encoding_unicode); + + alignMode = DRAWTEXT_ALIGN_LEFT; +} + +DrawGLText::DrawGLText(const DrawGLText &oth) : font(0), fontString(oth.fontString), + curFontMode(oth.curFontMode), origin(oth.origin), r(oth.r), + g(oth.g), b(oth.b), a(oth.a), up(oth.up), textDir(oth.textDir), + readDir(oth.readDir),isOK(oth.isOK), ensureReadFromNorm(oth.ensureReadFromNorm) +{ + + font=0; + switch(curFontMode) + { + case FTGL_BITMAP: + font = new FTGLBitmapFont(fontString.c_str()); + break; + case FTGL_PIXMAP: + font = new FTGLPixmapFont(fontString.c_str()); + break; + case FTGL_OUTLINE: + font = new FTGLOutlineFont(fontString.c_str()); + break; + case FTGL_POLYGON: + font = new FTGLPolygonFont(fontString.c_str()); + break; + case FTGL_EXTRUDE: + font = new FTGLExtrdFont(fontString.c_str()); + break; + case FTGL_TEXTURE: + font = new FTGLTextureFont(fontString.c_str()); + break; + default: + //Don't do this. Use valid font numbers + ASSERT(false); + font=0; + } + + //In case of allocation failure or invalid font num + if(!font || font->Error()) + { + isOK=false; + return; + } + + //Try to make it 100 point + font->FaceSize(5); + font->Depth(20); + //Use unicode + font->CharMap(ft_encoding_unicode); +} + +void DrawGLText::draw() const +{ + if(!isOK) + return; + + //Translate the drawing position to the origin + Point3D offsetVec=textDir; + float advance; + float halfHeight; + + FTBBox box; + box=font->BBox(strText.c_str()); + advance=box.Upper().X()-box.Lower().X(); + + halfHeight=box.Upper().Y()-box.Lower().Y(); + halfHeight/=2.0f; + + switch(alignMode) + { + case DRAWTEXT_ALIGN_LEFT: + break; + case DRAWTEXT_ALIGN_CENTRE: + offsetVec=offsetVec*advance/2.0f; + break; + case DRAWTEXT_ALIGN_RIGHT: + offsetVec=offsetVec*advance; + break; + default: + ASSERT(false); + } + + + glPushMatrix(); + + + glPushAttrib(GL_CULL_FACE); + + glDisable(GL_CULL_FACE); + if(curFontMode !=FTGL_BITMAP) + { + offsetVec=origin-offsetVec; + glTranslatef(offsetVec[0],offsetVec[1],offsetVec[2]); + + //Rotate such that the new X-Y plane is set to the + //desired text orientation. (ie. we want to draw the text in the + //specified combination of updir-textdir, rather than in the X-y plane) + + //--- + //Textdir and updir MUST be normal to one another + ASSERT(textDir.dotProd(up) < sqrtf(std::numeric_limits::epsilon())); + + //rotate around textdir cross X, if the two are not the same + Point3D rotateAxis; + Point3D newUp=up; + float angle=textDir.angle(Point3D(1,0,0) ); + if(angle > sqrtf(std::numeric_limits::epsilon())) + { + rotateAxis = textDir.crossProd(Point3D(-1,0,0)); + rotateAxis.normalise(); + + Point3f tmp,axis; + tmp.fx=up[0]; + tmp.fy=up[1]; + tmp.fz=up[2]; + + axis.fx=rotateAxis[0]; + axis.fy=rotateAxis[1]; + axis.fz=rotateAxis[2]; + + + glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]); + quat_rot(&tmp,&axis,angle); //angle is in radiians + + newUp[0]=tmp.fx; + newUp[1]=tmp.fy; + newUp[2]=tmp.fz; + } + + //rotate new up direction into y around x axis + angle = newUp.angle(Point3D(0,1,0)); + if(angle > sqrtf(std::numeric_limits::epsilon()) && + fabs(angle - M_PI) > sqrtf(std::numeric_limits::epsilon())) + { + rotateAxis = newUp.crossProd(Point3D(0,-1,0)); + rotateAxis.normalise(); + glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]); + } + + //Ensure that the text is not back-culled (i.e. if the + //text normal is pointing away from the camera, it does not + //get drawn). Here we have to flip the normal, by spinning the + //text by 180 around its up direction (which has been modified + //by above code to coincide with the y axis. + if(curCamera) + { + //This is not *quite* right in perspective mode + //but is right in orthogonal + + Point3D textNormal,camVec; + textNormal = up.crossProd(textDir); + textNormal.normalise(); + + camVec = origin - curCamera->getOrigin(); + + //ensure the camera is not sitting on top of the text. + if(camVec.sqrMag() > std::numeric_limits::epsilon()) + { + + camVec.normalise(); + + if(camVec.dotProd(textNormal) < 0) + { + //move halfway along text, noting that + //the text direction is now the x-axis + glTranslatef(advance/2.0f,halfHeight,0); + //spin text around its up direction 180 degrees + glRotatef(180,0,1,0); + //restore back to original position + glTranslatef(-advance/2.0f,-halfHeight,0); + } + + camVec=curCamera->getUpDirection(); + if(camVec.dotProd(up) < 0) + { + //move halfway along text, noting that + //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 + glRotatef(180,0,0,1); + //move halfway along text, noting that + //the text direction is now the x-axis + glTranslatef(-advance/2.0f,-halfHeight,0); + } + + } + + + } + + } + else + { + //FIXME: The text ends up in a weird location + //2D coordinate storage for bitmap text + double xWin,yWin,zWin; + //Compute the 2D coordinates + double model_view[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, model_view); + + double projection[16]; + glGetDoublev(GL_PROJECTION_MATRIX, projection); + + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + + //Apply the openGL coordinate transformation pipeline to the + //specified coords + gluProject(offsetVec[0],offsetVec[1],offsetVec[2] + ,model_view,projection,viewport, + &xWin,&yWin,&zWin); + + glRasterPos3f(xWin,yWin,zWin); + + } + //--- + + + glColor4f(r,g,b,a); + + //Draw text + if(curFontMode == FTGL_TEXTURE) + { + glPushAttrib(GL_ENABLE_BIT); + glEnable(GL_TEXTURE_2D); + + font->Render(strText.c_str()); + glPopAttrib(); + } + else + font->Render(strText.c_str()); + + glPopAttrib(); + + glPopMatrix(); +} + +DrawGLText::~DrawGLText() +{ + if(font) + delete font; +} + +void DrawGLText::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + +void DrawGLText::getBoundingBox(BoundCube &b) const +{ + + if(isOK) + { + float minX,minY,minZ; + float maxX,maxY,maxZ; + font->BBox(strText.c_str(),minX,minY,minZ,maxX,maxY,maxZ); + b.setBounds(minX+origin[0],minY+origin[1],minZ+origin[2], + maxX+origin[0],maxY+origin[1],maxZ+origin[2]); + } + else + b.setInverseLimits(); + +} + +void DrawGLText::setAlignment(unsigned int newMode) +{ + ASSERT(newMode < DRAWTEXT_ALIGN_ENUM_END); + alignMode=newMode; +} + +void DrawGLText::recomputeParams(const vector &vecs, + const vector &scalars, unsigned int mode) +{ + switch(mode) + { + case DRAW_TEXT_BIND_ORIGIN: + ASSERT(vecs.size() ==1 && scalars.size() ==0); + origin=vecs[0]; + break; + default: + ASSERT(false); + } +} + +DrawRectPrism::DrawRectPrism() : drawMode(DRAW_WIREFRAME), r(1.0f), g(1.0f), b(1.0f), a(1.0f), lineWidth(1.0f) +{ +} + +DrawRectPrism::~DrawRectPrism() +{ +} + +void DrawRectPrism::getBoundingBox(BoundCube &b) const +{ + b.setBounds(pMin[0],pMin[1],pMin[2], + pMax[0],pMax[1],pMax[2]); +} + +void DrawRectPrism::draw() const +{ + ASSERT(r <=1.0f && g<=1.0f && b <=1.0f && a <=1.0f); + ASSERT(r >=0.0f && g>=0.0f && b >=0.0f && a >=0.0f); + + if(!active) + return; + + switch(drawMode) + { + case DRAW_WIREFRAME: + { + glLineWidth(lineWidth); + drawBox(pMin,pMax,r,g,b,a); + break; + } + case DRAW_FLAT: + { + glBegin(GL_QUADS); + glColor4f(r,g,b,a); + + glNormal3f(0,0,-1); + //Along the bottom + glVertex3f(pMin[0],pMin[1],pMin[2]); + glVertex3f(pMin[0],pMax[1],pMin[2]); + glVertex3f(pMax[0],pMax[1],pMin[2]); + glVertex3f(pMax[0],pMin[1],pMin[2]); + //Up the side + glNormal3f(1,0,0); + glVertex3f(pMax[0],pMax[1],pMax[2]); + glVertex3f(pMax[0],pMin[1],pMax[2]); + glVertex3f(pMax[0],pMin[1],pMin[2]); + glVertex3f(pMax[0],pMax[1],pMin[2]); + //Over the top + glNormal3f(0,0,1); + glVertex3f(pMax[0],pMin[1],pMax[2]); + glVertex3f(pMax[0],pMax[1],pMax[2]); + glVertex3f(pMin[0],pMax[1],pMax[2]); + glVertex3f(pMin[0],pMin[1],pMax[2]); + + //and back down + glNormal3f(-1,0,0); + glVertex3f(pMin[0],pMax[1],pMin[2]); + glVertex3f(pMin[0],pMin[1],pMin[2]); + glVertex3f(pMin[0],pMin[1],pMax[2]); + glVertex3f(pMin[0],pMax[1],pMax[2]); + + //Now the other two sides + glNormal3f(0,-1,0); + glVertex3f(pMax[0],pMin[1],pMax[2]); + glVertex3f(pMin[0],pMin[1],pMax[2]); + glVertex3f(pMin[0],pMin[1],pMin[2]); + glVertex3f(pMax[0],pMin[1],pMin[2]); + + glNormal3f(0,1,0); + glVertex3f(pMax[0],pMax[1],pMax[2]); + glVertex3f(pMax[0],pMax[1],pMin[2]); + glVertex3f(pMin[0],pMax[1],pMin[2]); + glVertex3f(pMin[0],pMax[1],pMax[2]); + + glEnd(); + + break; + + } + default: + ASSERT(false); + } + + +} + +void DrawRectPrism::setAxisAligned( const Point3D &p1, const Point3D &p2) +{ + for(unsigned int ui=0; ui<3; ui++) + { + pMin[ui]=std::min(p1[ui],p2[ui]); + pMax[ui]=std::max(p1[ui],p2[ui]); + } + +} + +void DrawRectPrism::setAxisAligned( const BoundCube &b) +{ + b.getBounds(pMin,pMax); +} + +void DrawRectPrism::setColour(float rnew, float gnew, float bnew, float anew) +{ + r=rnew; + g=gnew; + b=bnew; + a=anew; +} + +void DrawRectPrism::setLineWidth(float newLineWidth) +{ + ASSERT(newLineWidth > 0.0f); + lineWidth=newLineWidth; +} + +void DrawRectPrism::recomputeParams(const vector &vecs, + const vector &scalars, unsigned int mode) +{ + switch(mode) + { + case DRAW_RECT_BIND_TRANSLATE: + { + ASSERT(vecs.size() ==1); + Point3D delta; + delta = (pMax - pMin)*0.5; + //Object has been translated + pMin = vecs[0]-delta; + pMax = vecs[0]+delta; + break; + } + case DRAW_RECT_BIND_CORNER_MOVE: + { + ASSERT(vecs.size() ==1); + //Delta has changed, but origin should stay the same + Point3D mean, corner; + mean = (pMin + pMax)*0.5; + + //Prevent negative offset values, otherwise we can + //get inside out boxes + corner=vecs[0]; + for(unsigned int ui=0;ui<3;ui++) + corner[ui]= fabs(corner[ui]); + + pMin = mean-corner; + pMax = mean+corner; + break; + } + default: + ASSERT(false); + } +} + +DrawTexturedQuadOverlay::DrawTexturedQuadOverlay() : texPool(0) +{ +} + +DrawTexturedQuadOverlay::~DrawTexturedQuadOverlay() +{ +#ifdef DEBUG + textureOK=false; +#endif +} + +void DrawTexturedQuadOverlay::setSize(float s) +{ + length=s; +} + + +void DrawTexturedQuadOverlay::draw() const +{ + if(!textureOK) + return; + + ASSERT(glIsTexture(textureId)); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0, winX, winY, 0); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,textureId); + + // Draw overlay quad + glColor3f(1.0f,1.0f,1.0f); + glBegin(GL_QUADS); + glTexCoord2f(0.0f,0.0f); + glVertex3f(position[0]-length/2.0,position[1]-length/2.0,0.0); + glTexCoord2f(0.0f,1.0f); + glVertex3f(position[0]-length/2.0,position[1]+length/2.0,0.0); + glTexCoord2f(1.0f,1.0f); + glVertex3f(position[0]+length/2.0,position[1]+length/2.0,0.0); + glTexCoord2f(1.0f,0.0f); + glVertex3f(position[0]+length/2.0,position[1]-length/2.0,0.0); + glEnd(); + + glDisable(GL_TEXTURE_2D); + /* draw stuff */ + + glPopMatrix(); //Pop modelview matrix + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); +} + + +bool DrawTexturedQuadOverlay::setTexture(const char *textureFile) +{ + ASSERT(texPool); + unsigned int dummy; + + textureOK= texPool->openTexture(textureFile,textureId,dummy); + return textureOK; +} + +void DrawTexturedQuadOverlay::getBoundingBox(BoundCube &b) const +{ + b.setInvalid(); +} + + +DrawColourBarOverlay::DrawColourBarOverlay() +{ + a=1.0; + string f; + f=getDefaultFontFile(); + font = new FTGLPolygonFont(f.c_str()); +}; + +DrawColourBarOverlay::DrawColourBarOverlay(const DrawColourBarOverlay &oth) +{ + string f; + f=getDefaultFontFile(); + + font = new FTGLPolygonFont(f.c_str()); + a=oth.a; + + rgb=oth.rgb; + min=oth.min; + max=oth.max; + + height=oth.height; + width=oth.width; + + tlX=oth.tlX; + tlY=oth.tlY; +}; + +void DrawColourBarOverlay::draw() const +{ + //Draw quads + float elemHeight; + //80% of bar width is for the actual colour bar itself. + float barWidth=0.8*width; + elemHeight=height/(float)rgb.size(); + glBegin(GL_QUADS); + for(unsigned int ui=0;uiError()) + { +#ifdef DEBUG + std::cerr << "Ah bugger. No font!" << std::endl; +#endif + return; + } + + + + //FTGL units are a pain; The devs could not decide + //whether to implement them in opengl coords or real coords + //so they did neither, and implemented them in "points". + //here we assume that we can transform 1 ftgl unit + //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(); + glTranslatef(tlX+width,tlY,0); + string s; + stream_cast(s,max); + //Note negative sign to flip from y-down screen (opengl) to text dir + //(y up) + glScaled(FTGL_DEFAULT_UNIT_SCALE, + -FTGL_DEFAULT_UNIT_SCALE,FTGL_DEFAULT_UNIT_SCALE); + font->Render(s.c_str()); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(tlX+width,tlY+height,0); + stream_cast(s,min); + //Note negative sign to flip from y-down screen (opengl) to text dir + //(y up) + glScaled(FTGL_DEFAULT_UNIT_SCALE, + -FTGL_DEFAULT_UNIT_SCALE,FTGL_DEFAULT_UNIT_SCALE); + font->Render(s.c_str()); + glPopMatrix(); + glEnable(GL_CULL_FACE); + + + +} + +void DrawColourBarOverlay::setColourVec(const vector &r, + const vector &g, + const vector &b) +{ + ASSERT(r.size() == g.size()); + ASSERT(g.size() == b.size()); + rgb.resize(r.size()); + for(unsigned int ui=0;uigetMinBounds(),field->getMaxBounds()); +} + + +void DrawField3D::setField(const Voxels *newField) +{ + field=newField; +} + +void DrawField3D::setRenderMode(unsigned int mode) +{ + volumeRenderMode=mode; +} + +void DrawField3D::setColourMinMax() +{ + colourMapBound[0]=field->min(); + colourMapBound[1]=field->max(); + + ASSERT(colourMapBound[0] <=colourMapBound[1]); +} + + +void DrawField3D::draw() const +{ + if(alphaVal < sqrt(std::numeric_limits::epsilon())) + return; + + ASSERT(field); + + //Depend upon the render mode + switch(volumeRenderMode) + { + case VOLUME_POINTS: + { + size_t fieldSizeX,fieldSizeY,fieldSizeZ; + Point3D p; + + field->getSize(fieldSizeX,fieldSizeY, fieldSizeZ); + + Point3D delta; + delta = field->getPitch(); + delta*=0.5; + if(!ptsCacheOK) + { + ptsCache.clear(); + for(unsigned int uiX=0; uiXgetData(uiX,uiY,uiZ); + if(v > std::numeric_limits::epsilon()) + { + RGBThis rgb; + //Set colour and point loc + colourMapWrap(colourMapID,rgb.v, + field->getData(uiX,uiY,uiZ), + colourMapBound[0],colourMapBound[1]); + + ptsCache.push_back(make_pair(field->getPoint(uiX,uiY,uiZ)+delta,rgb)); + } + } + } + } + + + ptsCacheOK=true; + } + + if(alphaVal < 1.0f) + { + //We need to generate some points, then sort them by distance + //from eye (back to front), otherwise they will not blend properly + std::vector > eyeDists; + + Point3D camOrigin = curCamera->getOrigin(); + + eyeDists.resize(ptsCache.size()); + + //Set up an original index for the eye distances + #pragma omp parallel for + for(unsigned int ui=0;uigetMinBounds(),field->getMaxBounds(), + boxColourR, boxColourG,boxColourB,boxColourA); + } + //Draw the projections +} + +void DrawField3D::setAlpha(float newAlpha) +{ + alphaVal=newAlpha; +} + +void DrawField3D::setPointSize(float size) +{ + pointSize=size; +} + +void DrawField3D::setMapColours(unsigned int mapID) +{ + ASSERT(mapID < NUM_COLOURMAPS); + colourMapID= mapID; +} + +void DrawField3D::setBoxColours(float rNew, float gNew, float bNew, float aNew) +{ + boxColourR = rNew; + boxColourG = gNew; + boxColourB = bNew; + boxColourA = aNew; + +} + + +DrawIsoSurface::DrawIsoSurface() : cacheOK(false), drawMode(DRAW_SMOOTH), + threshold(0.5f), r(0.5f), g(0.5f), b(0.5f), a(0.5f) +{ +#ifdef DEBUG + voxels=0; +#endif +} + +DrawIsoSurface::~DrawIsoSurface() +{ + if(voxels) + delete voxels; +} + + +bool DrawIsoSurface::needsDepthSorting() const +{ + return a< 1 && a > std::numeric_limits::epsilon(); +} + +void DrawIsoSurface::swapVoxels(Voxels *f) +{ + std::swap(f,voxels); + cacheOK=false; + mesh.clear(); +} + + +void DrawIsoSurface::updateMesh() const +{ + + mesh.clear(); + marchingCubes(*voxels, threshold,mesh); + + cacheOK=true; + +} + +void DrawIsoSurface::getBoundingBox(BoundCube &b) const +{ + if(voxels) + { + b.setBounds(voxels->getMinBounds(), + voxels->getMaxBounds()); + } + else + b.setInverseLimits(); +} + + +void DrawIsoSurface::draw() const +{ + if(a< sqrt(std::numeric_limits::epsilon())) + return; + + if(!cacheOK) + { + //Hmm, we don't have a cached copy of the isosurface mesh. + //we will need to compute one, it would seem. + updateMesh(); + } + + + //This could be optimised by using triangle strips + //rather than direct triangles. + if(a < 1.0f) + { + //We need to sort them by distance + //from eye (back to front), otherwise they will not blend properly + std::vector > eyeDists; + + Point3D camOrigin = curCamera->getOrigin(); + eyeDists.resize(mesh.size()); + + //Set up an original index for the eye distances + #pragma omp parallel for shared(camOrigin) + for(unsigned int ui=0;ui. +*/ + +#ifndef DRAWABLES_H +#define DRAWABLES_H + +#include "textures.h" +#include "cameras.h" +#include "isoSurface.h" + +//STL includes + + + + +//MacOS is "special" and puts it elsewhere +#ifdef __APPLE__ + #include +#else + #include +#endif + +//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) +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 +#include +#include + +enum +{ + FTGL_BITMAP=0, + FTGL_PIXMAP, + FTGL_OUTLINE, + FTGL_POLYGON, + FTGL_EXTRUDE, + FTGL_TEXTURE +}; + +//!Text aligment modes for DrawGLText +enum +{ + DRAWTEXT_ALIGN_LEFT, + DRAWTEXT_ALIGN_CENTRE, + DRAWTEXT_ALIGN_RIGHT, + DRAWTEXT_ALIGN_ENUM_END +}; + + +//!Primitve drawing mode. (wireframe/solid) +enum +{ + DRAW_WIREFRAME, + DRAW_FLAT, + DRAW_SMOOTH, + DRAW_END_ENUM //Not a mode, just a marker to catch end-of-enum +}; + +//!Axis styles +enum +{ + AXIS_IN_SPACE +}; + +//!Drawable types +enum +{ + DRAW_TYPE_POINT, + DRAW_TYPE_MANYPOINT, + DRAW_TYPE_VECTOR, + DRAW_TYPE_TRIANGLE, + DRAW_TYPE_QUAD, + DRAW_TYPE_SPHERE, + DRAW_TYPE_CYLINDER, + DRAW_TYPE_DISPLAYLIST, + DRAW_TYPE_GLTEXT, + DRAW_TYPE_RECTPRISM, + DRAW_TYPE_COLOURBAR, + DRAW_TYPE_TEXTUREDOVERLAY, + DRAW_TYPE_FIELD3D, + DRAW_TYPE_ISOSURFACE, + DRAW_TYPE_AXIS, +}; + + +//!Binding enums. Needed to bind drawable selection +//to internal modification actions inside the drawable +enum +{ + DRAW_SPHERE_BIND_ORIGIN, + DRAW_SPHERE_BIND_RADIUS, + DRAW_VECTOR_BIND_ORIENTATION, + DRAW_VECTOR_BIND_ORIGIN_ONLY, + DRAW_VECTOR_BIND_ORIGIN, + DRAW_VECTOR_BIND_TARGET, + DRAW_CYLINDER_BIND_ORIGIN, + DRAW_CYLINDER_BIND_DIRECTION, + DRAW_CYLINDER_BIND_RADIUS, + DRAW_RECT_BIND_TRANSLATE, + DRAW_RECT_BIND_CORNER_MOVE, + DRAW_TEXT_BIND_ORIGIN, + //DRAW_TEXT_BIND_TEXTDIR, //FIXME: Implement me for annotation todo. + //DRAW_TEXT_BIND_UPDIR, + DRAW_BIND_ENUM_END +}; + + + +//!An abstract bas class for drawing primitives +class DrawableObj +{ + protected: + //!Is the drawable active? + bool active; + + //!Is the object changed since last set? + bool haveChanged; + //!Pointer to current scene camera + static const Camera *curCamera; + + public: + //!Can be selected from openGL viewport interactively? + bool canSelect; + + //!Wants lighting calculations active during render? + bool wantsLight; + + //!Is this an overlay? By default, no + virtual bool isOverlay() const { return false;} + + //!Constructor + DrawableObj(); + + virtual unsigned int getType() const =0; + + //!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;}; + + //!Break object down into simple elements + virtual void explode(std::vector &simpleObjects); + + virtual bool hasChanged() const { return haveChanged; } + + + //!Set the active state of the object + void setActive(bool active); + //!Pure virtual funciton - draw the object + virtual void draw() const =0; + + //!Set if user can interact with object, needed for opengl hit testing + void setInteract(bool canAct){canSelect=canAct;}; + + virtual void getBoundingBox(BoundCube &b) const = 0; + //!Drawable destructor + virtual ~DrawableObj(); + + //!If we offer any kind of external pointer interface; use this to do a recomputation as needed. This is needed for selection binding behaviour + virtual void recomputeParams(const vector &vecs, const vector &scalars, unsigned int mode) {}; + + //!Set the current camera + static void setCurCamera(const Camera *c){curCamera=c;}; + + //!Get the centre of the object. Only valid if object is simple + virtual Point3D getCentroid() const ; + + // virtual DrawableObj *clone() const; + +}; + +//A single point drawing class +class DrawPoint : public DrawableObj +{ + protected: + //!Point origin + Point3D origin; + //!Point colour (r,g,b,a) range: [0.0f,1.0f] + float r,g,b,a; + public: + //!Constructor + DrawPoint(); + //!Constructor that takes in positional argments + DrawPoint(float,float,float); + //!Destructor + virtual ~DrawPoint(); + + //!Sets the color of the point to be drawn + void setColour(float r, float g, float b, float alpha); + //!Draws the points + void draw() const; + //!Sets the location of the poitns + void setOrigin(const Point3D &); + + void getBoundingBox(BoundCube &b) const { b.setInvalid();}; + + Point3D getCentroid() const{ return origin;} +}; + +//!A point drawing class - for many points of same size & colour +class DrawManyPoints : public DrawableObj +{ + protected: + //!Vector of points to draw + std::vector pts; + //!Point colours (r,g,b,a) range: [0.0f,1.0f] + float r,g,b,a; + //!Size of the point + float size; + + mutable bool haveCachedBounds; + mutable BoundCube cachedBounds; + public: + //!Constructor + DrawManyPoints(); + //!Destructor + virtual ~DrawManyPoints(); + + virtual unsigned int getType() const {return DRAW_TYPE_MANYPOINT;}; + //!Swap out the internal vector with an extenal one + void swap(std::vector &); + //!Remove all points + void clear(); + //!Add points into the drawing vector + void addPoints(const std::vector &); + //!Add a single point into the drawing vector, at a particular offset + // *must call resize first* + void setPoint(size_t offset,const Point3D &); + + //!Reset the number of many points to draw + void resize(size_t newSize); + //! set the color of the points to be drawn + void setColour(float r, float g, float b, float alpha); + //!Set the display size of the drawn poitns + void setSize(float); + //!Draw the points + void draw() const; + + //!Shuffle the points to remove anisotropic drawing effects. Thus must be done prior to draw call. + void shuffle(); + //!Get the bounding box that encapuslates this object + void getBoundingBox(BoundCube &b) const; + + //!return number of points + size_t getNumPts() const { return pts.size();}; +}; + +//!Draw a vector +class DrawVector: public DrawableObj +{ + protected: + //!Vector origin + Point3D origin; + Point3D vector; + + //!Do we draw the arrow head? + bool drawArrow; + + //!Radius of tail of arrow + float arrowSize; + + //!Scale arrow head by vector size + bool scaleArrow; + + //!Whether to draw the arrow head at both ends + bool doubleEnded; + + //!Vector colour (r,g,b,a) range: [0.0f,1.0f] + float r,g,b,a; + + //!Size of "tail" line to draw + float lineSize; + public: + //!Constructor + DrawVector(); + //!Destructor + virtual ~DrawVector(); + + virtual unsigned int getType() const {return DRAW_TYPE_VECTOR;}; + + //!Set if we want to draw the arrow or not + void setDrawArrow(bool wantDraw) { drawArrow=wantDraw;} + //!Sets the color of the point to be drawn + void setColour(float r, float g, float b, float alpha); + //!Draws the points + void draw() const; + //!Sets the location of the poitns + void setOrigin(const Point3D &); + //!Sets the location of the poitns + void setVector(const Point3D &); + + //Set the start/end of vector in one go + void setEnds(const Point3D &start, const Point3D &end); + + //Set to draw both ends + void setDoubleEnded(bool wantDoubleEnd=true); + + //!Gets the arrow axis direction + Point3D getVector() const { return vector;}; + + //!Gets the arrow axis direction + Point3D getOrigin() const{ return origin;}; + + //!Set the arrowhead size + void setArrowSize(float size) { arrowSize=size;} + + //!Set the "tail" line size + void setLineSize(float size) { lineSize=size;} + void getBoundingBox(BoundCube &b) const; + + + //!Recompute the internal parameters using the input vector information + void recomputeParams(const std::vector &vecs, + const std::vector &scalars, unsigned int mode); + +}; + +//! A single colour triangle +class DrawTriangle : public DrawableObj +{ + protected: + //!The vertices of the triangle + Point3D vertices[3]; + Point3D vertNorm[3]; + //!Colour data - red, green, blue, alpha + float r,g,b,a; + public: + //!Constructor + DrawTriangle(); + //!Destructor + virtual ~DrawTriangle(); + + virtual unsigned int getType() const {return DRAW_TYPE_TRIANGLE;}; + + //!Set one of three vertices (0-2) locations + void setVertex(unsigned int, const Point3D &); + //!Set the vertex normals + void setVertexNorm(unsigned int, const Point3D &); + //!Set the colour of the triangle + void setColour(float r, float g, float b, float a); + //!Draw the triangle + void draw() const; + //!Get bounding cube + void getBoundingBox(BoundCube &b) const { b.setBounds(vertices,3);} +}; + +//!A smooth coloured quad +/* According to openGL, the quad's vertices need not be coplanar, + * but they must be convex + */ +class DrawQuad : public DrawableObj +{ + private: + //!Vertices of the quad + Point3D vertices[4]; + + //!Colour data for the quad + //!The lighting normal of the triangle + /*! 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(); + //!Destructor + virtual ~DrawQuad(); + + virtual unsigned int getType() const {return DRAW_TYPE_QUAD;}; + //!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 &); + //!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 + /*!Uses the first 3 vertices to calculate the normal. + */ + void calcNormal(); + //!Draw the triangle + void draw() const; + //!Get bounding cube + void getBoundingBox(BoundCube &b) const { return b.setBounds(vertices,4);} +}; + +//!A sphere drawing +class DrawSphere : public DrawableObj +{ + protected: + + //!Pointer to the GLU quadric doohicker + GLUquadricObj *q; + //!Origin of the object + Point3D origin; + //!Colour data - rgba + float r,g,b,a; + //!Sphere radius + float radius; + //!Number of lateral and longitudinal segments + unsigned int latSegments,longSegments; + public: + //!Default Constructor + DrawSphere(); + //! Destructor + virtual ~DrawSphere(); + + virtual unsigned int getType() const {return DRAW_TYPE_SPHERE;}; + //!Sets the location of the sphere's origin + void setOrigin(const Point3D &p); + //!Gets the location of the sphere's origin + Point3D getOrigin() const { return origin;}; + //!Set the number of lateral segments + void setLatSegments(unsigned int); + //!Set the number of longitudinal segments + void setLongSegments(unsigned int); + //!Set the radius + void setRadius(float); + //!get the radius + float getRadius() const { return radius;}; + //!Set the colour (rgba) of the object + void setColour(float r,float g,float b,float a); + //!Draw the sphere + void draw() const; + //!Get the bounding box that encapuslates this object + void getBoundingBox(BoundCube &b) const ; + + //!Recompute the internal parameters using the input vector information + // i.e. this is used for (eg) mouse interaction + void recomputeParams(const vector &vecs, + const vector &scalars, unsigned int mode); + +}; + +//!A tapered cylinder drawing class +class DrawCylinder : public DrawableObj +{ + protected: + //!Pointer to quadric, required for glu. Note the caps are defined as well + GLUquadricObj *q,*qCap[2]; + //!Colours for cylinder + float r,g,b,a; + //!Cylinder start and end radii + float radius; + //!Length of the cylinder + float length; + + //!Origin of base and direction of cylinder + Point3D origin, direction; + //!number of sectors (pie slices) + unsigned int slices; + //!number of vertical slices (should be 1 if endradius equals start radius + unsigned int stacks; + + //!Do we lock the drawing to only use the first radius? + bool radiiLocked; + public: + //!Constructor + DrawCylinder(); + //!Destructor + virtual ~DrawCylinder(); + + virtual unsigned int getType() const {return DRAW_TYPE_CYLINDER;}; + //!Set the location of the base of the cylinder + void setOrigin(const Point3D &pt); + //!Number of cuts perpendicular to axis - ie disks + void setSlices(unsigned int i); + //!Number of cuts along axis - ie segments + void setStacks(unsigned int i); + + //!Gets the location of the origin + Point3D getOrigin() const { return origin;}; + //!Gets the cylinder axis direction + Point3D getDirection() const{ return direction;}; + //!Set end radius + void setRadius(float val); + //!get the radius + float getRadius() const { return radius;}; + //!Set the orientation of cylinder + void setDirection(const Point3D &pt); + //!Set the length of cylinder + void setLength(float len); + //!Set the color of the cylinder + void setColour(float r,float g,float b,float a); + + //!Draw the clyinder + void draw() const; + //!Get the bounding box that encapuslates this object + void getBoundingBox(BoundCube &b) const ; + + //!Recompute the internal parameters using the input vector information + void recomputeParams(const vector &vecs, const vector &scalars, unsigned int mode); + + virtual bool needsDepthSorting() const; + + + + //!Lock (or unlock) the radius to the start radius (i.e. synch the two) + void lockRadii(bool doLock=true) {radiiLocked=doLock;}; +}; + +//!Drawing mode enumeration for scalar field +enum +{ + VOLUME_POINTS=0 +}; + +//!A display list generating class +/*! This class allows for the creation of display lists for openGL objects + * You can use this class to create a display list which will allow you to + * reference cached openGL calls already stored in the video card. + * This can be used to reduce the overhead in the drawing routines + */ +class DrawDispList : public DrawableObj +{ + private: + //!Static variable for the next list number to generate + unsigned int listNum; + //!True if the list is active (collecting/accumulating) + bool listActive; + //!Bounding box of objects in display list + BoundCube boundBox; + public: + //!Constructor + DrawDispList(); + //!Destructor + virtual ~DrawDispList(); + + virtual unsigned int getType() const {return DRAW_TYPE_DISPLAYLIST;} + + //!Execute the display list + void draw() const; + + //!Set it such that many openGL calls map to the display list. + /*!If "execute" is true, the commands will be excuted after + * accumulating the display list buffer + * For a complete list of which calls map to the dispaly list, + * see the openGL spec, "Display lists" + */ + bool startList(bool execute); + + //!Add a drawable object - list MUST be active + /* If the list is not active, this will simply exectue + * the draw function of the drawable + */ + void addDrawable(const DrawableObj *); + + //!Close the list - this *will* clear the gl error system + bool endList(); + //!Get bounding cube + void getBoundingBox(BoundCube &b) const { b=boundBox;} + +}; + +//!A class to draw text obects using FTGL +/*May not be the best way to do this. + * MIght be better to have static instances + * of each possible type of font, then + * render the text appropriately + */ +class DrawGLText : public DrawableObj +{ + + private: + + //!FTGL font instance + FTFont *font; + + //!Font string + std::string fontString; + //!Current font mode + unsigned int curFontMode; + + //!Text string + std::string strText; + //!Origin of text + Point3D origin; + //!Alignment mode + unsigned int alignMode; + + //!Colours for text + float r,g,b,a; + + //Two vectors required to define + //these should always give a dot prod of + //zero + + //!Up direction for text + Point3D up; + + //!Text flow direction + Point3D textDir; + + //!Direction for which text should be legible + /*! This will ensure that the text is legible from + * the direction being pointed to by normal. It is + * not the true normal of the quad. as the origin and the + * up direction specify some of that data already + */ + Point3D readDir; + + //!True if no erro + bool isOK; + + //!Ensure that the text is never mirrored from view direction + bool ensureReadFromNorm; + public: + //!Constructor (font file & text mode) + /* Valid font types are FTGL_x where x is + * BITMAP + * PIXMAP + * OUTLINE + * POLYGON + * EXTRUDE + * TEXTURE + */ + DrawGLText(std::string fontFile, + unsigned int ftglTextMode); + DrawGLText(const DrawGLText &other); + + //!Destructor + virtual ~DrawGLText(); + + virtual unsigned int getType() const {return DRAW_TYPE_GLTEXT;} + //!Set the size of the text (in points (which may be GL units, + //unsure)) + inline void setSize(unsigned int size) + {if(isOK){font->FaceSize(size);}}; + //!Set the depth of the text (in points, may be GL units, unsure) + inline void setDepth(unsigned int depth) + {if(isOK){font->Depth(depth);}}; + //!Returs true if the class data is good + inline bool ok() const + {return isOK;}; + + //!Set the text string to be displayed + inline void setString(const std::string &str) + {strText=str;}; + + //!Render the text string + void draw() const; + + //!Set the up direction for the text + /*!Note that this must be orthogonal to + * the reading direction + */ + inline void setUp(const Point3D &p) + { up=p;up.normalise();}; + //!Set the origin + inline void setOrigin(const Point3D &p) + { origin=p;}; + //!Set the reading direction + /*!The reading direction is the direction + * from which the text should be legible + * This direction is important only if ensureReadFromNorm + * is set + */ + inline void setReadDir(const Point3D &p) + { readDir=p;}; + + //!Set the text flow direction + /*! This *must* be orthogonal to the up vector + * i.e. forms a right angle with + */ + inline void setTextDir(const Point3D &p) + {textDir=p;textDir.normalise();} + //!Return the location of the lower-left of the text + inline Point3D getOrigin() const + {return origin;}; + + inline void setReadFromNorm(bool b) + {ensureReadFromNorm=b;} + + //!Set the colour (rgba) of the object + void setColour(float r,float g,float b,float a); + + //!Get the bounding box for the text + void getBoundingBox(BoundCube &b) const; + + //!Set the text alignment (default is left) + void setAlignment(unsigned int mode); + + //Binding parameter recomputation + void recomputeParams(const vector &vecs, + const vector &scalars, unsigned int mode); +}; + + + + +//!A class to draw rectangluar prisms +class DrawRectPrism : public DrawableObj +{ + private: + //!Drawing mode, (line or surface); + unsigned int drawMode; + //!Colours for prism + float r,g,b,a; + //!Lower left and upper right of box + Point3D pMin, pMax; + //!Thickness of line + float lineWidth; + public: + DrawRectPrism(); + ~DrawRectPrism(); + + virtual unsigned int getType() const {return DRAW_TYPE_RECTPRISM;} + + //!Draw object + void draw() const; + + //!Set the draw mode + void setDrawMode(unsigned int n) { drawMode=n;}; + //!Set colour of box + void setColour(float rnew, float gnew, float bnew, float anew); + //!Set thickness of box + void setLineWidth(float lineWidth); + //!Set up box as axis-aligned rectangle using two points + void setAxisAligned(const Point3D &p1,const Point3D &p2); + //!Set up box as axis-aligned rectangle using bounding box + void setAxisAligned(const BoundCube &b); + + void getBoundingBox(BoundCube &b) const; + + //!Recompute the internal parameters using the input vector information + void recomputeParams(const vector &vecs, const vector &scalars, unsigned int mode); +}; + +struct RGBFloat +{ + float v[3]; +}; + +class DrawColourBarOverlay : public DrawableObj +{ + private: + FTFont *font; + + //!Colours for each element + vector rgb; + //alpha (transparancy) value + float a; + //!Minimum and maximum values for the colour bar (for ticks) + float min,max; + //!Height and width of bar (total) + float height,width; + //!top left of bar + float tlX,tlY; + + public: + + DrawColourBarOverlay(); + DrawColourBarOverlay(const DrawColourBarOverlay &o); + ~DrawColourBarOverlay(){delete font;}; + + + virtual unsigned int getType() const {return DRAW_TYPE_COLOURBAR;} + + void getBoundingBox(BoundCube &b) const ; + + //!This is an overlay + bool isOverlay() const {return true;}; + void setColourVec(const vector &r, + const vector &g, + const vector &b); + //!Draw object + void draw() const; + + void setAlpha(float alpha) { a=alpha;}; + void setSize(float widthN, float heightN) {height=heightN, width=widthN;} + void setPosition(float newTLX,float newTLY) { tlX=newTLX; tlY=newTLY;} + void setMinMax(float minNew,float maxNew) { min=minNew;max=maxNew;}; + +}; + +//!A class to hande textures to draw +class DrawTexturedQuadOverlay : public DrawableObj +{ + private: + TexturePool *texPool; + unsigned int textureId; + float position[2]; + float length; + unsigned int winX,winY; + + bool textureOK; + public: + DrawTexturedQuadOverlay(); + ~DrawTexturedQuadOverlay(); + + virtual unsigned int getType() const {return DRAW_TYPE_TEXTUREDOVERLAY;} + + //!This is an overlay + bool isOverlay() const {return true;}; + + 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;}; + + void setSize(float size); + + //!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; + + void getBoundingBox(BoundCube &b) const ; +}; + + +struct RGBThis +{ + unsigned char v[3]; +}; + +//!This class allows for the visualisation of 3D scalar fields +class DrawField3D : public DrawableObj +{ + private: + mutable std::vector > ptsCache; + mutable bool ptsCacheOK; + protected: + //!Alpha transparancy of objects in field + float alphaVal; + + //!Size of points in the field - + //only meaningful if the render mode is set to alpha blended points + float pointSize; + + //!True if the scalar field's bounding box is to be drawn + bool drawBoundBox; + + //!Colours for the bounding boxes + float boxColourR,boxColourG,boxColourB,boxColourA; + + //!True if volume grid is enabled + bool volumeGrid; + + //!Colour map lower and upper bounds + float colourMapBound[2]; + + //!Which colourmap to use + unsigned int colourMapID; + + //!Sets the render mode for the 3D volume + /* Possible modes + * 0: Alpha blended points + */ + unsigned int volumeRenderMode; + //!The scalar field - used to store data values + const Voxels *field; + public: + //!Default Constructor + DrawField3D(); + //!Destructor + virtual ~DrawField3D(); + + virtual unsigned int getType() const {return DRAW_TYPE_FIELD3D;} + + //!Get the bounding box for this object + void getBoundingBox(BoundCube &b) const; + + //!Set the render mode (see volumeRenderMode variable for details) + void setRenderMode(unsigned int); + + //!Set the field pointer + void setField(const Voxels *field); + + //!Set the alpha value for elemnts + void setAlpha(float alpha); + + //!Set the colour bar minima and maxima from current field values + void setColourMinMax(); + + //!Set the colourMap ID + void setColourMapID(unsigned int i){ colourMapID=i;}; + + //!Render the field + void draw() const; + + //!Set the size of points + void setPointSize(float size); + + //!Set the colours that ar ebeing used in the tempMap + void setMapColours(unsigned int map); + + //!Set the coour of the bounding box + void setBoxColours(float r, float g, float b, float a); + +}; + +class DrawIsoSurface: public DrawableObj +{ +private: + + mutable bool cacheOK; + + //!should we draw the thing + // - in wireframe + // -Flat + // -Smooth + // + unsigned int drawMode; + + //!Isosurface scalar threshold + float threshold; + + Voxels *voxels; + + mutable vector mesh; + + //!Warning. Although I declare this as const, I do some naughty mutating to the cache. + void updateMesh() const; + + //!Point colour (r,g,b,a) range: [0.0f,1.0f] + float r,g,b,a; +public: + + DrawIsoSurface(); + ~DrawIsoSurface(); + + virtual unsigned int getType() const {return DRAW_TYPE_ISOSURFACE;} + //!Transfer ownership of data pointer to class + void swapVoxels(Voxels *v); + + //!Set the drawing method + + //Draw + void draw() const; + + //!Set the isosurface value + void setScalarThresh(float thresh) { threshold=thresh;cacheOK=false;mesh.clear();}; + + //!Get the bouding box (of the entire scalar field) + void getBoundingBox(BoundCube &b) const ; + + //!Sets the color of the point to be drawn + void setColour(float rP, float gP, float bP, float alpha) { r=rP;g=gP;b=bP;a=alpha;} ; + + //!Do we need depth sorting? + bool needsDepthSorting() const; +}; + + +class DrawAxis : public DrawableObj +{ + private: + //!Drawing style + unsigned int style; + Point3D position; + //!size + float size; + public: + DrawAxis(); + ~DrawAxis(); + + virtual unsigned int getType() const {return DRAW_TYPE_AXIS;} + + //!Draw object + void draw() const; + + + void setStyle(unsigned int style); + void setSize(float newSize); + void setPosition(const Point3D &p); + + void getBoundingBox(BoundCube &b) const; +}; +#endif diff -Nru 3depict-0.0.12/src/gl/effect.cpp 3depict-0.0.13/src/gl/effect.cpp --- 3depict-0.0.12/src/gl/effect.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/effect.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,704 @@ +/* + * effect.cpp - 3D visuals effects implementation + * 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 . +*/ + + +#include "effect.h" + + + +#include "common/xmlHelper.h" +#include "common/stringFuncs.h" +#include "common/constants.h" + +Camera* Effect::curCam=0; +BoundCube Effect::bc; +float MIN_CROP_FRACTION=0.0001; + +const unsigned int NUM_EFFECTS=2; +const char *EFFECT_NAMES[] = { "boxcrop", + "anaglyph" + }; + +//factory functions +Effect *makeEffect(unsigned int effectID) +{ + Effect *e; + switch(effectID) + { + case EFFECT_ANAGLYPH: + e = new AnaglyphEffect; + break; + + case EFFECT_BOX_CROP: + e=new BoxCropEffect; + break; + + default: + ASSERT(false); + } + + return e; +} + + + +Effect *makeEffect(const std::string &str) +{ + Effect *e=0; + + for(unsigned int ui=0;uigetType()]; +} + +BoxCropEffect::BoxCropEffect() : openGLIdStart(0), useCamCoordinates(false) +{ + effectType=EFFECT_BOX_CROP; +} + +void BoxCropEffect::enable(unsigned int pass) const +{ + + //we only need to do anything on the first pass. All other passes are unchanged + if(pass) + return; + //Compute the bounding box that is the clipped boundary + Point3D pAAB[2]; //Axis aligned box + bc.getBounds(pAAB[0],pAAB[1]); + + Point3D pCentre; + pCentre = (pAAB[0] + pAAB[1])*0.5f; + + unsigned int glOffset=openGLIdStart; + + if(useCamCoordinates) + { + Point3f pBox[8]; + for(unsigned int ui=0;ui<8;ui++) + { + //Counting in binary to generate box corner vertices. + pBox[ui].fx = pAAB[(ui>>2) &1][0]; + pBox[ui].fy = pAAB[(ui>>1) &1][1]; + pBox[ui].fz = pAAB[ui&1][2]; + } + //Translate to rotate around the box centre + for(unsigned int ui=0;ui<8;ui++) + { + pBox[ui].fx-=pCentre[0]; + pBox[ui].fy-=pCentre[1]; + pBox[ui].fz-=pCentre[2]; + } + + Point3D x,y,z; + //get camera orientation data + z= curCam->getUpDirection(); + y= curCam->getViewDirection(); + + //We need to first do a "passive" coordinate transformation on the box coordinates + //to determine the box coordinates in camera basis vectors (after translation such tat + //centre of box is in centre of world). + + //Active transformations are v'=Tv_orig. Passive transformation is that v_prime = T^-1 v_orig + // + + z.normalise(); //Not needed, I think.. but can't hurt + y.normalise(); + x= z.crossProd(y); + + float angle; + angle=z.angle(Point3D(0,0,1)); + + + + //If needed, perform a rotation to align the box up + //vector with the camera up vector + Point3f r; + Point3D yTmpRot; + if(fabs(angle) > sqrtf(std::numeric_limits::epsilon())) + { + Point3D rotateAxis; + + + //Check for numerical stability problem when camera + //& world z axes point exactly apart + if( fabs(angle-M_PI) ::epsilon())) + rotateAxis=Point3D(1,0,0); //Pick *any* vector in X-Y plane. + else + rotateAxis = z.crossProd(Point3D(0,0,1)); + rotateAxis.normalise(); + + r.fx=rotateAxis[0]; + r.fy=rotateAxis[1]; + r.fz=rotateAxis[2]; + + for(unsigned int ui=0;ui<8;ui++) + quat_rot(&(pBox[ui]),&r,angle); + + + Point3f yRot; + yRot.fx=0; + yRot.fy=1; + yRot.fz=0; + quat_rot(&yRot,&r,angle); + + yTmpRot=Point3D(yRot.fx,yRot.fy,yRot.fz); + + ASSERT(yTmpRot.sqrMag() > sqrtf(std::numeric_limits::epsilon())); + + } + else + yTmpRot=Point3D(0,1,0); + + //Rotating around the z axis to set "spin" + r.fx=z[0]; + r.fy=z[1]; + r.fz=z[2]; + + angle=y.angle(yTmpRot); + + + if( fabs(angle) > sqrtf(std::numeric_limits::epsilon())) + { + //Spin the box around to match the final coordinate system + for(unsigned int ui=0;ui<8;ui++) + quat_rot(&(pBox[ui]),&r,angle); + } + + + //Now compute the box coordinates, then break their position + //vectors (from box centre) down into the basis + //coordinates of our camera + Point3D pBoxVertices[8]; + + for(unsigned int ui=0;ui<8;ui++) + pBoxVertices[ui]= Point3D(pBox[ui].fx, + pBox[ui].fy,pBox[ui].fz); + + float dotValue[3]; + dotValue[0]=dotValue[1]=dotValue[2]=-std::numeric_limits::max(); + //Find the largest positive basis components (these form the camera BB limits) + for(unsigned int ui=0;ui<8;ui++) + { + float tmp; + tmp =x.dotProd(pBoxVertices[ui]); + if(tmp > dotValue[0]) + dotValue[0]=tmp; + + tmp =y.dotProd(pBoxVertices[ui]); + if(tmp > dotValue[1]) + dotValue[1]=tmp; + + tmp =z.dotProd(pBoxVertices[ui]); + if(tmp > dotValue[2]) + dotValue[2]=tmp; + + } + + //Compute the cropping deltas in the range [-1,1] + float dC[6]; + for(unsigned int ui=0;ui<6;ui++) + { + + if(ui&1) + { + //upper + dC[ui] =2.0*(0.5- cropFractions[ui]); + } + else + { + //Lower + dC[ui]=2.0*(cropFractions[ui]-0.5); + } + } + + //Cropping delta * dotproduct *basisvector == crop point + //Note the reversal of the Z and Y vectors + pAAB[0] = pCentre + x*dotValue[0]*dC[0] + +y*dotValue[1]*dC[2]+z*dotValue[2]*dC[4]; + pAAB[1] = pCentre + x*dotValue[0]*dC[1] + +y*dotValue[1]*dC[3]+z*dotValue[2]*dC[5]; + + + //Draw crop iff crop fractions are +ve + + //X + if(cropFractions[0] >=MIN_CROP_FRACTION) + { + doClip(pAAB[0],x,glOffset); + glOffset++; + } + if(cropFractions[1] >=MIN_CROP_FRACTION) + { + doClip(pAAB[1],-x,glOffset); + glOffset++; + } + + //Y + if(cropFractions[2] >=MIN_CROP_FRACTION) + { + doClip(pAAB[0],y,glOffset); + glOffset++; + } + if(cropFractions[3] >=MIN_CROP_FRACTION) + { + doClip(pAAB[1],-y,glOffset); + glOffset++; + } + + //Z + if(cropFractions[4] >=MIN_CROP_FRACTION) + { + doClip(pAAB[0],z,glOffset); + glOffset++; + } + if(cropFractions[5] >=MIN_CROP_FRACTION) + { + doClip(pAAB[1],-z,glOffset++); + glOffset++; + } + } + else + { + pAAB[0] = pCentre + Point3D(0.5-cropFractions[0], + 0.5-cropFractions[2],0.5-cropFractions[4])*(pAAB[0]-pCentre)*2.0; + pAAB[1] = pCentre + Point3D(0.5-cropFractions[1], + 0.5-cropFractions[3],0.5-cropFractions[5])*(pAAB[1]-pCentre)*2.0; + + for(unsigned int ui=0;ui<6;ui++) + { + Point3D normal; + + //Don't update minimum crop fractions + if(cropFractions[ui] < MIN_CROP_FRACTION) + continue; + //Set up the normal & origin (use rectangular prism vertex as origin) + normal=Point3D(0,0,0); + normal.setValue(ui/2,1); + if(ui&1) + { + normal=-normal; + doClip(pAAB[1],normal,glOffset); + } + else + doClip(pAAB[0],normal,glOffset); + + glOffset++; + } + } +} + +void BoxCropEffect::doClip(const Point3D &origin, const Point3D &normal, unsigned int glOffset) const +{ + double array[4]; + //Ax + By + Cz + D =0. Prove from + //n.dot(v-p_0)=0 + array[0]=normal[0]; + array[1]=normal[1]; + array[2]=normal[2]; + array[3] = -normal.dotProd(origin); + + + glMatrixMode(GL_MODELVIEW); + + //Set up the effect + glClipPlane(GL_CLIP_PLANE0 +glOffset, + array); + glEnable(GL_CLIP_PLANE0+glOffset); + + +} + +void BoxCropEffect::disable() const +{ + unsigned int startId=openGLIdStart; + + for(unsigned int ui=0; ui<6;ui++) + { + if(cropFractions[ui]>= MIN_CROP_FRACTION) + { + glDisable(GL_CLIP_PLANE0+startId); + startId++; + } + } +} + +bool BoxCropEffect::willDoSomething() const +{ + for(unsigned int ui=0;ui<6;ui++) + { + if(cropFractions[ui]>=MIN_CROP_FRACTION) + return true; + } + + return false; +} + +void BoxCropEffect::setFractions(const float *frac) +{ + for(unsigned int ui=0;ui<6;ui++) + cropFractions[ui]=frac[ui]; +} + +float BoxCropEffect::getCropValue(unsigned int pos) const +{ + ASSERT(pos<6); + return cropFractions[pos]; +} + + +void BoxCropEffect::getCroppedBounds(BoundCube &b) const +{ + Point3D pLow,pHi; + b.getBounds(pLow,pHi); + + Point3D pCentre = (pLow+pHi)*0.5; + pLow = pCentre + Point3D(0.5-cropFractions[0], + 0.5-cropFractions[2],0.5-cropFractions[4])*(pLow-pCentre)*2.0; + pHi = pCentre + Point3D(0.5-cropFractions[1], + 0.5-cropFractions[3],0.5-cropFractions[5])*(pHi-pCentre)*2.0; + + b.setBounds(pLow,pHi); +} + +bool BoxCropEffect::writeState(std::ofstream &f, unsigned int format, unsigned int depth) const +{ + using std::endl; + switch(format) + { + case STATE_FORMAT_XML: + f << tabs(depth+1) << "" << endl; + + f << tabs(depth+2) << "" << endl; + for(unsigned int ui=0;ui<6;ui++) + { + f << tabs(depth+3) << "" << endl; + } + + f << tabs(depth+2) << "" << endl; + + + f << tabs(depth+2) << "" << endl; + f << tabs(depth+1) << "" << endl; + break; + + default: + ASSERT(false); + return false; + + } + + return true; +} + + +bool BoxCropEffect::readState(xmlNodePtr nodePtr) +{ + using std::string; + + nodePtr=nodePtr->xmlChildrenNode; + xmlNodePtr scalars; + if(XMLHelpFwdToElem(nodePtr,"cropvalues")) + return false; + + scalars=nodePtr->xmlChildrenNode; + + for(unsigned int ui=0;ui<6;ui++) + { + if(!XMLGetNextElemAttrib(scalars,cropFractions[ui],"scalar","value")) + return false; + } + + string s; + if(!XMLGetNextElemAttrib(nodePtr,s,"usecamcoordinates","value")) + return false; + + if(s=="0") + useCamCoordinates=false; + else if (s == "1") + useCamCoordinates=true; + else + return false; + + + return true; +} + + +AnaglyphEffect::AnaglyphEffect() : colourMode(ANAGLYPH_REDBLUE), eyeFlip(false), + oldCam(0),baseShift(0.01f) +{ + effectType=EFFECT_ANAGLYPH; +} + +void AnaglyphEffect::enable(unsigned int passNumber) const +{ + if(passNumber >1 || curCam->type() !=CAM_LOOKAT) + return; + + if(passNumber==0) + { + oldCam=curCam->clone(); + //Translate both the target, and the origin + curCam->translate(baseShift,0); + //Apply the frustum offset to restore the shifted focal plane + ((CameraLookAt*)curCam)->setFrustumDistort(baseShift); + + } + else + { + *curCam=*oldCam; + //this time, in the reverse direction; + //Translate both the target, and the origin + curCam->translate(-baseShift,0); + //Apply the frustum offset to restore the shifted focal plane + ((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); + + + //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); + } + 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); + + 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); + } + + } + + + +} + +void AnaglyphEffect::setMode(unsigned int mode) +{ + ASSERT(colourMode" << endl; + f << tabs(depth+2) << "" << endl; + + f << tabs(depth+2) << "" << endl; + f << tabs(depth+2) << "" << endl; + f << tabs(depth+1) << "" << endl; + break; + + default: + ASSERT(false); + return false; + + } + + return true; +} + + +bool AnaglyphEffect::readState(xmlNodePtr nodePtr) +{ + using std::string; + + if(!XMLGetNextElemAttrib(nodePtr,colourMode,"colourmode","value")) + return false; + if(colourMode >= ANAGLYPH_HALF_COLOUR) + return false; + + + string s; + if(!XMLGetNextElemAttrib(nodePtr,s,"eyeflip","value")) + return false; + + + if(s == "0") + eyeFlip=false; + else if(s == "1") + eyeFlip=true; + else + return false; + + if(!XMLGetNextElemAttrib(nodePtr,baseShift,"baseshift","value")) + return false; + + return true; +} + + diff -Nru 3depict-0.0.12/src/gl/effect.h 3depict-0.0.13/src/gl/effect.h --- 3depict-0.0.12/src/gl/effect.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/effect.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,200 @@ +/* + * effect.h - opengl 3D effects 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 . +*/ + +#ifndef EFFECT_H +#define EFFECT_H + +#ifdef ATTRIBUTE_PRINTF + #pragma push_macro("ATTRIBUTE_PRINTF") + #include + #pragma pop_macro(" ATTRIBUTE_PRINTF") +#else + #include + #undef ATTRIBUTE_PRINTF +#endif + +//OpenGL includes +//MacOS is "special" and puts it elsewhere +#ifdef __APPLE__ + #include +#else + #include +#endif + +#include "cameras.h" + +//opengl allows up to 6 clipping planes +const unsigned int MAX_OPENGL_CLIPPLANES=6; + +//Effect IDs +enum +{ + EFFECT_BOX_CROP=0, + EFFECT_ANAGLYPH, + EFFECT_ENUM_END +}; + + +enum{ + //Colour mask methods + ANAGLYPH_REDBLUE, + ANAGLYPH_REDGREEN, + ANAGLYPH_REDCYAN, + ANAGLYPH_GREENMAGENTA, + //Colour matrix +accumulation buffer methods + ANAGLYPH_HALF_COLOUR, + ANAGLYPH_MIXED, + ANAGLYPH_ENUM_END //Not a method. end of enum +}; + +class Effect +{ + protected: + static Camera *curCam; + static BoundCube bc; + unsigned int effectType; + public: + Effect(); + virtual ~Effect() {}; + virtual void enable(unsigned int pass=0) const =0; + virtual void disable() const=0; + std::string getName() const; + + + //Write the effect's state information to file + virtual bool writeState(std::ofstream &f, + unsigned int format, unsigned int depth) const=0; + //read the effects state information from an XML file + virtual bool readState(xmlNodePtr n)=0; + + virtual bool needCamUpdate() const { return false;} + + //!Returns true if the effect has any influence on the output + virtual bool willDoSomething() const=0; + + virtual unsigned int numPassesNeeded() const { return 1;} + + virtual unsigned int getType() const { return effectType;}; + static void setCurCam(Camera *c) {curCam=c;} + static void setBoundingCube(const BoundCube &c) {bc=c;} + +}; + + +class BoxCropEffect : public Effect +{ + private: + //controlling ID values for gl plane. No more than MAX_OPENGL_CLIPPLANES allowed + unsigned int openGLIdStart,openGLIdEnd; + //Cropping margins (Fraction from edge towards opposite edge (complete)). 0->1. + //Opposing edges must sum to 0->1. (xLo,xHi,yLo...) + float cropFractions[6]; + //!True if we should transform to camera coordinates before applying crop + bool useCamCoordinates; + + //!Aspect ratio of output image + float outputAspect; + + void doClip(const Point3D &origin, const Point3D & normal,unsigned int glOffset) const; + public: + BoxCropEffect(); + virtual ~BoxCropEffect(){}; + + //!Enable the clipping plane. Values *must* be set before calling + void enable(unsigned int pass) const; + + //!DIsable the clipping plane + void disable() const; + + + + //Write the effect's state information to file + bool writeState(std::ofstream &f, unsigned int format, + unsigned int depth) const; + //read the effects state information from an XML file + bool readState(xmlNodePtr n); + + //!Returns true if the effect has any influence on the output + bool willDoSomething() const; + + //!Set the fractions of cube from margin + //-- there should be 6 floats (x,y,z)_(low,high) (x_lo, x_hi....) + // each low/hi should form a sum between 0 and 1. + void setFractions(const float *fractionArray); + + void useCamCoords(bool enable){useCamCoordinates=enable;}; + + //!Alters the input box to generate cropping bounding box + //note the box may be inside out if the cropping limits + //exceed themselves.. + void getCroppedBounds(BoundCube &b) const; + + float getCropValue(unsigned int pos) const; +}; + +class AnaglyphEffect : public Effect +{ + private: + unsigned int colourMode; + bool eyeFlip; + + mutable Camera *oldCam; + float baseShift; + + public: + AnaglyphEffect(); + ~AnaglyphEffect(){}; + + //!Enable the clipping plane. Values *must* be set before calling + void enable(unsigned int pass) const; + + //!DIsable the clipping plane + void disable() const; + + //Write the effect's state information to file + bool writeState(std::ofstream &f, unsigned int format, + unsigned int depth) const; + //read the effects state information from an XML file + bool readState(xmlNodePtr n); + + //!Whether we should be flipping the lens from its hard-coded left-right + void setFlip(bool shouldFlip) {eyeFlip=shouldFlip;}; + + void setMode(unsigned int mode); + void setBaseShift(float shift) { baseShift=shift;}; + + bool needCamUpdate() const { return true;} + //!Returns true if the effect has any influence on the output + bool willDoSomething() const {return true;}; + + virtual unsigned int numPassesNeeded() const { return 2;} + + + float getBaseShift() const { return baseShift;}; + unsigned int getMode() const { return colourMode;}; + + +}; + + +Effect *makeEffect(unsigned int effectID); + +Effect *makeEffect(const std::string &s); + + +#endif diff -Nru 3depict-0.0.12/src/gl/isoSurface.cpp 3depict-0.0.13/src/gl/isoSurface.cpp --- 3depict-0.0.12/src/gl/isoSurface.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/isoSurface.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,740 @@ +/* + * IsoSurface.cpp - Isosurface interface generation + * 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 . +*/ + +#include "isoSurface.h" + +#include + +#ifdef DEBUG +template +bool mapUnique(const std::map &m) +{ + vector vec; + vec.reserve(m.size()); + + for(typename std::map::const_iterator it = m.begin(); it!=m.end(); ++it) + { + if(std::find(vec.begin(),vec.end(),it->second) != vec.end()) + return false; + + vec.push_back(it->second); + + } + + return true; +} +#endif + + +//input vector "vec" must be sorted and unique +template +void removeElements( const std::vector &elems,std::vector &vec) +{ + if(vec.empty() || elems.empty()) + return; + + if(vec.size() == elems.size()) + { + vec.clear(); + return; + } + + size_t offset=vec.size()-1; + //Run backwards, swapping out + for(size_t ui=elems.size();ui--;) + { + ASSERT(ui <= offset); + std::swap(vec[elems[ui]],vec[offset]); + offset--; + } + vec.resize(offset+1); +} + + + + +void TriangleWithVertexNorm::computeACWNormal(Point3D &n) const +{ + Point3D a,b; + + a = p[0]-p[1]; + b = p[0]-p[2]; + + n=a.crossProd(b); + n.normalise(); +} + +void TriangleWithVertexNorm::safeComputeACWNormal(Point3D &n) const +{ + Point3D a,b; + + a = p[0]-p[1]; + b = p[0]-p[2]; + + n=a.crossProd(b); + if(n.sqrMag() < sqrt(std::numeric_limits::epsilon()) ) + n=Point3D(0,0,1); + else + n.normalise(); + + + +} + +float TriangleWithVertexNorm::computeArea() const +{ + Point3D a,b; + + a = p[0]-p[1]; + b = p[0]-p[2]; + + return a.crossProd(b).sqrMag(); + +} + +bool TriangleWithVertexNorm::isDegenerate() const +{ + return (p[0].sqrDist(p[1]) < std::numeric_limits::epsilon() || + p[0].sqrDist(p[2]) < std::numeric_limits::epsilon() || + p[2].sqrDist(p[1]) < std::numeric_limits::epsilon()); +} + +void TriangleWithVertexNorm::getCentroid(Point3D &c) const +{ + c=p[0]; + c+=p[1]; + c+=p[2]; + + c*=1.0f/3.0f; +} + +//This code is a modified version of the following: +//============== +// Marching Cubes Example Program +// by Cory Bloyd (corysama@yahoo.com) +// +// A simple, portable and complete implementation of the Marching Cubes +// and Marching Tetrahedrons algorithms in a single source file. +// There are many ways that this code could be made faster, but the +// intent is for the code to be easy to understand. +// +// For a description of the algorithm go to +// http://astronomy.swin.edu.au/pbourke/modelling/polygonise/ +// +// The original code is public domain, and is used here under the GNU General Public Licence, V3 or later. +// ========= + +// For any edge, if one vertex is inside of the surface and the other is outside of the surface +// then the edge intersects the surface +// For each of the 8 vertices of the cube can be two possible states : either inside or outside of the surface +// For any cube the are 2^8=256 possible sets of vertex states +// This table lists the edges intersected by the surface for all 256 possible vertex states +// There are 12 edges. For each entry in the table, if edge #n is intersected, then bit #n is set to 1 +int aiCubeEdgeFlags[256]= +{ + 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 +}; + +// For each of the possible vertex states listed in aiCubeEdgeFlags there is a specific triangulation +// of the edge intersection points. a2iTriangleConnectionTable lists all of them in the form of +// 0-5 edge triples with the list terminated by the invalid value -1. +// For example: a2iTriangleConnectionTable[3] list the 2 triangles formed when corner[0] +// and corner[1] are inside of the surface, but the rest of the cube is not. +// +// I found this table in an example program someone wrote long ago. It was probably generated by hand + +int a2iTriangleConnectionTable[256][16] = +{ + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, + {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, + {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, + {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, + {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, + {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, + {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, + {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, + {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, + {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, + {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, + {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, + {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, + {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, + {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, + {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, + {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, + {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, + {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, + {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, + {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, + {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, + {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, + {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, + {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, + {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, + {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, + {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, + {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, + {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, + {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, + {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, + {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, + {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, + {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, + {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, + {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, + {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, + {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, + {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, + {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, + {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, + {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, + {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, + {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, + {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, + {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, + {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, + {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, + {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, + {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, + {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, + {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, + {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, + {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, + {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, + {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, + {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, + {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, + {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, + {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, + {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, + {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, + {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, + {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, + {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, + {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, + {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, + {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, + {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, + {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, + {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, + {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, + {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, + {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, + {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, + {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, + {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, + {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, + {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, + {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, + {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, + {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, + {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, + {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, + {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, + {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, + {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, + {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, + {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, + {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, + {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, + {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, + {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, + {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, + {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, + {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} +}; + +//a2fVertexOffset lists the positions, relative to vertex0, of each of the 8 vertices of a cube +static const float a2fVertexOffset[8][3] = +{ + {0.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0},{1.0, 0.0, 1.0},{1.0, 1.0, 1.0},{0.0, 1.0, 1.0} +}; + +//The deltas for the vertex offsets. This is the int version of a2fVertexOffset +const unsigned int VERTEX_OFFSET[8][3] = +{ + {0, 0, 0},{1, 0, 0},{1, 1, 0},{0, 1, 0}, + {0, 0, 1},{1, 0, 1},{1, 1, 1},{0, 1, 1} +}; + +//a2iEdgeConnection lists the index of the endpoint vertices for each of the 12 edges of the cube +static const int a2iEdgeConnection[12][2] = +{ + {0,1}, {1,2}, {2,3}, {3,0}, + {4,5}, {5,6}, {6,7}, {7,4}, + {0,4}, {1,5}, {2,6}, {3,7} +}; + +//a2fEdgeDirection lists the direction vector (vertex1-vertex0) for each edge in the cube +static const float a2fEdgeDirection[12][3] = +{ + {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0}, + {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0}, + {0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{ 0.0, 0.0, 1.0},{0.0, 0.0, 1.0} +}; + +//Mapping between edges as defined in a2iEdgeConenction, (and thus implicitly in edge table) +//and the voxels.h definition +int edgeRemap[12] ={ 0,6,1,4, + 2,7,3,5, + 8,10,11,9}; + + +//vMarchingCubes iterates over the entire dataset, calling vMarchCube on each cube +void marchingCubes(const Voxels &v,float isoValue, vector &tVec) +{ + size_t nx,ny,nz; + v.getSize(nx,ny,nz); + + ASSERT(nx > 1 && ny>1 && nz>1); + + //Don't try to isosurface a any volume with a unitary dimension. + if(nx ==1 || ny ==1 || nz == 1) + return; + + Point3D gridSpacing; + gridSpacing=v.getPitch(); + +#ifdef DEBUG + BoundCube boundC; + boundC.setBounds(v.getMinBounds(),v.getMaxBounds()); +#endif + + vector indexedTriVec; + + //Loop over the vertices, 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 + for(size_t iX = 0; iX < nx-1; iX++) + { + int iEdgeFlags,iFlagIndex; + for(size_t iY = 0; iY < ny-1; iY++) + { + for(size_t iZ = 0; iZ < nz-1; iZ++) + { + iEdgeFlags=iFlagIndex=0; + Point3D position; + //Lower left corner of cell for dual grid + position=v.getPoint(iX,iY,iZ) + gridSpacing*0.5; + + //Find which vertices are inside of the surface and which are outside + for(int iVertexTest = 0; iVertexTest < 8; iVertexTest++) + { + float f; + f=v.getData(iX+VERTEX_OFFSET[iVertexTest][0], + iY+VERTEX_OFFSET[iVertexTest][1], + iZ+VERTEX_OFFSET[iVertexTest][2]); + + //Compute position in triangle and edge connection + //tables + if(f <= isoValue) + iFlagIndex |= 1< > edgeTriMap; +#pragma omp parallel for + for(size_t ui=0;ui >::iterator it; + it = edgeTriMap.find((indexedTriVec[ui].p[uj] >>2 ) << 2); + if(it == edgeTriMap.end()) + { + + list seedList; + seedList.push_back(ui); +#pragma omp critical + edgeTriMap.insert( + make_pair((indexedTriVec[ui].p[uj] >>2 ) << 2,seedList)); + + } + else + { + it->second.push_back(ui); + } + } + + } + + + //Generate the position points for each edge + map pointMap; + for(map >::iterator it=edgeTriMap.begin(); + it!=edgeTriMap.end(); ++it) + { + Point3D low,high,voxelFrameIntersection; + float lowF,highF; + + if(pointMap.find((it->first>>2)<<2) != pointMap.end()) + continue; + + //Low/high sides of edge's scalar values + v.getEdgeEndApproxVals(it->first,lowF,highF); + + + //Get the edge's low and high end node positions + v.getEdgeEnds((it->first>>2)<<2,low,high); + + //OK, now we have that, lets use the values to "lever" the + //solution point note node locations for isosurface + if(fabs(highF-lowF) < sqrt(std::numeric_limits::epsilon())) + { + //Prevent divide by zero + voxelFrameIntersection=(low+high)*0.5; + } + else + { + //interpolate + float alpha; + alpha= (isoValue- lowF) / (highF- lowF); + voxelFrameIntersection=low + (high-low)*alpha; + } + + + pointMap.insert(make_pair((it->first>>2)<<2,voxelFrameIntersection)); + } + + + tVec.resize(indexedTriVec.size()); + vector popTris; + //Set all triangle vertices + #pragma omp parallel for + for(size_t ui=0;ui>2)<<2); + + if(tVec[ui].isDegenerate()) + { +#pragma omp critical + popTris.push_back(ui); + } + } + + + //Remove any degenerate triangles from both indexed and real maps + removeElements(popTris,tVec); + removeElements(popTris,indexedTriVec); + + if(tVec.empty()) + return; + + //set all triangle edge normals by inverse face area weighting. + // The idea is that big triangles don't affect the normal at the point + // as they are quite delocalised. Little triangles affect it more. + // This is entirely empirical + // ---- + + vector origNormal; + origNormal.resize(indexedTriVec.size()); + #pragma omp parallel for + for(size_t ui=0;ui::iterator it=pointMap.begin(); + it!=pointMap.end();++it) + it->second=Point3D(0,0,0); + + //Construct the shared normals + float smallNum=sqrt(std::numeric_limits::epsilon()); + for(size_t ui=0;ui smallNum) + { + for(int uj=0;uj<3;uj++) + pointMap.at((indexedTriVec[ui].p[uj]>>2) <<2)+=origNormal[ui]*weight; + } + } + + + //re-normalise normals + for(map::iterator it=pointMap.begin(); + it!=pointMap.end();++it) + { + if(it->second.sqrMag() > smallNum) + it->second.normalise(); + else + it->second=Point3D(0,0,1); + } + + //assign these normals to the vertices of each triangle + #pragma omp parallel for + for(size_t ui=0;ui>2)<<2); + } + // -- + + // ---- + + + //TODO: We could use something like triStripper + // to optimise this, rather than just build the raw triangles + // http://users.telenet.be/tfautre/softdev/tristripper/ + +} diff -Nru 3depict-0.0.12/src/gl/isoSurface.h 3depict-0.0.13/src/gl/isoSurface.h --- 3depict-0.0.12/src/gl/isoSurface.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/isoSurface.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * isoSurface.h - Marching cubes implementation + * 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 . + */ + + +#ifndef ISOSURFACE_H +#define ISOSURFACE_H + +#include "common/voxels.h" + +class TriangleWithVertexNorm +{ + public: + Point3D p[3]; + Point3D normal[3]; + + void getCentroid(Point3D &p) const; + void computeACWNormal(Point3D &p) const; + void safeComputeACWNormal(Point3D &p) const; + float computeArea() const; + bool isDegenerate() const; +}; + +struct TriangleWithIndexedVertices +{ + size_t p[3]; +}; + + +//Perform marching cube algorithm +void marchingCubes(const Voxels &v,float isoValue, + std::vector &tVec); + + +#endif diff -Nru 3depict-0.0.12/src/gl/scene.cpp 3depict-0.0.13/src/gl/scene.cpp --- 3depict-0.0.12/src/gl/scene.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/scene.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,1040 @@ +/* + * scene.cpp - OpenGL 3D static scene implementation + * 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 . +*/ + +#include "scene.h" + + + +using std::vector; + +Scene::Scene() : tempCam(0), activeCam(0), cameraSet(false), outWinAspect(1.0f), r(0.0f), g(0.0f), b(0.0f) +{ + lastHovered=lastSelected=(unsigned int)(-1); + lockInteract=false; + hoverMode=selectionMode=false; + viewRestrict=false; + useAlpha=true; + useLighting=true; + useEffects=false; + showAxis=true; + + //default to black + rBack=gBack=bBack=0.0f; + +} + +Scene::~Scene() +{ + clearAll(); +} + +unsigned int Scene::initDraw() +{ + glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT); + + if(useAlpha) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + + glDisable(GL_LIGHTING); + //Set up the scene lights + //== + //Set up default lighting + const float light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; + const float light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; + const float light_specular[] = { 0.0, 0.0, 0.0, 0.0 }; + float light_position[] = { 1.0, 1.0, 1.0, 0.0 }; + glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); + glLightfv(GL_LIGHT0, GL_POSITION, light_position); + + + + + glDisable(GL_LIGHTING); + //== + + //Use the active if set + if(cameraSet) + { + if(!boundCube.isValid()) + computeSceneLimits(); + + } + + + + //Let the effects objects know about the scene + Effect::setBoundingCube(boundCube); + + unsigned int passes=1; + + if(useEffects) + { + for(unsigned int ui=0;uinumPassesNeeded()); + } + + return passes; +} + +void Scene::updateCam(const Camera *camToUse) const +{ + Point3D lightNormal; + + + glLoadIdentity(); + //If viewport restriction is on, inform camera to + //shrink viewport to specified region + if(viewRestrict) + { + camToUse->apply(outWinAspect,boundCube,true, + viewRestrictStart[0],viewRestrictEnd[0], + viewRestrictStart[1],viewRestrictEnd[1]); + } + else + camToUse->apply(outWinAspect,boundCube); + + lightNormal=camToUse->getViewDirection(); + glNormal3f(lightNormal[0],lightNormal[1],lightNormal[2]); + +} + +void Scene::draw() +{ + + glPushMatrix(); + + + Camera *camToUse; + if(tempCam) + camToUse=tempCam; + else + { + ASSERT(activeCam < cameras.size()); + camToUse=cameras[activeCam]; + } + //Inform text about current camera, so it can billboard if needed + DrawableObj::setCurCamera(camToUse); + Effect::setCurCam(camToUse); + + + bool lightsOn=false; + unsigned int numberTotalPasses; + numberTotalPasses=initDraw(); + + unsigned int passNumber=0; + + if(cameraSet) + updateCam(camToUse); + + + + bool needCamUpdate=false; + while(passNumber < numberTotalPasses) + { + + if(useEffects) + { + for(unsigned int ui=0;uienable(passNumber); + needCamUpdate|=effects[ui]->needCamUpdate(); + } + + if(cameraSet && needCamUpdate) + { + glLoadIdentity(); + updateCam(camToUse); + } + } + + + if(showAxis) + { + if(useLighting) + glEnable(GL_LIGHTING); + DrawAxis a; + a.setStyle(AXIS_IN_SPACE); + a.setSize(boundCube.getLargestDim()); + a.setPosition(boundCube.getCentroid()); + + a.draw(); + if(useLighting) + glDisable(GL_LIGHTING); + } + + + //First sub-pass with opaque objects + //----------- + //Draw the referenced objects + drawObjectVector(refObjects,lightsOn,true); + //Draw normal objects + drawObjectVector(objects,lightsOn,true); + //----------- + + //Second pass with transparent objects + //----------- + //Draw the referenced objects + drawObjectVector(refObjects,lightsOn,false); + //Draw normal objects + drawObjectVector(objects,lightsOn,false); + //----------- + + + glFlush(); + passNumber++; + } + + + //Disable effects + if(useEffects) + { + //Disable them in reverse order to simulate a stack-type + //behaviour. + for(unsigned int ui=effects.size();ui!=0;) + { + ui--; + effects[ui]->disable(); + } + } + + + glPopMatrix(); + + //Now draw 2D overlays + if(!lockInteract&& lastHovered != (unsigned int)(-1) ) + drawHoverOverlay(); + drawOverlays(); + +} + +void Scene::drawObjectVector(const vector &drawObjs, bool &lightsOn, bool drawOpaques) const +{ + for(unsigned int ui=0; uineedsDepthSorting() == drawOpaques) + continue; + + //overlays need to be drawn later + if(drawObjs[ui]->isOverlay()) + continue; + + if(useLighting) + { + if(!drawObjs[ui]->wantsLight && lightsOn ) + { + //Object prefers doing its thing in the dark + glDisable(GL_LIGHTING); + lightsOn=false; + } + else if (drawObjs[ui]->wantsLight && !lightsOn) + { + glEnable(GL_LIGHTING); + lightsOn=true; + } + } + + //If we are in selection mode, draw the bounding box + //if the object is selected. + if(ui == lastSelected && selectionMode) + { + //May be required for selection box drawing + BoundCube bObject; + DrawRectPrism p; + //Get the bounding box for the object & draw it + drawObjs[ui]->getBoundingBox(bObject); + p.setAxisAligned(bObject); + p.setColour(0,0.2,1,0.5); //blue-greenish + if(lightsOn) + glDisable(GL_LIGHTING); + p.draw(); + if(lightsOn) + glEnable(GL_LIGHTING); + + } + + drawObjs[ui]->draw(); + } +} + +void Scene::drawOverlays() const +{ + + //Custom projection matrix + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_LIGHTING); + //Set the opengl camera state back into modelview mode + if(viewRestrict) + { + + //FIXME: How does the aspect ratio fit in here? + gluOrtho2D(viewRestrictStart[0], + viewRestrictEnd[0], + viewRestrictStart[0], + viewRestrictStart[1]); + } + else + gluOrtho2D(0, outWinAspect, 1.0, 0); + + + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + + + for(unsigned int ui=0;uiisOverlay()) + refObjects[ui]->draw(); + } + + for(unsigned int ui=0;uiisOverlay()) + objects[ui]->draw(); + } + + + glEnable(GL_DEPTH_TEST); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); +} + +void Scene::drawHoverOverlay() +{ + + glEnable(GL_ALPHA_TEST); + glDisable(GL_DEPTH_TEST); + //Search for a binding + bool haveBinding; + haveBinding=false; + + //Prevent transparent areas from interacting + //with the depth buffer + glAlphaFunc(GL_GREATER,0.01f); + + vector binder; + for(unsigned int uj=0;ujgetAvailBindings(objects[lastHovered],binder)) + { + haveBinding=true; + break; + } + } + + + if(haveBinding) + { + glPushAttrib(GL_LIGHTING); + glDisable(GL_LIGHTING); + + //Now draw some hints for the binding itself as a 2D overlay + // + //Draw the action type (translation, rotation etc) + //and the button it is bound to + DrawTexturedQuadOverlay binderIcons,mouseIcons,keyIcons; + + + 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; + for(unsigned int ui=0;uigetInteractionMode()) + { + case BIND_MODE_FLOAT_SCALE: + case BIND_MODE_FLOAT_TRANSLATE: + case BIND_MODE_POINT3D_SCALE: + foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_ENLARGE]); + break; + case BIND_MODE_POINT3D_TRANSLATE: + foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_TRANSLATE]); + break; + case BIND_MODE_POINT3D_ROTATE: + case BIND_MODE_POINT3D_ROTATE_LOCK: + foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_ROTATE]); + default: + break; + } + + //Draw the mouse action + switch(binder[ui]->getMouseButtons()) + { + case SELECT_BUTTON_LEFT: + foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_LEFT_CLICK]); + break; + case SELECT_BUTTON_MIDDLE: + foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_MIDDLE_CLICK]); + break; + case SELECT_BUTTON_RIGHT: + foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_RIGHT_CLICK]); + break; + default: + //The flags are or'd together, so we can get other combinations + break; + } + + bool foundKeyTex; + foundKeyTex=false; + //Draw the keyboard action, if any + switch(binder[ui]->getKeyFlags()) + { + case FLAG_CMD: +#ifdef __APPLE__ + foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_COMMAND]); +#else + foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_CTRL]); +#endif + break; + case FLAG_SHIFT: + foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_SHIFT]); + break; + default: + //The flags are or'd together, so we can get other combinations + break; + } + + if(foundIconTex && foundMouseTex ) + { + const float SPACING=0.75*ICON_SIZE; + if(foundKeyTex) + { + //Make room for keyTex + binderIcons.setPos((0.93+SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum)); + keyIcons.setPos(0.93*winX,ICON_SIZE*winY*(1+(float)iconNum)); + mouseIcons.setPos((0.93-SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum)); + } + else + { + binderIcons.setPos(0.95*winX,ICON_SIZE*winY*(1+(float)iconNum)); + mouseIcons.setPos(0.90*winX,ICON_SIZE*winY*(1+(float)iconNum)); + } + + binderIcons.draw(); + mouseIcons.draw(); + + if(foundKeyTex) + keyIcons.draw(); + + iconNum++; + } + + } + + glPopAttrib(); + + } + + + glDisable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); +} + + +void Scene::commitTempCam() +{ + ASSERT(tempCam); + std::swap(cameras[activeCam], tempCam); + delete tempCam; + tempCam=0; +} + +void Scene::discardTempCam() +{ + delete tempCam; + tempCam=0; +} + +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(); + else + *tempCam=*cameras[activeCam]; +} + +void Scene::addDrawable(DrawableObj const *obj ) +{ + objects.push_back(obj); + BoundCube bc; + obj->getBoundingBox(bc); + + if(bc.isValid()) + boundCube.expand(bc); +} + +void Scene::addRefDrawable(const DrawableObj *obj) +{ + refObjects.push_back(obj); + BoundCube bc; + obj->getBoundingBox(bc); + + ASSERT(bc.isValid()); + boundCube.expand(bc); +} + +void Scene::clearAll() +{ + //Invalidate the bounding cube + boundCube.setInverseLimits(); + + clearObjs(); + clearRefObjs(); + clearBindings(); + clearCams(); +} + +void Scene::clearObjs() +{ + for(unsigned int ui=0; uiensureVisible(boundCube,direction); +} + +void Scene::computeSceneLimits() +{ + boundCube.setInverseLimits(); + + BoundCube b; + for(unsigned int ui=0; uigetBoundingBox(b); + + if(b.isValid()) + boundCube.expand(b); + } + + for(unsigned int ui=0; uigetBoundingBox(b); + + if(b.isValid()) + boundCube.expand(b); + } + + + if(!boundCube.isValid()) + { + //He's going to spend the rest of his life + //in a one by one unit box. + + //If there are no objects, then set the bounds + //to 1x1x1, centered around the origin + boundCube.setBounds(-0.5,-0.5,-0.5, + 0.5,0.5,0.5); + } + //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()); + + + //The scene bounds should be no less than 0.1 units + BoundCube unitCube; + Point3D centre; + + centre=boundCube.getCentroid(); + + unitCube.setBounds(centre+Point3D(0.05,0.05,0.05), + centre-Point3D(0.05,0.05,0.05)); + boundCube.expand(unitCube); +} + +Camera *Scene::getActiveCam() +{ + ASSERT(cameras.size()); + return cameras[activeCam]; +} + +Camera *Scene::getTempCam() +{ + ASSERT(tempCam); + 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 > &idVec) const +{ + std::vector ids; + camIDs.getIds(ids); + + idVec.resize(ids.size()); + for(unsigned int ui=0;uigetUserString()); + } +} + +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. +unsigned int Scene::glSelect(bool storeSelected) +{ + ASSERT(!lockInteract); + + glClear( GL_DEPTH_BUFFER_BIT ); + //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 + GLuint *selectionBuffer = new GLuint[512]; + glSelectBuffer(512, selectionBuffer); + glRenderMode(GL_SELECT); + glInitNames(); + + if(!boundCube.isValid()) + computeSceneLimits(); + + glPushMatrix(); + //Apply the camera, but do NOT load the identity matrix, as + //we have set the pick matrix + cameras[activeCam]->apply(outWinAspect,boundCube,false); + + //Set up the objects. Only NON DISPLAYLIST items can be selected. + for(unsigned int ui=0; uicanSelect) + objects[ui]->draw(); + glPopName(); + } + + //OpengGL Faq: + //The number of hit records is returned by the call to + //glRenderMode(GL_RENDER). Each hit record contains the following + //information stored as unsigned ints: + // + // * Number of names in the name stack for this hit record + // * Minimum depth value of primitives (range 0 to 2^32-1) + // * Maximum depth value of primitives (range 0 to 2^32-1) + // * Name stack contents (one name for each unsigned int). + // + //You can use the minimum and maximum Z values with the device + //coordinate X and Y if known (perhaps from a mouse click) + //to determine an object coordinate location of the picked + //primitive. You can scale the Z values to the range 0.0 to 1.0, + //for example, and use them in a call to gluUnProject(). + glFlush(); + GLint hits = glRenderMode(GL_RENDER); + + //The hit query records are stored in an odd manner + //as the name stack is returned with it. This depends + //upon how you have constructed your name stack during drawing + //(clearly). I didn't bother fully understanding this, as it does + //what I want. + GLuint *ptr = selectionBuffer; + GLuint *closestNames = 0; + GLuint minZ = 0xffffffff; + GLuint numClosestNames = 0; + for ( int i=0; itype()) + { + case CAM_LOOKAT: + ((CameraLookAt *)cameras[activeCam])->recomputeUpDirection(); + break; + } +} + +void Scene::addSelectionDevices(const vector *> &d) +{ + for(unsigned int ui=0;ui > tmp; + d[ui]->getModifiedBindings(tmp); + tmp.clear(); +#endif + selectionDevices.push_back(d[ui]); + } +} + +//Values are in the range [0 1]. +void Scene::applyDevice(float startX, float startY, float curX, float curY, + unsigned int keyFlags, unsigned int mouseFlags, bool permanent) +{ + + ASSERT(!lockInteract); + if(lastSelected == (unsigned int) (-1)) + return; + + + //Object should be in object array, and be selectable + ASSERT(lastSelected < objects.size()) + ASSERT(objects[lastSelected]->canSelect); + + //Grab basis vectors. (up, fowards and + //across from camera view.) + //--- + Point3D forwardsDir,upDir; + + forwardsDir=getActiveCam()->getViewDirection(); + upDir=getActiveCam()->getUpDirection(); + + forwardsDir.normalise(); + upDir.normalise(); + Point3D acrossDir; + acrossDir=forwardsDir.crossProd(upDir); + + acrossDir.normalise(); + //--- + + //Compute the distance between the selected object's + //centroid and the camera + //--- + float depth; + BoundCube b; + objects[lastSelected]->getBoundingBox(b); + //Camera-> object vector + Camera *cam=getActiveCam(); + + Point3D camToObject; + //Get the vector to the object + camToObject = b.getCentroid() - cam->getOrigin(); + depth = camToObject.dotProd(forwardsDir); + //--- + + //Compute the width of the camera view for the object at + //the plane that intersects the object's centroid, and is + //normal to the camera direction + float viewWidth; + switch(cam->type()) + { + case CAM_LOOKAT: + viewWidth=((CameraLookAt*)cam)->getViewWidth(depth); + break; + default: + ASSERT(false); + } + + + //We have the object number, but we don't know which binding + //corresponds to this object. Search all bindings. It may be that more than one + //binding is enabled for this object + SelectionBinding *binder; + + vector activeBindings; + for(unsigned int ui=0;uigetBinding( + objects[lastSelected],mouseFlags,keyFlags,binder)) + activeBindings.push_back(binder); + } + + for(unsigned int ui=0;uicomputeWorldVectorCoeffs(mouseFlags,keyFlags, + vectorCoeffs[0],vectorCoeffs[1]); + + //Apply vector coeffs, dependant upon binding + worldVec = acrossDir*vectorCoeffs[0][0]*(curX-startX)*outWinAspect + + upDir*vectorCoeffs[0][1]*(curX-startX)*outWinAspect + + forwardsDir*vectorCoeffs[0][2]*(curX-startX)*outWinAspect + + acrossDir*vectorCoeffs[1][0]*(curY-startY) + + upDir*vectorCoeffs[1][1]*(curY-startY) + + forwardsDir*vectorCoeffs[1][2]*(curY-startY); + worldVec*=viewWidth; + + activeBindings[ui]->applyTransform(worldVec,permanent); + } + + computeSceneLimits(); + //Inform viscontrol about updates, if we have applied any + if(activeBindings.size() && permanent) + { + visControl->setUpdates(); + //If the viscontrol is in the middle of an update, + //tell it to abort. + if(visControl->isRefreshing()) + visControl->abort(); + } + +} + +unsigned int Scene::duplicateCameras(vector &cams) const +{ + cams.resize(cameras.size()); + + for(unsigned int ui=0;uiclone(); + + return activeCam; +} + +void Scene::getEffects(vector &eff) const +{ + eff.resize(effects.size()); + + for(unsigned int ui=0;ui > &bindings) const +{ + for(unsigned int ui=0;uigetModifiedBindings(bindings); +} + +void Scene::restrictView(float xS, float yS, float xFin, float yFin) +{ + viewRestrictStart[0]=xS; + viewRestrictStart[1]=yS; + + viewRestrictEnd[0]=xFin; + viewRestrictEnd[1]=yFin; + + viewRestrict=true; +} + +bool Scene::isDefaultCam() const +{ + return activeCam==0; +} + +bool Scene::camNameExists(const std::string &s) const +{ + for(unsigned int ui=0;uigetUserString() == s) + return true; + } + + return false; +} + + + +unsigned int Scene::addEffect(Effect *e) +{ + ASSERT(e); + ASSERT(effects.size() == effectIDs.size()); + effects.push_back(e); + + + return effectIDs.genId(effects.size()-1); +} + + +void Scene::removeEffect(unsigned int uniqueID) +{ + unsigned int position = effectIDs.getPos(uniqueID); + delete effects[position]; + effects.erase(effects.begin()+position); + effectIDs.killByPos(position); +} + +void Scene::clearEffects() +{ + for(size_t ui=0;ui. +*/ +#ifndef SCENE_H +#define SCENE_H + + +class Scene; + +//Custom includes +#include "../backend/viscontrol.h" + +#include "../backend/filter.h" +#include "effect.h" + +//OpenGL debugging macro +#if DEBUG +#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; \ +} +#else +#define glError() +#endif + +#ifdef DEBUG + #define glStackDepths() { \ + int gldepthdebug[3];glGetIntegerv (GL_MODELVIEW_STACK_DEPTH, gldepthdebug);\ + glGetIntegerv (GL_PROJECTION_STACK_DEPTH, gldepthdebug+1);\ + glGetIntegerv (GL_TEXTURE_STACK_DEPTH, gldepthdebug+2);\ + std::cerr << "OpenGL Stack Depths: ModelV:" << gldepthdebug[0] << " Pr: "\ + << gldepthdebug[1] << " Tex:" << gldepthdebug[2] << std::endl;} +#else + #define glStackDepths() +#endif + +//!The scene class brings together elements such as objects, lights, and cameras +//to enable scene rendering +class Scene +{ + private: + //!Viscontroller. Needed for notification of updates during selection binding + VisController *visControl; + //!Objects that will be used for drawing + std::vector objects; + + //!Objects used for drawing that will not be destroyed + std::vector refObjects; + + + //!Bindings for interactive object properties + std::vector *> selectionDevices; + + //!Various OpenGL effects + std::vector effects; + + //!Vector of camera stats + std::vector cameras; + + //!Temporary override camera + Camera *tempCam; + + //!Texture pool + TexturePool texPool; + + //!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 + float outWinAspect; + + //!Blank canvas colour + float r,g,b; + + + //!Camera id storage and handling + UniqueIDHandler camIDs; + + //!Effect ID handler + UniqueIDHandler effectIDs; + + //!Cube that holds the scene bounds + BoundCube boundCube; + + + //!True if user interaction (selection/hovering) is forbidden + bool lockInteract; + //!Tells the scene if we are in selection mode or not + bool selectionMode; + + //!Tells us if we are in hover mode (should we draw hover overlays?) + bool hoverMode; + + //!Is the camera to be restricted to only draw a particular portion of the viewport? + bool viewRestrict; + + float viewRestrictStart[2], viewRestrictEnd[2]; + + //!Last selected object from call to glSelect(). -1 if last call failed to identify an item + unsigned int lastSelected; + + //!Last hoeverd object + unsigned int lastHovered; + + //!Should alpha belnding be used? + bool useAlpha; + //!Should lighting calculations be performed? + bool useLighting; + //!Should we be using effects? + bool useEffects; + + //!Should the world axis be drawn? + bool showAxis; + + //!Background colour + float rBack,gBack,bBack; + + + ///!Draw the hover overlays + void drawHoverOverlay(); + + //!Draw the normal overlays + void drawOverlays() const; + + //!initialise the drawing window + unsigned int initDraw(); + + void updateCam(const Camera *camToUse) const; + + + //!Draw a specified vector of objects + void drawObjectVector(const std::vector &objects, bool &lightsOn, bool drawOpaques=true) const; + + + public: + //!Constructor + Scene(); + //!Destructor + virtual ~Scene(); + + //!Set the vis control + void setViscontrol(VisController *v) { visControl=v;}; + //!Draw the objects in the active window. May adjust cameras and compute bounding as needed. + void draw(); + + + //!clear rendering vectors + void clearAll(); + //!Clear drawing objects vector + void clearObjs(); + //! Clear the reference object vector + 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 + float getAspect() const { return outWinAspect;}; + + //!Add a drawable object + /*!Pointer must be set to a valid (allocated) object. + *!Scene will delete upon call to clearAll, clearObjs or + *!upon destruction + */ + 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 + * 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); + + //!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); + + + //! set the active camera + void setActiveCam(unsigned int uniqueCamID); + + //! get the active camera + Camera *getActiveCam() ; + + //! get the active camera's location + Point3D getActiveCamLoc() const; + + //!Construct (or refresh) a temporary camera + /*! this temporary camera is discarded with + * either killTempCam or reset to the active + * camera with another call to setTempCam(). + * The temporary camera overrides the existing camera setup + */ + void setTempCam(); + + //!Return pointer to active camera. Must init a temporary camera first! (use setTempCam) + Camera *getTempCam() ; + + //!Make the temp camera permanent. + void commitTempCam(); + + //!Discard the temporary camera + void discardTempCam(); + + //!Are we using a temporary camera? + 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(); } ; + + //!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 > &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(); + + //!perform an openGL selection rendering pass. Return + //closest object in depth buffer under position + //if nothing, returns -1 + unsigned int glSelect(bool storeSelection=true); + + //!Add selection devices to the scene. + void addSelectionDevices(const std::vector *> &d); + + //!Clear the current selection devices + void clearDevices(); + + //!Apply the device given the following start and end + //viewport coordinates. + void applyDevice(float startX, float startY, + float curX, float curY,unsigned int keyFlags, + unsigned int mouseflags,bool permanent=true); + + // is interaction currently locked? + bool isInteractionLocked() const { return lockInteract;} + //!Prevent user interactoin + void lockInteraction(bool amLocking=true) { lockInteract=amLocking;}; + //!Set selection mode true=select on, false=select off. + //All this does internally is modify how drawing works. + void setSelectionMode(bool selMode) { selectionMode=selMode;}; + + //!Set the hover mode to control drawing + void setHoverMode(bool hMode) { hoverMode=hMode;}; + + //!Return the last object over whichthe cursor was hovered + void setLastHover(unsigned int hover) { lastHovered=hover;}; + //!Get the last selected object from call to glSelect() + unsigned int getLastSelected() const { return lastSelected;}; + + //!Return the last object over whichthe cursor was hovered + unsigned int getLastHover() const { return lastHovered;}; + //!Duplicates the internal camera vector. return value is active camera + //in returned vector + unsigned int duplicateCameras(std::vector &cams) const; + //!Get a copy of the effects pointers + void getEffects(std::vector &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 > &bindings) const; + + //!Restrict the openGL drawing view when using the camera + void restrictView(float xS,float yS, float xFin, float yFin); + //!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;}; + + //!Set whether to enable lighting + void setLighting(bool newLight) { useLighting=newLight;}; + + //!Set whether to enable the XYZ world axes + void setWorldAxisVisible(bool newAxis) { showAxis=newAxis;}; + //!Get whether the XYZ world axes are enabled + bool getWorldAxisVisible() const { return showAxis;}; + + //!Set window size + void setWinSize(unsigned int x, unsigned int y) {winX=x;winY=y;} + + //!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;}; + + void getBackgroundColour(float &newR,float &newG,float &newB) const { newR=rBack;newG=gBack;newB=bBack;}; + + //!Computes the bounding box for the scene. + //this is locked to a minimum of 0.1 unit box around the origin. + //this avoids nasty camera situations, where lookat cameras are sitting + //on their targets, and don't know where to look. + void computeSceneLimits(); + + //!Set whether to use effects or not + void setEffects(bool enable) {useEffects=enable;} + + //!Add an effect + unsigned int addEffect(Effect *e); + //!Remove a given effect + void removeEffect(unsigned int uniqueEffectID); + + //!Clear effects vector + void clearEffects(); +}; + +#endif diff -Nru 3depict-0.0.12/src/gl/select.cpp 3depict-0.0.13/src/gl/select.cpp --- 3depict-0.0.12/src/gl/select.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/select.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,225 @@ +/* + * select.cpp - filter selection binding implementation + * 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 . +*/ + +#include "select.h" + + +SelectionBinding::SelectionBinding() +{ + obj=0; + valModified=false; + bindingId=drawActionId=0; +} + +void SelectionBinding::setBinding(unsigned int button, unsigned int modifierFlags,unsigned int actionId, + unsigned int bindID, float initValue, DrawableObj * d) +{ + //Cache the current value + cachedValFloat = initValue; + drawActionId=actionId; + //Grab the object identifier itself + obj=d; + + bindKeys=modifierFlags; + bindButtons=button; + bindingId=bindID; + + fMin=-std::numeric_limits::max(); + fMax=std::numeric_limits::max(); + + dataType=BIND_TYPE_FLOAT; +} + +void SelectionBinding::setBinding(unsigned int button, unsigned int modifierFlags, unsigned int actionId, + unsigned int bindID, const Point3D &initValue, DrawableObj *d) +{ + + bindingId=bindID; + drawActionId=actionId; + obj=d; + + + bindKeys=modifierFlags; + bindButtons=button; + + cachedValPoint3D = initValue; + + dataType=BIND_TYPE_POINT3D; +} + +void SelectionBinding::setInteractionMode(unsigned int newBindMode) +{ + //Rotation cannot have associated key flags. These are reserved + //for changing the orientation of the rotation + bindMode=newBindMode; +} + +void SelectionBinding::setFloatLimits(float newMin,float newMax) +{ + fMin=newMin; + fMax=newMax; +} + +void SelectionBinding::applyTransform(const Point3D &worldVec, bool permanent) +{ + vector scalars; + vector vecs; + float fTmp; + switch(bindMode) + { + case BIND_MODE_FLOAT_SCALE: + { + //Compute the new scalar as the magnitude of the difference vector + fTmp = sqrtf(worldVec.sqrMag()); + fTmp = std::max(fMin,fTmp); + fTmp = std::min(fMax,fTmp); + + scalars.push_back(fTmp); + break; + } + case BIND_MODE_FLOAT_TRANSLATE: + { + //Compute the new scalar as an offset by the mag of the scalar + fTmp =0.5*cachedValFloat+sqrtf(worldVec.sqrMag()); + fTmp = std::max(fMin,fTmp); + fTmp = std::min(fMax,fTmp); + + scalars.push_back(fTmp); + cachedValFloat=fTmp; + break; + } + case BIND_MODE_POINT3D_TRANSLATE: + case BIND_MODE_POINT3D_SCALE: + { + vecs.push_back(cachedValPoint3D+worldVec); + + //Only apply if this is a permanent change, + //otherwise we will get an integrating effect + if(permanent) + cachedValPoint3D+=worldVec; + break; + } + case BIND_MODE_POINT3D_ROTATE: + { + if(worldVec.sqrMag() > sqrtf(std::numeric_limits::epsilon())) + { + vecs.push_back(worldVec); + cachedValPoint3D = worldVec; + } + + break; + } + case BIND_MODE_POINT3D_ROTATE_LOCK: + { + if(worldVec.sqrMag() > sqrtf(std::numeric_limits::epsilon())) + { + //Renormalise the vector back to the same scale as the cached value + vecs.push_back(worldVec*sqrtf(cachedValPoint3D.sqrMag()/worldVec.sqrMag())); + if(permanent) + cachedValPoint3D=vecs.back(); + } + + break; + } + default: + ASSERT(false); + } + + if(vecs.size() || scalars.size()) + { + //Force a recomputation of the internal parameters + //for the drawable object. Whatever they are. + obj->recomputeParams(vecs,scalars,drawActionId); + + valModified=true; + } +} + +void SelectionBinding::computeWorldVectorCoeffs(unsigned int buttonFlags, + unsigned int modifierFlags,Point3D &xCoeffs,Point3D &yCoeffs) const + +{ + switch(bindMode) + { + case BIND_MODE_FLOAT_TRANSLATE: + case BIND_MODE_FLOAT_SCALE: + //It is of no concern. we are going to pass this to sqrmag + //anyway during applyTransform. + xCoeffs=Point3D(1,0,0); + yCoeffs=Point3D(0,1,0); + break; + case BIND_MODE_POINT3D_TRANSLATE: + case BIND_MODE_POINT3D_SCALE: + case BIND_MODE_POINT3D_ROTATE: + case BIND_MODE_POINT3D_ROTATE_LOCK: + { + if(modifierFlags == FLAG_CMD && bindKeys!=FLAG_CMD) + { + //Mouse movement in x sends you forwards + //y movement sends you up down (wrt camera) + xCoeffs=Point3D(0,0,1); + yCoeffs=Point3D(0,1,0); + } + else if(modifierFlags == FLAG_SHIFT && bindKeys != FLAG_SHIFT) + { + //Mouse movement in x sends you across + //y movement sends you forwards (wrt camera) + xCoeffs=Point3D(1,0,0); + yCoeffs=Point3D(0,0,1); + } + else + { + //For example: FLAG_NONE + //IN plane with camera. + xCoeffs=Point3D(1,0,0); + yCoeffs=Point3D(0,1,0); + } + break; + } + default: + ASSERT(false); + } +} + + +void SelectionBinding::getValue(float &f) const +{ + f=cachedValFloat; +} + +void SelectionBinding::getValue(Point3D &f) const +{ + f=cachedValPoint3D; +} + +bool SelectionBinding::matchesDrawable(const DrawableObj *d, + unsigned int mouseFlags, unsigned int keyFlags) const +{ + //Object and mouseflags must match. keyflags must be nonzero after masking with bindKeys + if(bindKeys) + return (obj == d && mouseFlags == bindButtons && (keyFlags &bindKeys) == bindKeys); + else + return (obj == d && mouseFlags == bindButtons); +}; + + +bool SelectionBinding::matchesDrawable(const DrawableObj *d) const +{ + return (obj == d); +} + diff -Nru 3depict-0.0.12/src/gl/select.h 3depict-0.0.13/src/gl/select.h --- 3depict-0.0.12/src/gl/select.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/select.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,260 @@ +/* + * select,h - Opengl interaction 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 . +*/ + + +#ifndef SELECT_H +#define SELECT_H + +#include "drawables.h" + + +//Mouse button flags +enum +{ + SELECT_BUTTON_LEFT=1, + SELECT_BUTTON_MIDDLE=2, + SELECT_BUTTON_RIGHT=4 +}; + +//!Keyboard keydown flags +enum +{ + FLAG_NONE=0, + FLAG_CMD=1, //control (non-mac) or "clover" key (mac) + FLAG_SHIFT=2, //Left or right shift key. +}; + +//!Allowable binding modes +enum +{ + BIND_MODE_FLOAT_SCALE, //Object scaling only (fp value) + BIND_MODE_FLOAT_TRANSLATE, //Floating point translation + BIND_MODE_POINT3D_TRANSLATE, //3D point translation in 2D plane perpendicular to camera + BIND_MODE_POINT3D_SCALE, //3D point translation in 2D plane perpendicular to camera; but indicate to user that this performs some kind of scaling operation + BIND_MODE_POINT3D_ROTATE, //3D rotation in 2D plane perpendicular to camera + BIND_MODE_POINT3D_ROTATE_LOCK, // 3D rotation in 2D plane perpendicular to camera, but with locked magnitude +}; + +//!Bindable data types (data types that SelectionBinding can work with) +enum +{ + BIND_TYPE_FLOAT, + BIND_TYPE_POINT3D +}; + +//!This class is used to pool together a graphical representation (via the drawable), of +//an object with its internal data structural representation. This allows the user +//to grapple with the drawable representation and feed this into the scene. +//This class binds ONE drawable object to a set of actions based upon key and button combinations. +class SelectionBinding +{ + private: + //Pointer to drawable that generates selection events. + //calls recomputeParams function + DrawableObj *obj; + + //ID number for parent to know which of its bindings this is + unsigned int bindingId; + + //ID number to bind the action for the drawable object + unsigned int drawActionId; + + //Binding type + unsigned int dataType; + + + //Binding button (ORed together) + unsigned int bindButtons; + + //Binding key (ORed together) + unsigned int bindKeys; + + //Binding mode + unsigned int bindMode; + + //Original value of data type (probably more mem efficient ot use a void*...) + float cachedValFloat; + Point3D cachedValPoint3D; + + bool valModified; + + //limits in floating point + float fMin,fMax; + + public: + SelectionBinding(); + + //!Returns true if this binding will be activated given the current flags + bool isActive(unsigned int button,unsigned int curModifierFlags); + + //!Set the binding for a float DO NOT CACHE THE DRAWABLEOBJ-> THAT IS BAD + void setBinding(unsigned int buttonFlags, unsigned int modifierFlags, + unsigned int drawActionId, unsigned int bindingID, + float initVal, DrawableObj *d); + + //!Set the binding for a Point3D. DO NOT CACHE THE DRAWABLEOBJ-> THAT IS BAD + void setBinding(unsigned int buttonFlags, unsigned int modifierFlags, + unsigned int drawActionId,unsigned int bindingID, + const Point3D &initVal, DrawableObj *d); + + //!Set the interaction method. (example translate, scale, rotate etc) + void setInteractionMode(unsigned int bindMode); + + //!Get the interaction mode + unsigned int getInteractionMode() const { return bindMode;}; + + //!Get the mouse button + unsigned int getMouseButtons() const { return bindButtons;}; + + //!Get the mouse button + unsigned int getKeyFlags() const { return bindKeys;}; + + //!Set the limits for a floating point data type + void setFloatLimits(float min,float max); + + //!Is this binding for the following object? + bool matchesDrawable(const DrawableObj *d, + unsigned int mouseFlags, unsigned int keyFlags) const; + //!Is this binding for the following object? + bool matchesDrawable(const DrawableObj *d) const; + + //!Apply the user ineraction specified. set permanent=true to + //make it such that this is not undone during the next transform, + //or call to reset() + //worldvec is the vector along which to transform the object (subject to + //interpretation by the "interaction mode" (bindmode) setting) + void applyTransform(const Point3D &worldVec,bool permanent=false); + + + //!Map the screen coords world coords, given the mouse and keyflags + //coeffs are 0: right 1: forwards 2: up ( right hand rule) + void computeWorldVectorCoeffs(unsigned int buttonFlags, + unsigned int modifierFlags,Point3D &xCoeffs,Point3D &yCoeffs) const; + + //!Retrieve the current value from the drawable representation + void getValue(float &f) const; + //!Retreive the current value from the drawable representation + void getValue(Point3D &p) const; + + unsigned int getID() const { return bindingId;}; + + //!True if the binding has modified the data + bool modified() const {return valModified;}; +}; + +template class SelectionDevice +{ + private: + std::vector bindingVec; + const T *target; +public: + //!Create a new selection device + SelectionDevice(const T *p); + + //!Copy constructor (not implemented) + SelectionDevice(const SelectionDevice ©Src); + + //!Bind a floating point type between the graphical and internal reps. + //note that it is a BUG to attempt to bind any object that uses a + //display list in its internal representation. + void addBinding(SelectionBinding b); + + bool getBinding(const DrawableObj *d, unsigned int mouseFlags, + unsigned int keyFlags, SelectionBinding* &b); + + bool getAvailBindings(const DrawableObj *d, vector &b) const; + void getModifiedBindings(vector > &bindings); +}; + +template +SelectionDevice::SelectionDevice(const T *p) : target(p) +{ +} + +template +void SelectionDevice::addBinding(SelectionBinding b) +{ + bindingVec.push_back(b); +} + +template +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;uigetKeyFlags(); + 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 +void SelectionDevice::getModifiedBindings(vector > &bindings) +{ + ASSERT(target); + for(unsigned int ui=0;ui +bool SelectionDevice::getAvailBindings(const DrawableObj *d,vector &b) const +{ + ASSERT(b.empty()); + for(unsigned int ui=0;ui. +*/ + +#include "textures.h" + +#include "pngread.h" + +#include "wxcommon.h" + +const char *TEST_OVERLAY_PNG[] = { + "textures/Left_clicked_mouse.png", + "textures/Left-Right-arrow.png", + "textures/Right_clicked_mouse.png", + "textures/rotateArrow.png", + "textures/middle_clicked_mouse.png", + "textures/scroll_wheel_mouse.png", + "textures/enlarge.png", + + "textures/keyboard-ctrl.png", + "textures/keyboard-command.png", + "textures/keyboard-alt.png", + "textures/keyboard-tab.png", + "textures/keyboard-shift.png", + }; + +TexturePool::~TexturePool() +{ + closeAll(); +} + +bool TexturePool::openTexture(const char *texName,unsigned int &texID, unsigned int &uniqID) +{ + std::string texPath; + + texPath = locateDataFile(texName); + + //See if we already have this texture (use abs. name) + for(unsigned int ui=0;uiwidth = width; + dest->height = height; + dest->data = new unsigned char[4*width*height]; + for (y=0; ydata[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 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)); +} diff -Nru 3depict-0.0.12/src/gl/textures.h 3depict-0.0.13/src/gl/textures.h --- 3depict-0.0.12/src/gl/textures.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gl/textures.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * textures.h - Texture control classes 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 . +*/ + + +#ifndef TEXTURES_H +#define TEXTURES_H + +#include "common/basics.h" + +#ifdef __APPLE__ +#include +#include +#else +#include +#include +#endif + + + +//Named Textures +enum +{ + TEXTURE_LEFT_CLICK=0, + TEXTURE_TRANSLATE, + TEXTURE_RIGHT_CLICK, + TEXTURE_ROTATE, + TEXTURE_MIDDLE_CLICK, + TEXTURE_SCROLL_WHEEL, + TEXTURE_ENLARGE, + + TEXTURE_CTRL, + TEXTURE_COMMAND, + TEXTURE_ALT, + TEXTURE_TAB, + TEXTURE_SHIFT +}; + +//Paths to named textures +extern const char *TEST_OVERLAY_PNG[]; + +typedef struct { +GLuint name; /* OpenGL name assigned by the thingy */ +GLuint width; +GLuint height; +unsigned char *data; +} texture; + +class TexturePool +{ +private: + UniqueIDHandler texUniqIds; + std::vector > openTextures; + + public: + TexturePool() {} ; + ~TexturePool(); + //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); + + //Close the specified texture, using its unique ID + void closeTexture(unsigned int texID); + + //Close all textures + void closeAll(); + +}; + +//!Type can be GL_TEXTURE_1D or GL_TEXTURE_2D +int pngTexture(texture* dest, const char* filename, GLenum type); +int pngTexture2D(texture*, const char*); +int pngTexture1D(texture*, const char*); + + +#endif diff -Nru 3depict-0.0.12/src/glPane.cpp 3depict-0.0.13/src/glPane.cpp --- 3depict-0.0.12/src/glPane.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/glPane.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1097 +0,0 @@ -/* - * glPane.cpp - OpenGL panel implementation - * Copyright (C) 2012, 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 . -*/ - - -#include -#include -#include -#include -#include -#include "wxcommon.h" - -#include "glPane.h" - - -// include OpenGL -#ifdef __WXMAC__ -#include "OpenGL/glu.h" -#include "OpenGL/gl.h" - -#else -#include -#include - -#endif - -#include "translation.h" - - -//Unclear why, but windows does not allow GL_BGR, -//needs some other define BGR_EXT (NFI), which is 0x80E0 -#if defined(WIN32) || defined(WIN64) - #define GL_BGR 0x80E0 -#endif - - -enum -{ - ID_KEYPRESS_TIMER=wxID_ANY+1, -}; - -//Double tap delay (ms), for axis reversal -const unsigned int DOUBLE_TAP_DELAY=500; - -BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas) -EVT_MOTION(BasicGLPane::mouseMoved) -EVT_ERASE_BACKGROUND(BasicGLPane::OnEraseBackground) -EVT_LEFT_DOWN(BasicGLPane::mouseDown) -EVT_LEFT_UP(BasicGLPane::mouseReleased) -EVT_MIDDLE_UP(BasicGLPane::mouseReleased) -EVT_MIDDLE_DOWN(BasicGLPane::mouseDown) -EVT_RIGHT_UP(BasicGLPane::mouseReleased) -EVT_RIGHT_DOWN(BasicGLPane::mouseDown) -EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow) -EVT_SIZE(BasicGLPane::resized) -EVT_KEY_DOWN(BasicGLPane::keyPressed) -EVT_CHAR(BasicGLPane::charEvent) -EVT_KEY_UP(BasicGLPane::keyReleased) -EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved) -EVT_PAINT(BasicGLPane::render) -EVT_TIMER(ID_KEYPRESS_TIMER,BasicGLPane::OnAxisTapTimer) -END_EVENT_TABLE() - -//Controls camera pan/translate/pivot speed; Radii per pixel or distance/pixel -const float CAMERA_MOVE_RATE=0.05; - -// Controls zoom speed, in err, zoom units.. Ahem. -const float CAMERA_SCROLL_RATE=0.05; -//Zoom speed for keyboard -const float CAMERA_KEYBOARD_SCROLL_RATE=1; - -int attribList[] = {WX_GL_RGBA, - WX_GL_DEPTH_SIZE, - 16, - WX_GL_DOUBLEBUFFER, - 1, - 0,0}; - -BasicGLPane::BasicGLPane(wxWindow* parent) : -wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas"),attribList) -{ - haveCameraUpdates=false; - applyingDevice=false; - paneInitialised=false; - - keyDoubleTapTimer=new wxTimer(this,ID_KEYPRESS_TIMER); - lastKeyDoubleTap=(unsigned int)-1; - - mouseMoveFactor=mouseZoomFactor=1.0f; - dragging=false; - lastMoveShiftDown=false; - selectionMode=false; - lastKeyFlags=lastMouseFlags=0; -} - -BasicGLPane::~BasicGLPane() -{ - keyDoubleTapTimer->Stop(); - delete keyDoubleTapTimer; -} - -bool BasicGLPane::displaySupported() const -{ -#if wxCHECK_VERSION(2,9,0) - return IsDisplaySupported(attribList); -#else - ASSERT(false); - //Lets hope so. If its not, then its just going to fail anyway. - //If it is, then returning false would simply create a roadblock. - //Either way, you shouldn't get here. - return true; -#endif -} - -void BasicGLPane::setSceneInteractionAllowed(bool enabled) -{ - currentScene.lockInteraction(!enabled); -} - -unsigned int BasicGLPane::selectionTest(const wxPoint &p,bool &shouldRedraw) -{ - - if(currentScene.isInteractionLocked()) - { - shouldRedraw=false; - return -1; - } - - //TODO: Refactor. Much of this could be pushed into the scene, - //and hence out of this wx panel. - - //Push on the matrix stack - glPushMatrix(); - - GLint oldViewport[4]; - glGetIntegerv(GL_VIEWPORT, oldViewport); - //5x5px picking region. Picking is done by modifying the view - //to enlarge the selected region. - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPickMatrix(p.x, oldViewport[3]-p.y,5, 5, oldViewport); - glMatrixMode(GL_MODELVIEW); - - int lastSelected = currentScene.getLastSelected(); - int selectedObject=currentScene.glSelect(); - - //If the object selection hasn't changed, we don't need to redraw - //if it has changed, we should redraw - shouldRedraw = (lastSelected !=selectedObject); - - //Restore the previous matirx - glPopMatrix(); - - //Restore the viewport - int w, h; - GetClientSize(&w, &h); - glViewport(0, 0, (GLint) w, (GLint) h); - - return selectedObject; -} - -unsigned int BasicGLPane::hoverTest(const wxPoint &p,bool &shouldRedraw) -{ - - if(currentScene.isInteractionLocked()) - { - shouldRedraw=false; - return -1; - } - //Push on the matrix stack - glPushMatrix(); - - GLint oldViewport[4]; - glGetIntegerv(GL_VIEWPORT, oldViewport); - //5x5px picking region. Picking is done by modifying the view - //to enlarge the selected region. - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPickMatrix(p.x, oldViewport[3]-p.y,5, 5, oldViewport); - glMatrixMode(GL_MODELVIEW); - - unsigned int lastHover = currentScene.getLastHover(); - unsigned int hoverObject=currentScene.glSelect(false); - - //FIXME: Should be able to make this more efficient - shouldRedraw = lastHover!=(unsigned int)-1; - - //Set the scene's hover value - currentScene.setLastHover(hoverObject); - currentScene.setHoverMode(hoverObject != (unsigned int)-1); - - //Restore the previous matirx - glPopMatrix(); - - //Restore the viewport - int w, h; - GetClientSize(&w, &h); - glViewport(0, 0, (GLint) w, (GLint) h); - - return hoverObject; -} - -// some useful events to use -void BasicGLPane::mouseMoved(wxMouseEvent& event) -{ - if (applyingDevice) return; - enum - { - CAM_MOVE, //Movement of some kind - CAM_TRANSLATE, //translate camera - CAM_PIVOT, //Pivot around view and across directions - CAM_ROLL //Roll around view direction - }; - - - if(selectionMode ) - { - if(currentScene.isInteractionLocked()) - { - event.Skip(); - return; - } - - - wxPoint p=event.GetPosition(); - - unsigned int mouseFlags=0; - unsigned int keyFlags=0; - wxMouseState wxm = wxGetMouseState(); - - if(wxm.CmdDown()) - keyFlags|=FLAG_CMD; - if(wxm.ShiftDown()) - keyFlags|=FLAG_SHIFT; - - if(wxm.LeftDown()) - mouseFlags|= SELECT_BUTTON_LEFT; - if(wxm.RightDown()) - mouseFlags|= SELECT_BUTTON_RIGHT; - if(wxm.MiddleDown()) - mouseFlags|= SELECT_BUTTON_MIDDLE; - - //We can get a mouse move event which reports no buttons mbefore a mouse-up event, - //this occurs frequently under windows, but sometimes under GTK - if(!mouseFlags) - { - event.Skip(); - return; - } - - int w, h; - GetClientSize(&w, &h); - - - currentScene.applyDevice((float)draggingStart.x/(float)w, - (float)draggingStart.y/(float)h, - p.x/(float)w,p.y/(float)h, - keyFlags,mouseFlags, - false); - - lastMouseFlags=mouseFlags; - lastKeyFlags=keyFlags; - Refresh(); - return; - } - - if(!dragging) - { - wxPoint p=event.GetPosition(); - - //Do a hover test - bool doRedraw=false; - hoverTest(p,doRedraw); - - if(doRedraw) - Refresh(); - - return; - } - - wxPoint draggingCurrent = event.GetPosition(); - - //left-right and up-down move values - float lrMove,udMove; - - //Movement rate multiplier -- intialise to user value - float camMultRate=mouseMoveFactor; - if(event.m_shiftDown) - { - //Commit the current temp cam using the last camera rate - //and then restart the motion. - if(!lastMoveShiftDown && currentScene.haveTempCam()) - currentScene.commitTempCam(); - - camMultRate*=5.0f; - - lastMoveShiftDown=true; - - } - else - { - //Commit the current temp cam using the last camera rate - //and then restart the motion. - if(lastMoveShiftDown && currentScene.haveTempCam()) - currentScene.commitTempCam(); - - lastMoveShiftDown=false; - } - - lrMove=CAMERA_MOVE_RATE*camMultRate*(draggingCurrent.x - draggingStart.x); - udMove=CAMERA_MOVE_RATE*camMultRate*(draggingCurrent.y - draggingStart.y); - - lrMove*=2.0f*M_PI/180.0; - udMove*=2.0f*M_PI/180.0; - unsigned int camMode=0; - //Decide camera movement mode - bool translateMode; - - translateMode=event.CmdDown(); - - bool swingMode; - #if defined(WIN32) || defined(WIN64) || defined(__APPLE__) - swingMode=wxGetKeyState(WXK_ALT); - #else - swingMode=wxGetKeyState(WXK_TAB); - #endif - - if(translateMode && !swingMode) - camMode=CAM_TRANSLATE; - else if(swingMode && !translateMode) - camMode=CAM_PIVOT; - else if(swingMode && translateMode) - camMode=CAM_ROLL; - else - camMode=CAM_MOVE; - - switch(camMode) - { - case CAM_TRANSLATE: - currentScene.discardTempCam(); - currentScene.setTempCam(); - currentScene.getTempCam()->translate(lrMove,-udMove); - break; - case CAM_PIVOT: - currentScene.discardTempCam(); - currentScene.setTempCam(); - currentScene.getTempCam()->pivot(lrMove,udMove); - break; - case CAM_MOVE: - currentScene.setTempCam(); - currentScene.getTempCam()->move(lrMove,udMove); - break; - case CAM_ROLL: - currentScene.setTempCam(); - currentScene.getTempCam()->roll(atan2(udMove,lrMove)); - - break; - default: - ASSERT(false); - break; - } - - if(!event.m_leftDown) - { - dragging=false; - currentScene.commitTempCam(); - } - - haveCameraUpdates=true; - - Refresh(false); -} - -void BasicGLPane::mouseDown(wxMouseEvent& event) -{ - - wxPoint p=event.GetPosition(); - - //Do not re-trigger if dragging or doing a scene update. - //This can cause a selection test to occur whilst - //a temp cam is activated in the scene, or a binding refresh is underway, - //which is currently considered bad - if(!dragging && !applyingDevice && !selectionMode - && !currentScene.isInteractionLocked()) - { - //Check to see if the user has clicked an object in the scene - bool redraw; - selectionTest(p,redraw); - - - //If the selected object is valid, then - //we did select an object. Treat this as a seletion event - if(currentScene.getLastSelected() != (unsigned int)-1) - { - selectionMode=true; - currentScene.setSelectionMode(true); - } - else - { - //we aren't setting, it -- it shouldn't be the case - ASSERT(selectionMode==false); - - //Prevent right button from triggering camera drag - if(!event.LeftDown()) - { - event.Skip(); - return; - } - - //If not a valid selection, this is a camera drag. - dragging=true; - } - - draggingStart = event.GetPosition(); - //Set keyboard focus to self, to recieve key events - SetFocus(); - - if(redraw) - Refresh(); - } - - event.Skip(); -} - -void BasicGLPane::mouseWheelMoved(wxMouseEvent& event) -{ - const float SHIFT_MULTIPLIER=5; - - float cameraMoveRate=-(float)event.GetWheelRotation()/(float)event.GetWheelDelta(); - - cameraMoveRate*=mouseZoomFactor; - - if(event.ShiftDown()) - cameraMoveRate*=SHIFT_MULTIPLIER; - - cameraMoveRate*=CAMERA_SCROLL_RATE; - //Move by specified deltea - currentScene.getActiveCam()->forwardsDolly(cameraMoveRate); - - //if we are using a temporary camera, update that too - if(currentScene.haveTempCam()) - currentScene.getTempCam()->forwardsDolly(cameraMoveRate); - - haveCameraUpdates=true; - Refresh(); - event.Skip(); -} - -void BasicGLPane::mouseReleased(wxMouseEvent& event) -{ - if(currentScene.isInteractionLocked()) - { - event.Skip(); - return; - } - - if(selectionMode ) - { - //If user releases all buttons, then allow the up - if(!event.LeftIsDown() && - !event.RightIsDown() && !event.MiddleIsDown()) - { - wxPoint p=event.GetPosition(); - - int w, h; - GetClientSize(&w, &h); - applyingDevice=true; - - - currentScene.applyDevice((float)draggingStart.x/(float)w, - (float)draggingStart.y/(float)h, - p.x/(float)w,p.y/(float)h, - lastKeyFlags,lastMouseFlags, - true); - - applyingDevice=false; - - - selectionMode=false; - currentScene.setSelectionMode(selectionMode); - - Refresh(); - } - event.Skip(); - return; - } - - - if(currentScene.haveTempCam()) - currentScene.commitTempCam(); - currentScene.finaliseCam(); - - haveCameraUpdates=true; - dragging=false; - - Refresh(); - event.Skip(); - -} - -void BasicGLPane::rightClick(wxMouseEvent& event) -{ -} - -void BasicGLPane::mouseLeftWindow(wxMouseEvent& event) -{ - if(selectionMode) - { - wxPoint p=event.GetPosition(); - - int w, h; - GetClientSize(&w, &h); - - applyingDevice=true; - currentScene.applyDevice((float)draggingStart.x/(float)w, - (float)draggingStart.y/(float)h, - p.x/(float)w,p.y/(float)h, - lastKeyFlags,lastMouseFlags, - true); - - selectionMode=false; - currentScene.setSelectionMode(selectionMode); - Refresh(); - applyingDevice=false; - - event.Skip(); - return; - - } - - if(event.m_leftDown) - { - if(currentScene.haveTempCam()) - { - currentScene.commitTempCam(); - dragging=false; - } - } - event.Skip(); -} - -void BasicGLPane::keyPressed(wxKeyEvent& event) -{ - - switch(event.GetKeyCode()) - { - case WXK_SPACE: - { - unsigned int visibleDir; - - //Use modifier keys to alter the direction of visiblity - //First compute the part of the keymask that does not - //reflect the double tap - // needs to be control in apple as cmd-space open spotlight - unsigned int keyMask; -#ifdef __APPLE__ - #if wxCHECK_VERSION(2,9,0) - keyMask = (event.RawControlDown() ? 1 : 0); - #else - keyMask = (event.ControlDown() ? 1 : 0); - #endif -#else - keyMask = (event.CmdDown() ? 1 : 0); -#endif - keyMask |= (event.ShiftDown() ? 2 : 0); - - //Now determine if we are the same mask as last time - bool isKeyDoubleTap=(lastKeyDoubleTap==keyMask); - //double tapping allows for selection of reverse direction - keyMask |= ( isKeyDoubleTap ? 4 : 0); - - visibleDir=-1; - - //Hardwire key combo->Mapping - switch(keyMask) - { - //Space only - case 0: - visibleDir=3; - break; - //Command down +space - case 1: - visibleDir=0; - break; - //Shift +space - case 2: - visibleDir=2; - break; - //NO CASE 3 - //Double+space - case 4: - visibleDir=5; - break; - //Doublespace+Cmd - case 5: - visibleDir=4; - break; - - //Space+Double+shift - case 6: - visibleDir=1; - break; - default: - ; - } - - if(visibleDir!=(unsigned int)-1) - { - - if(isKeyDoubleTap) - { - //It was a double tap. Reset the tapping and stop the timer - lastKeyDoubleTap=(unsigned int)-1; - keyDoubleTapTimer->Stop(); - } - else - { - lastKeyDoubleTap=keyMask & (~(0x04)); - keyDoubleTapTimer->Start(DOUBLE_TAP_DELAY,wxTIMER_ONE_SHOT); - } - - - currentScene.ensureVisible(visibleDir); - parentStatusBar->SetStatusText(wxTRANS("Use shift/ctrl-space or double tap to alter reset axis")); - parentStatusBar->SetBackgroundColour(*wxCYAN) - ; - parentStatusTimer->Start(statusDelay,wxTIMER_ONE_SHOT); - Refresh(); - haveCameraUpdates=true; - } - } - break; - } - event.Skip(); -} - -void BasicGLPane::setGlClearColour(float r, float g, float b) -{ - ASSERT(r >= 0.0f && r <= 1.0f); - ASSERT(g >= 0.0f && g <= 1.0f); - ASSERT(b >= 0.0f && b <= 1.0f); - - //Let openGL know that we have changed the colour. - glClearColor( r, g, b, 0.0f); - - currentScene.setBackgroundColour(r,g,b); - - Refresh(); -} - -void BasicGLPane::keyReleased(wxKeyEvent& event) -{ - - float cameraMoveRate=CAMERA_KEYBOARD_SCROLL_RATE; - - if(event.ShiftDown()) - cameraMoveRate*=5; - - switch(event.GetKeyCode()) - { - case '-': - case WXK_NUMPAD_SUBTRACT: - case WXK_SUBTRACT: - { - //Do a backwards dolly by fixed amount - currentScene.getActiveCam()->forwardsDolly(cameraMoveRate); - if(currentScene.haveTempCam()) - currentScene.getTempCam()->forwardsDolly(cameraMoveRate); - break; - } - case '+': - case '=': - case WXK_NUMPAD_ADD: - case WXK_ADD: - { - //Reverse direction of motion - cameraMoveRate= -cameraMoveRate; - - //Do a forwards dolly by fixed amount - currentScene.getActiveCam()->forwardsDolly(cameraMoveRate); - if(currentScene.haveTempCam()) - currentScene.getTempCam()->forwardsDolly(cameraMoveRate); - break; - } - default: - ; - } - - Refresh(); - event.Skip(); -} - -void BasicGLPane::charEvent(wxKeyEvent& event) -{ - -} - - -void BasicGLPane::resized(wxSizeEvent& evt) -{ - wxGLCanvas::OnSize(evt); - - prepare3DViewport(0,0,getWidth(),getHeight()); - wxClientDC *dc=new wxClientDC(this); - Refresh(); - delete dc; -} - -bool BasicGLPane::prepare3DViewport(int tlx, int tly, int brx, int bry) -{ - - if(!paneInitialised) - return false; - - //Prevent NaN. - if(!(bry-tly)) - return false; - GLint dims[2]; - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); - - //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 - if(dims[0] <(brx-tlx) || dims[1] < bry-tly || - (!dims[0] || !dims[1] )) - return false; - - glViewport( tlx, tly, brx-tlx, bry-tly); - - currentScene.setWinSize(brx-tlx,bry-tly); - - //Assume no perspective transform - //use scene camera to achieve this - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - - float aspect = (float)(brx-tlx)/(float)(bry-tly); - - currentScene.setAspect(aspect); - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - float r,g,b; - currentScene.getBackgroundColour(r,g,b); - glClearColor( r, g, b,1.0f ); - glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); - - - - glEnable(GL_LIGHT0); - - - glShadeModel(GL_SMOOTH); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - - - - glEnable(GL_COLOR_MATERIAL); - glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ) ; - - glEnable(GL_POINT_SMOOTH); - glEnable(GL_LINE_SMOOTH); - - - -// SetPosition( wxPoint(0,0) ); - - return true; -} - -int BasicGLPane::getWidth() -{ - return GetClientSize().x; -} - -int BasicGLPane::getHeight() -{ - return GetClientSize().y; -} - -void BasicGLPane::render( wxPaintEvent& evt ) -{ -#ifdef DEBUG - extern EventLogger evtlog; - evtlog.insert(evt); -#endif - //Prevent calls to openGL if pane not visible - if (!IsShown()) - return; - - wxGLCanvas::SetCurrent(); - if(!paneInitialised) - { - paneInitialised=true; - prepare3DViewport(0,0,getWidth(),getHeight()); - } - - wxPaintDC(this); - currentScene.draw(); - glFlush(); - SwapBuffers(); -} - -void BasicGLPane::OnEraseBackground(wxEraseEvent &evt) -{ - //Do nothing. This is to help elminate flicker apparently -} - -void BasicGLPane::updateClearColour() -{ - float rClear,gClear,bClear; - currentScene.getBackgroundColour(rClear,gClear,bClear); - //Can't set the opengl window without a proper context - ASSERT(paneInitialised); - setGlClearColour(rClear,gClear,bClear); - //Let openGL know that we have changed the colour. - glClearColor( rClear, gClear, - bClear,1.0f); -} - -bool BasicGLPane::saveImage(unsigned int width, unsigned int height, - const char *filename, bool showProgress) -{ - GLint dims[2]; - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); - - //Opengl should not be giving us zero dimensions here. - // if it does, just abandon saving the image as a fallback - ASSERT(dims[0] && dims[1]); - if(!dims[0] || !dims[1]) - return false; - - //create new image - wxImage *image = new wxImage(width,height); - - //We cannot seem to draw outside the current viewport. - //in a cross platform manner. - //fall back to stitching the image together by hand - char *pixels; - - - pixels= new char[3*width*height]; - int panelWidth,panelHeight; - GetClientSize(&panelWidth,&panelHeight); - - float oldAspect = currentScene.getAspect(); - currentScene.setAspect((float)panelHeight/(float)panelWidth); - - //Check - if((unsigned int)width > panelWidth || (unsigned int)height> panelHeight) - { - unsigned int numTilesX,numTilesY; - numTilesX = width/panelWidth; - numTilesY = height/panelHeight; - if(panelWidth % width) - numTilesX++; - - if(panelHeight% height) - numTilesY++; - - //Construct the image using "tiles": what we do is - //use the existing viewport size (as we cannot reliably change it - //without handling an OnSize event to resize the underlying - //system buffer (eg hwnd under windows.)) - //and then use this to reconstruct the image in a piece wise manner - float tileStart[2]; - - float fractionWidth=(float)panelWidth/(float)width; - float fractionHeight=(float)panelHeight/(float)height; - - unsigned int thisTileNum=0; - - wxProgressDialog *wxD=0; - if(showProgress) - { - wxD = new wxProgressDialog(wxTRANS("Image progress"), - wxTRANS("Rendering tiles..."), numTilesX*numTilesY); - - wxD->Show(); - } - - std::string tmpStr,tmpStrTwo; - stream_cast(tmpStrTwo,numTilesX*numTilesY); - - for(unsigned int tileX=0;tileXUpdate(thisTileNum,wxStr(tmpStr)); - - - tileStart[1]=(fractionHeight*(float)tileY-0.5); - //Adjust the viewport such that the render generates the tile for - //this view. Coordinates are in normalised device coords (-1 to 1) - currentScene.restrictView(tileStart[0],tileStart[1], - tileStart[0]+fractionWidth,tileStart[1]+fractionHeight); - - //Clear the buffers and draw the openGL scene - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - currentScene.draw(); - - //Force openGL to block execution until draw complete - glFlush(); - glFinish(); - - //Grab the image generated for this tile - glReadBuffer(GL_BACK); - //Set the pixel alignment to one byte, so that openGL unpacks - //correctly into our buffer. - glPushAttrib(GL_PACK_ALIGNMENT); - glPixelStorei(GL_PACK_ALIGNMENT,1); - - //Read image - glReadPixels(0, 0, panelWidth,panelHeight, - GL_BGR, GL_UNSIGNED_BYTE, pixels); - glPopAttrib(); - - - //Copy the data into its target location, - char *pixel; - unsigned int pixX,pixY; - pixX=0; - pixY=0; - unsigned int cutoffX,cutoffY; - cutoffX= std::min((tileX+1)*panelWidth,width); - cutoffY= std::min((tileY+1)*panelHeight,height); - for (unsigned int ui=tileX*panelWidth; ui<=cutoffX; ui++) - { - pixY=0; - for (unsigned int uj=tileY*panelHeight; uj<=cutoffY; uj++) - { - pixel=pixels+(3*(pixY*panelWidth+ pixX)); - image->SetRGB(ui,(height-1)-uj,pixel[2],pixel[1],pixel[0]); - pixY++; - } - pixX++; - } - } - - } - //Disable the view restriction - currentScene.unrestrictView(); - if(showProgress) - wxD->Destroy(); - - } - else - { - //"Resize" the viewport. This wont cause the underlying buffer to resize - //so the imae will reduce, but be surrounded by borders. - //Its a bit of a hack, but it should work - prepare3DViewport(0,0,width,height); - - //Clear the buffers and draw the openGL scene - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - currentScene.draw(); - glFinish(); - - SwapBuffers(); - glReadBuffer(GL_BACK); - - //Set the pixel alignment to one byte, so that openGL unpacks - //correctly into our buffer. - glPushAttrib(GL_PACK_ALIGNMENT); - glPixelStorei(GL_PACK_ALIGNMENT,1); - //Read the image - glReadPixels(0, 0, width,height, - GL_BGR, GL_UNSIGNED_BYTE, pixels); - - - glPopAttrib(); - - char *pixel; - - //copy rows & columns into image - for(unsigned int ui=0;uiSetRGB(ui,(height-1)-uj,pixel[2],pixel[1],pixel[0]); - } - } - - //Restore viewport - prepare3DViewport(0,0,getWidth(),getHeight()); - } - - delete[] pixels; - - bool isOK=image->SaveFile(wxCStr(filename),wxBITMAP_TYPE_PNG); - - currentScene.setAspect(oldAspect); - delete image; - - wxPaintEvent event; - wxPostEvent(this,event); - - return isOK; -} - -void BasicGLPane::OnAxisTapTimer(wxTimerEvent &evt) -{ - lastKeyDoubleTap=(unsigned int)-1; -} - - -bool BasicGLPane::saveImageSequence(unsigned int resX, unsigned int resY, unsigned int nFrames, - wxString &path,wxString &prefix, wxString &ext) -{ - //OK, lets animate! - // - - - ASSERT(!currentScene.haveTempCam()); - std::string outFile; - Camera *c; - wxProgressDialog *wxD = new wxProgressDialog(wxTRANS("Animation progress"), - wxTRANS("Rendering sequence..."), nFrames,this,wxPD_CAN_ABORT ); - - wxD->Show(); - std::string tmpStr,tmpStrTwo; - stream_cast(tmpStrTwo,nFrames); - for(unsigned int ui=0;uimove(angle,0); - - //Save the result - outFile = string(stlStr(path))+ string("/") + - string(stlStr(prefix))+digitStr+ string(".") + string(stlStr(ext)); - if(!saveImage(resX,resY,outFile.c_str(),false)) - return false; - - //Update the progress bar - stream_cast(tmpStr,ui+1); - //Tell user which image from the animation we are saving - tmpStr = std::string(TRANS("Saving Image ")) + tmpStr + std::string(TRANS(" of ")) + tmpStrTwo + "..."; - if(!wxD->Update(ui,wxStr(tmpStr))) - break; - - Refresh(); - } - - //Discard the current temp. cam to return the scene back to normal - currentScene.discardTempCam(); - wxD->Destroy(); - - wxPaintEvent event; - wxPostEvent(this,event); - return true; - -} diff -Nru 3depict-0.0.12/src/glPane.h 3depict-0.0.13/src/glPane.h --- 3depict-0.0.12/src/glPane.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/glPane.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* - * gLPane.h - WxWidgets opengl Pane. - * Copyright (C) 2012, 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 . -*/ -#ifndef GLPANE_H -#define GLPANE_H - -#include - -//Local includes -#include "scene.h" - - -class BasicGLPane : public wxGLCanvas -{ -private: - wxStatusBar *parentStatusBar; - wxTimer *parentStatusTimer; - unsigned int statusDelay; - //In some implementation of openGL in wx. - //calling GL funcs before Paint() will crash program - bool paneInitialised; - //Is the user engaged in a drag operation? - bool dragging; - - //Where is the start of the mouse drag? - wxPoint draggingStart; - bool lastMoveShiftDown; - - //True if an object has been mouse-overed for selection - bool selectionMode; - //The scene ID value for the currently selected object - unsigned int curSelectedObject; - //The scene ID value for object currently being "hovered" over - unsigned int hoverObject; - - //!Last mouseflags/keyflags during selection event - unsigned int lastMouseFlags,lastKeyFlags; - - //Test for a object selection. Returns -1 if no selection - //or object ID if selection OK. Also sets lastSelected & scene - unsigned int selectionTest(const wxPoint &p, bool &shouldRedraw); - - //Test for a object hover under cursor Returns -1 if no selection - //or object ID if selection OK. Also sets last hover and scene - unsigned int hoverTest(const wxPoint &p, bool &shouldRedraw); - - //!Are there updates to the camera Properties due to camera motion? - bool haveCameraUpdates; - - //!Are we currently applying a device in the scene? - bool applyingDevice; - - //Parameters for modifying mouse speed - float mouseZoomFactor,mouseMoveFactor; - - unsigned int lastKeyDoubleTap; - - wxTimer *keyDoubleTapTimer; -public: - bool displaySupported() const; - - //Enable/Disable the scene interaction for user objects? - void setSceneInteractionAllowed(bool enabled=true); - - //!The scene object, holds all info about 3D drawable components - Scene currentScene; - - //!Must be called before user has a chance to perform interaction - void setParentStatus(wxStatusBar *statusBar, - wxTimer *timer,unsigned int statDelay) - { parentStatusBar=statusBar;parentStatusTimer=timer;statusDelay=statDelay;}; - - bool hasCameraUpdates() const {return haveCameraUpdates;}; - - void clearCameraUpdates() {haveCameraUpdates=false;}; - - BasicGLPane(wxWindow* parent); - ~BasicGLPane(); - - void resized(wxSizeEvent& evt); - - int getWidth(); - int getHeight(); - - - void setMouseMoveFactor(float f) { mouseMoveFactor=f;}; - void setMouseZoomFactor(float f) { mouseZoomFactor=f;}; - - //!Is the window initialised? - bool isInited() { return paneInitialised;} - - //!Set the background colour (openGL clear colour) - void setGlClearColour(float r,float g,float b); - //!Pull in the colour from the scene - void updateClearColour(); - //!Render the view using the scene - void render(wxPaintEvent& evt); - //!Construct a 3D viewport, ready for openGL output. Returns false if initialisation failed - bool prepare3DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y); - //!Save an image to file, return false on failure - bool saveImage(unsigned int width, unsigned int height,const char *filename, bool showProgress=true); - //!Save an image sequence to files by orbiting the camera - bool saveImageSequence(unsigned int width, unsigned int height, unsigned int nFrames, - wxString &path, wxString &prefix, wxString &extension); - - //!Get the background colour - void getGlClearColour(float &r,float &g,float &b) { currentScene.getBackgroundColour(r,g,b);} - // events - void mouseMoved(wxMouseEvent& event); - void mouseDown(wxMouseEvent& event); - void mouseWheelMoved(wxMouseEvent& event); - void mouseReleased(wxMouseEvent& event); - void rightClick(wxMouseEvent& event); - void mouseLeftWindow(wxMouseEvent& event); - void keyPressed(wxKeyEvent& event); - void keyReleased(wxKeyEvent& event); - void charEvent(wxKeyEvent& event); - void OnEraseBackground(wxEraseEvent &); - void OnAxisTapTimer(wxTimerEvent &); - bool setFullscreen(bool fullscreen); - bool setMouseVisible(bool visible); - - - DECLARE_EVENT_TABLE() -}; - -#endif diff -Nru 3depict-0.0.12/src/glade-skeleton/autosaveDialog.wxg 3depict-0.0.13/src/glade-skeleton/autosaveDialog.wxg --- 3depict-0.0.12/src/glade-skeleton/autosaveDialog.wxg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/glade-skeleton/autosaveDialog.wxg 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ - - - - - - enum\n{\nID_LIST_STATES=wxID_ANY+1,\nID_REMOVE_ALL - - Restore state? - - wxVERTICAL - - wxLEFT|wxRIGHT|wxTOP|wxALIGN_CENTER_HORIZONTAL - 6 - - - - 1 - - - - - wxALL|wxEXPAND - 8 - - - 0 - - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxLEFT|wxBOTTOM - 8 - - - - - - - 0 - - - 20 - 20 - - - - wxLEFT|wxRIGHT|wxBOTTOM - 8 - - - CANCEL - - - - - wxRIGHT|wxBOTTOM - 8 - - - OK - - - - - - - - diff -Nru 3depict-0.0.12/src/glade-skeleton/errorDialog.wxg 3depict-0.0.13/src/glade-skeleton/errorDialog.wxg --- 3depict-0.0.12/src/glade-skeleton/errorDialog.wxg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/glade-skeleton/errorDialog.wxg 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ - - - - - - - Filter Errors - 551, 414 - - wxVERTICAL - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxLEFT|wxRIGHT|wxTOP|wxEXPAND - 6 - - - - - - - wxEXPAND - 0 - - - wxVERTICAL - - 0 - - - 10 - 10 - - - - wxTOP|wxEXPAND - 5 - - - wxHORIZONTAL - - 0 - - - 1 - - - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - - - wxTOP|wxEXPAND - 6 - - - wxHORIZONTAL - - 0 - - - 1 - - - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - - - 0 - - - 20 - 20 - - - - - - - - wxALL|wxALIGN_RIGHT - 5 - - - OK - - wxID_OK - - - - - diff -Nru 3depict-0.0.12/src/glade-skeleton/mainWindow.wxg 3depict-0.0.13/src/glade-skeleton/mainWindow.wxg --- 3depict-0.0.12/src/glade-skeleton/mainWindow.wxg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/glade-skeleton/mainWindow.wxg 1970-01-01 00:00:00.000000000 +0000 @@ -1,868 +0,0 @@ - - - - - - enum {\nID_COMBO_SETTINGS = wxID_ANY+1,\nID_FILE_EXIT,\nID_FILE_OPEN,\nID_FILE_SAVE,\nID_FILE_SAVEAS,\nID_HELP_ABOUT,\nID_HELP_HELP,\nID_NOTEBOOK_CONTROL,\nID_NOTE_CAMERA,\nID_NOTE_DATA,\nID_NOTE_PERFORMANCE,\nID_NOTE_TOOLS,\nID_NOTE_VISUALISATION,\nID_PANEL_DATA,\nID_PANEL_VIEW,\nID_SPLIT_LEFTRIGHT,\nID_SPLIT_TOP_BOTTOM,\nID_NOTE_SPECTRA,\nID_NOTE_RAW,\n}; - - Quick 3D - 1 - - - - - - ID_FILE_OPEN - Open - Open state file - OnFileOpen - - - - ID_FILE_SAVE - Save - Save state to file - OnFileSave - - - - ID_FILE_SAVEAS - MenuSaveAs - Save current state to new file - OnFileSaveAs - - - - --- - --- - - - - - Export Current Plot - OnFileExportPlot - - - - Export Current 3D View - OnFileExportImage - - - - Export Ion Data - OnFileExportIons - - - - Export Range Data - OnFileExportRange - - - - - --- - --- - - - - ID_FILE_EXIT - Exit - Exit Program - OnFileExit - - - - - - - - - --- - --- - - - - ID_VIEW_CONTROL_PANE - MenuControlPane - Enable or disable the left control pane - 1 - OnViewControlPane - - - - ID_VIEW_RAW_DATA_PANE - MenuRawDataPane - Enable or disable the raw data pane (bottom of right panel) - 1 - OnViewRawDataPane - - - - ID_VIEW_SPECTRA - MenuViewSPectra - 1 - - - - --- - --- - - - - - - - - - ID_HELP_HELP - MenuHelp - Show help files and documentation - OnHelpHelp - - - - --- - --- - - - - ID_HELP_ABOUT - MenuAbout - Information about this program - OnHelpAbout - - - - - - wxHORIZONTAL - - wxEXPAND - 0 - - - - wxSPLIT_VERTICAL - ID_SPLIT_LEFTRIGHT - panelView - panelLeft - - - - wxVERTICAL - - wxLEFT|wxBOTTOM|wxEXPAND - 2 - - - - - Data - Cam - Post - Tools - - ID_NOTEBOOK_CONTROL - - - 10, 10 - 1 - ID_NOTE_DATA - - wxVERTICAL - - 0 - - - 1 - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND - 3 - - - - 0 - ID_COMBO_SETTINGS - - - - OnComboSettings - OnComboSettingsText - OnComboSettingsEnter - - - - - wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL - 0 - - - - - - - - - wxEXPAND - 0 - - - - 1 - - - - 0 - - - 1 - - - - - wxEXPAND - 0 - - - - wxSPLIT_HORIZONTAL - filterPropertyPane - filterTreePane - - - - wxHORIZONTAL - - wxEXPAND - 0 - - - wxVERTICAL - - wxLEFT|wxRIGHT|wxEXPAND - 4 - - - - -1 - List of available filters - ID_FILTER_NAMES - - Range File - Downsampling - Mass Spectrum - Clipping - Compos. Profiles - Bounding Box - Ion Colour - Ion Transform - - - OnFilterNameCombo - OnFilterNameComboText - OnFilterNameComoEnter - - - - - wxLEFT|wxBOTTOM|wxEXPAND - 3 - - - - Tree of data filters - ID_TREE_FILTERS - - OnTreeBeginDrag - OnTreeEndDrag - OnTreeDeleteItem - OnTreeSelectionChange - OnTreeKeyDown - OnTreeItemTooltip - - - - - wxTOP - 8 - - - 1 - - - - - wxBOTTOM|wxEXPAND - 5 - - - - - - - - - wxEXPAND - 0 - - - wxVERTICAL - - 0 - - - 1 - - Enable/Disable automatic updates of data when filter change takes effect - ID_CHECK_AUTOUPDATE - - - - 0 - - - 10 - 10 - - - - wxALL - 2 - - - REFRESH - - - - - wxEXPAND - 0 - - - - - - - - - - - - - wxVERTICAL - - 0 - - - 1 - - - - - wxLEFT|wxEXPAND - 4 - - - ID_GRID_FILTER_PROPERTY - 1 - 1 - 1 - 3 - 1 - 0 - 1 - wxGrid.wxGridSelectCells - - Property - Value - - - OnGridFilterPropertyChange - - - - - - - - - - - - 10, 10 - 1 - ID_NOTE_CAMERA - - wxVERTICAL - - 0 - - - 1 - - - - - wxTOP|wxBOTTOM|wxEXPAND - 4 - - - wxHORIZONTAL - - 0 - - - -1 - ID_COMBO_CAMERA - - - - OnEventComboBox - OnEventText - OnEventTextEnter - - - - - wxLEFT|wxRIGHT - 2 - - - REMOVE - - - OnButtonRemoveCam - - - - - - - wxEXPAND - 0 - - - - 1 - - - - wxEXPAND - 0 - - - ID_GRID_CAMERA_PROPERTIES - Camera data information - 1 - 1 - 1 - 4 - 1 - 0 - 1 - wxGrid.wxGridSelectRows - - Property - Value - - - - - - - - - wxVERTICAL - - wxALL - 5 - - - - Enable/disable visual effects on final 3D output - - OnCheckPostProcess - - - - - wxEXPAND - 0 - - - - - Crop - Stereo - - - - - wxVERTICAL - - wxALL - 6 - - - - Enable cropping post-process effect - ID_EFFECT_CROP_ENABLE - - OnFxCropCheck - - - - - wxLEFT - 15 - - - - - - - wxLEFT|wxRIGHT|wxTOP|wxEXPAND - 5 - - - wxHORIZONTAL - - wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL - 0 - - - wxVERTICAL - - wxRIGHT|wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL - 5 - - - - 0 - ID_EFFECT_CROP_AXISONE_COMBO - - x-y - x-z - y-x - y-z - z-x - z-y - - - OnFxCropAxisOne - - - - - wxRIGHT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxSHAPED - 5 - - - - #54fff4 - ID_EFFECT_CROP_PANELONE_COMBO - - - - - - wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL - 0 - - - wxVERTICAL - - wxLEFT|wxBOTTOM|wxEXPAND - 5 - - - - 0 - ID_EFFECT_CROP_AXISTWO_COMBO - - x-y - x-z - y-x - y-z - z-x - z-y - - - OnFxCropAxisTwo - - - - - wxLEFT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxSHAPED - 5 - - - - #ff4fe2 - ID_EFFECT_CROP_PANELTWO_COMBO - - - - - - - - wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL - 5 - - - 2 - 0,1,2 - 3 - 0,1 - 2 - 2 - - wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - 0 - - - ID_EFFECT_CROP_TEXT_DX - - - - wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - 0 - - - ID_EFFECT_CROP_TEXT_DY - - - - wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - 0 - - - ID_EFFECT_CROP_TEXT_DZ - - - - - - - - - - wxVERTICAL - - wxLEFT|wxTOP - 6 - - - - Colour based 3D effect enable/disable - - OnFxStereoEnable - - - - - 0 - - - 20 - 20 - - - - wxBOTTOM|wxEXPAND - 15 - - - wxHORIZONTAL - - wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL - 5 - - - - 1 - - - - - wxLEFT - 5 - - - - 0 - Glasses colour mode - - Red-Blue - Red-Green - Red-Cyan - Half Colour - Mixed Colour - - - OnFxStereoCombo - - - - - 0 - - - 1 - - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxLEFT|wxTOP - 5 - - - 1 - - - - - wxLEFT|wxRIGHT|wxTOP|wxEXPAND - 5 - - - - Level of separation between left and right images, which sets 3D depth to visual distortion tradeoff - - OnFxStereoBaseline - - - - - - - wxLEFT - 5 - - - - Reverse output 3D channels (to negate a flip in 3D lens layout) - - - - - - - - - - - - wxVERTICAL - - wxLEFT|wxTOP|wxBOTTOM - 5 - - - - - - - wxLEFT|wxTOP|wxBOTTOM - 6 - - - - - - - wxLEFT|wxTOP|wxBOTTOM - 5 - - - - - - - wxLEFT|wxTOP|wxBOTTOM - 5 - - - - - - - wxTOP|wxEXPAND - 5 - - - wxHORIZONTAL - - wxRIGHT|wxALIGN_RIGHT - 5 - - - 1 - - - - - 5 - - - 0, 100 - 50 - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/glade-skeleton/preferencesDialog.wxg 3depict-0.0.13/src/glade-skeleton/preferencesDialog.wxg --- 3depict-0.0.12/src/glade-skeleton/preferencesDialog.wxg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/glade-skeleton/preferencesDialog.wxg 1970-01-01 00:00:00.000000000 +0000 @@ -1,400 +0,0 @@ - - - - - - - Preferences - 642, 487 - - wxVERTICAL - - wxEXPAND - 0 - - - - - Pref - Startup - Camera - - - - - wxHORIZONTAL - - - wxEXPAND - 0 - - - wxVERTICAL - - 0 - - - 1 - - - - - wxEXPAND - 0 - - - - 0 - ID_LIST_FILTERS - - - - OnListClick - - - - - - - 0 - - - 20 - 20 - - - - wxEXPAND - 0 - - - wxVERTICAL - - wxEXPAND - 0 - - - 10 - ID_GRID_PROPERTIES - - - - wxGrid.wxGridSelectCells - 1 - 1 - 1 - 0 - 1 - - OnFilterCellClick - OnFilterCellChange - - 1 - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - 0 - - - - - - - 0 - - - - - - - 0 - - - 20 - 20 - - - - - - - - - - - - wxVERTICAL - - wxALL|wxEXPAND - 5 - - - wxVERTICAL - - - 0 - - - - 0 - Set the method of panel layout when starting the program - ID_START_COMBO_PANEL - - Always show - Remember - Specify - - - OnStartupPanelCombo - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - 0 - - - 20 - 20 - - - - wxEXPAND - 0 - - - wxVERTICAL - - 0 - - - - ID_START_CHECK_CONTROL - - OnStartupCheckControl - - - - - 0 - - - - ID_START_CHECK_RAWDATA - - OnStartupCheckRawData - - - - - 0 - - - - ID_START_CHECK_PLOTLIST - - OnStartupCheckPlotList - - - - - - - - - - - wxALL|wxEXPAND - 5 - - - wxVERTICAL - - - 0 - - - - Lets the program check the internet to see if updates to the program version are available, then bugs you about it now and again. - - - - - - - - - - wxVERTICAL - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxALIGN_CENTER_VERTICAL - 0 - - - - 1 - - - - - 0 - - - 20 - 20 - - - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - wxEXPAND|wxALIGN_CENTER_VERTICAL - 0 - - - - Camera tanslation, orbit and swivel rates. - 1, 100 - 1 - - - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxALIGN_CENTER_VERTICAL - 0 - - - - 1 - - - - - 0 - - - 20 - 20 - - - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - wxEXPAND|wxALIGN_CENTER_VERTICAL - 0 - - - - Camera zooming rate. - 1, 100 - 1 - - - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - - - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxEXPAND - 0 - - - 20 - 20 - - - - wxTOP - 8 - - - OK - - - - - wxLEFT|wxTOP|wxBOTTOM - 8 - - - CANCEL - - - - - 0 - - - 20 - 10 - - - - - - - diff -Nru 3depict-0.0.12/src/glade-skeleton/resDialog.wxg 3depict-0.0.13/src/glade-skeleton/resDialog.wxg --- 3depict-0.0.12/src/glade-skeleton/resDialog.wxg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/glade-skeleton/resDialog.wxg 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ - - - - - - enum\n{\n ID_RESET=wxID_ANY+1,\n ID_SPIN_WIDTH,\n ID_SPIN_HEIGHT,\n ID_LOCK_ASPECT\n}; - - Resolution Selection - - wxVERTICAL - - wxEXPAND - 0 - - - wxHORIZONTAL - - 0 - - - 20 - 10 - - - - wxLEFT|wxEXPAND - 8 - - - wxVERTICAL - - 0 - - - 20 - 20 - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxALIGN_CENTER_VERTICAL - 0 - - - - 1 - - - - - wxALL|wxALIGN_CENTER_VERTICAL - 8 - - - ID_SPIN_WIDTH - - OnSpinWidth - - - - - - - wxEXPAND - 0 - - - wxHORIZONTAL - - wxALIGN_CENTER_VERTICAL - 0 - - - 1 - - - - - wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL - 5 - - - ID_SPIN_HEIGHT - - OnSpinHeight - - - - - - - wxALIGN_CENTER_VERTICAL - 3 - - - - ID_LOCK_ASPECT - - OnCheckLockAspect - - - - - 0 - - - 20 - 20 - - - - - - 0 - - - 10 - 10 - - - - wxEXPAND - 0 - - - - 1 - - - - wxALL|wxEXPAND - 5 - - - - - - - - - wxEXPAND - 0 - - - - 1 - - - - wxTOP|wxBOTTOM|wxEXPAND - 5 - - - wxHORIZONTAL - - wxALL - 5 - - - - ID_RESET - - OnBtnRefresh - - - - - 0 - - - 20 - 20 - - - - wxALL - 5 - - - OK - - - OnBtnOK - - - - - wxALL - 5 - - - CANCEL - - - OnBtnCancel - - - - - - - - diff -Nru 3depict-0.0.12/src/gui/art.h 3depict-0.0.13/src/gui/art.h --- 3depict-0.0.12/src/gui/art.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/art.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * art.h - Program icons 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 . + */ + +#ifndef ART_H +#define ART_H + +#include + +#include "../data/3Depict.xpm" + +class MyArtProvider : public wxArtProvider +{ + public: + MyArtProvider() {} + virtual ~MyArtProvider() {} + + protected: + wxBitmap CreateBitmap(const wxArtID& id, + const wxArtClient& client, + const wxSize& size) + { + if (id == _T("MY_ART_ID_ICON")) + return wxBitmap(_Depict); + + wxBitmap b; + return b; + + } +}; + +#endif // ART_H diff -Nru 3depict-0.0.12/src/gui/cropPanel.cpp 3depict-0.0.13/src/gui/cropPanel.cpp --- 3depict-0.0.12/src/gui/cropPanel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/cropPanel.cpp 2013-04-10 20:40:39.000000000 +0000 @@ -0,0 +1,706 @@ +/* + * wxCropPanel.cpp - cropping window for user interaction + * 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 . +*/ + + +#include "cropPanel.h" + +#include + +#include "common/assertion.h" + +//Crop array indices +enum +{ + CROP_LEFT, + CROP_TOP, + CROP_RIGHT, + CROP_BOTTOM, + CROP_ENUM_END +}; + + +BEGIN_EVENT_TABLE(CropPanel, wxPanel) + EVT_PAINT(CropPanel::onPaint) + EVT_MOTION(CropPanel::mouseMove) + EVT_LEFT_DOWN(CropPanel::mouseDown) + EVT_LEFT_UP(CropPanel::mouseReleased) + EVT_LEAVE_WINDOW(CropPanel::mouseLeftWindow) + EVT_LEFT_DCLICK(CropPanel::mouseDoubleLeftClick) + EVT_ERASE_BACKGROUND(CropPanel::OnEraseBackground) + EVT_SIZE(CropPanel::onResize) +END_EVENT_TABLE() + + + +CropPanel::CropPanel(wxWindow * parent, wxWindowID id, + const wxPoint & pos,const wxSize & size,long style) + : wxPanel(parent, id, pos, size, style) +{ + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + programmaticEvent=false; + crop[0]=crop[1]=crop[2]=crop[3]=0.2; + selMode=SELECT_MODE_NONE; + dragging=false; + linkedPanel=0; + linkMode=CROP_LINK_NONE; + hasUpdates=false; +} + +void CropPanel::OnEraseBackground(wxEraseEvent &event) +{ + //Intentionally do nothing, to suppress background erase +} + +void CropPanel::mouseMove(wxMouseEvent &event) +{ + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + + if(!w || !h) + return; + + //Do our calculations in reduced coordinates (0->1); + float xMouse,yMouse; + wxPoint mousePos =event.GetPosition(); + //Add a 1px border around control + xMouse=(float)(mousePos.x+1)/(float)(w-2); + yMouse=(float)(mousePos.y+1)/(float)(h-2); + + if(!dragging) + { + unsigned int index; + selMode=getBestCropWidget(xMouse,yMouse,index); + + //Update the currently selected index as needed + if(selMode == SELECT_MODE_SIDE || selMode == SELECT_MODE_CORNER) + selIndex=index; + } + else + { + float origCrop[4]; + for(unsigned int ui=0;ui<4;ui++) + origCrop[ui]=crop[ui]; + switch(selMode) + { + case SELECT_MODE_NONE: + ASSERT(false); // Can't be dragging nothing, can we. + break; + case SELECT_MODE_SIDE: + { + // we are dragging one of the side crop walls + switch(selIndex) + { + case 0: + crop[selIndex ] =xMouse; + break; + case 1: + crop[selIndex ] = yMouse; + break; + case 2: + crop[selIndex]=1.0-xMouse; + break; + case 3: + crop[selIndex]=1.0-yMouse; + break; + } + + break; + } + case SELECT_MODE_CORNER: + { + //we are dragging one of the corners + switch(selIndex) + { + case 0: + crop[0] =xMouse; + crop[1]=yMouse; + break; + case 1: + crop[1]=yMouse; + crop[2] =1.0-xMouse; + break; + case 2: + crop[2] =1.0-xMouse; + crop[3]=1.0-yMouse; + break; + case 3: + crop[3] =1.0-yMouse; + crop[0]=xMouse; + break; + } + break; + } + case SELECT_MODE_CENTRE: + { + //OK, we have to move them based upon the original drag + //coordinates + float delta[2]; + delta[0]=xMouse-mouseAtDragStart[0]; + delta[1]=yMouse-mouseAtDragStart[1]; + for(unsigned int ui=0;ui<4;ui++) + { + float flip; + + if(ui<2) + flip=1.0; + else + flip=-1; + crop[ui]=cropAtDragStart[ui]+delta[ui&1]*flip; + } + + break; + + } + } + + + //Check the result is still valid + if(!validCoords()) + { + //Try to only adjust the invalid coordinates, + //to make the motion a little "smoother" + for(unsigned int ui=0;ui<4;ui++) + { + if(crop[ui] > 1.0 || crop[ui] < 0.0) + crop[ui]=origCrop[ui]; + } + + //See if our quick fix solved the coord validity + if(!validCoords()) + { + //restore the original coords + for(unsigned int ui=0;ui<4;ui++) + crop[ui]=origCrop[ui]; + } + } + + if(linkedPanel) + updateLinked(); + + hasUpdates=true; + } + + + Refresh(); +} + +unsigned int CropPanel::getBestCropWidget(float xMouse, float yMouse,unsigned int &index) const +{ + unsigned int bestSelMode=SELECT_MODE_NONE; + + int w,h; + w=0;h=0; + GetClientSize(&w,&h); + + if(!w || !h) + return bestSelMode; + + float meanPx = 1.0/(1.0/(w-2) + 1.0/(h-2)); + unsigned int minIndex; + float minDist,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) + { + case 0: + //Top left corner + x=crop[CROP_LEFT]; + y=crop[CROP_TOP]; + break; + case 1: + //Top right corner + x=1.0-crop[CROP_RIGHT]; + y=crop[CROP_TOP]; + break; + + case 2: + //Bottom right corner + x=1.0-crop[CROP_RIGHT]; + y=1.0-crop[CROP_BOTTOM]; + break; + case 3: + //Bottom left corner + x=crop[CROP_LEFT]; + y=1.0-crop[CROP_BOTTOM]; + break; + default: + ASSERT(false); + } + + tmpDist=(xMouse-x)*(xMouse-x) + (yMouse-y)*(yMouse-y); + if(!ui || tmpDist < minDist) //first pass - no data + { + minIndex=ui; + minDist=tmpDist; + } + } + + minDist=sqrtf(minDist); + bool haveCorner; + + const float MIN_CUTOFF_DISTANCE= 3; + + //Do we have a corner minimum? + haveCorner= ((int)(minDist*meanPx) < MIN_CUTOFF_DISTANCE); + + bool haveCentre; + float meanX = (float)(crop[0] + (1.0-crop[2]))*0.5; + float meanY = (float)(crop[1] + (1.0-crop[3]))*0.5; + + float centreDist; + centreDist=sqrtf((xMouse-meanX)*(xMouse-meanX) + + (yMouse-meanY)*(yMouse-meanY)); + //Check the centre, which is allowed to trump the corners + if(haveCorner) + haveCentre=(centreDist< minDist); + else + haveCentre=(meanPx*centreDist) < MIN_CUTOFF_DISTANCE; + unsigned int sideIndex; + + bool haveSide=false; + //OK, well, we are allowed to have a side match, check that. + if(fabs(crop[CROP_LEFT] - xMouse)*meanPx < MIN_CUTOFF_DISTANCE) + { + haveSide=true; + sideIndex=CROP_LEFT; + } + //OK, well, we are allowed to have a side match, check that. + else if(fabs((1.0-crop[CROP_RIGHT]) - xMouse)*meanPx < MIN_CUTOFF_DISTANCE) + { + haveSide=true; + sideIndex=CROP_RIGHT; + } + else if(fabs(crop[CROP_TOP] - yMouse)*meanPx < MIN_CUTOFF_DISTANCE) + { + haveSide=true; + sideIndex=CROP_TOP; + } + else if(fabs((1.0- crop[CROP_BOTTOM]) - yMouse)*meanPx < MIN_CUTOFF_DISTANCE) + { + haveSide=true; + sideIndex=CROP_BOTTOM; + } + + + //!Prioritise selection mode + if(haveCentre) + { + bestSelMode=SELECT_MODE_CENTRE; + } + else if(haveCorner) + { + bestSelMode=SELECT_MODE_CORNER; + index=minIndex; + } + else if(haveSide) + { + bestSelMode=SELECT_MODE_SIDE; + index=sideIndex; + } + else + { + bestSelMode=SELECT_MODE_NONE; + } + + return bestSelMode; +} + +void CropPanel::mouseDoubleLeftClick(wxMouseEvent& event) +{ + //set the snap position using a bitmask + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + + if(!w || !h) + return; + + + unsigned int index; + + float xMouse,yMouse; + wxPoint mousePos =event.GetPosition(); + //Add a 1px border around control + xMouse=(float)(mousePos.x+1)/(float)(w-2); + yMouse=(float)(mousePos.y+1)/(float)(h-2); + + + switch(getBestCropWidget(xMouse,yMouse,index)) + { + //Just reset the crop values + //if we are at the centre or side + case SELECT_MODE_NONE: + case SELECT_MODE_CENTRE: + { + for(unsigned int ui=0;ui<4;ui++) + crop[ui]=0; + break; + } + case SELECT_MODE_SIDE: + { + //Ok, lets reset just this side + crop[index]=0; + break; + } + case SELECT_MODE_CORNER: + { + crop[index]=0; + crop[(index+1)%4]=0; + break; + } + default: + ASSERT(false); + } + + + Refresh(); + if(linkedPanel) + updateLinked(); + + hasUpdates=true; + event.Skip(); +} + + +void CropPanel::mouseLeftWindow(wxMouseEvent& event) +{ + if(!dragging) + selMode=SELECT_MODE_NONE; +} + +void CropPanel::mouseDown(wxMouseEvent &event) +{ + //set the snap position using a bitmask + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + + if(!w || !h) + return; + + + //Do our calculations in reduced coordinates (0->1); + wxPoint mousePos =event.GetPosition(); + mouseAtDragStart[0]=(float)(mousePos.x+1)/(float)(w-2); + mouseAtDragStart[1]=(float)(mousePos.y+1)/(float)(h-2); + + ASSERT(validCoords()); + if(selMode != SELECT_MODE_NONE) + dragging=true; + + for(unsigned int ui=0;ui<4;ui++) + cropAtDragStart[ui] = crop[ui]; + +} + + +void CropPanel::mouseReleased(wxMouseEvent &event) +{ + dragging=false; + selMode=SELECT_MODE_NONE; + selIndex=0; + + Refresh(); +} + +bool CropPanel::validCoords() const +{ + float sum; + sum=(crop[CROP_LEFT] + crop[CROP_RIGHT]); + //Draw the four crop markers + if(sum > 1.00f) + return false; + + + sum=(crop[CROP_TOP] + crop[CROP_BOTTOM]); + if( sum> 1.00f) + return false; + + + for(unsigned int ui=0;ui<4;ui++) + { + if(crop[ui] < 0.0) + return false; + } + + return true; +} + +void CropPanel::onPaint(wxPaintEvent &event) +{ + draw(); +} + +void CropPanel::draw() +{ + ASSERT(validCoords()); + + wxAutoBufferedPaintDC *dc=new wxAutoBufferedPaintDC(this); + + wxBrush *b = new wxBrush; + b->SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND)); + dc->Clear(); + + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + if(!w || !h) + { + delete dc; + return; + } + + + //Drawing coords + int lineX[8],lineY[8]; + + //Draw lines + lineX[0]=lineX[1]=(int)(crop[CROP_LEFT]*(float)w); + lineX[2]=0; + lineX[3]=w; + lineX[4]=lineX[5]=(int)((1.0-crop[CROP_RIGHT])*(float)w); + lineX[6]=w; + lineX[7]=0; + + lineY[0]=0; + lineY[1]=h; + lineY[2]=lineY[3]=(int)(crop[CROP_TOP]*(float)h); + lineY[4]=0; + lineY[5]=h; + lineY[6]=lineY[7]=(int)((1.0-crop[CROP_BOTTOM])*(float)h); + + + + //Draw greyed out section + //-- + wxPen *noPen; + noPen = new wxPen(*wxBLACK,1,wxTRANSPARENT); + b->SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND)); + dc->SetBrush(*b); + dc->SetPen(*noPen); + + dc->DrawRectangle(0,0,lineX[0],h); + dc->DrawRectangle(0,0,w,lineY[2]); + dc->DrawRectangle(0,lineY[6],w,h-lineY[6]); + dc->DrawRectangle(lineX[4],0,w-lineX[4],h); + delete noPen; + delete b; + //-- + + + wxPen *highPen,*normalPen; + highPen= new wxPen(*wxBLUE,2,wxSOLID); + normalPen= new wxPen(*wxBLACK,2,wxSOLID); + + dc->SetPen(*normalPen); + if(selMode!=SELECT_MODE_SIDE) + { + + dc->SetPen(*normalPen); + for(unsigned int ui=0;ui<8;ui+=2) + dc->DrawLine(lineX[ui],lineY[ui],lineX[ui+1],lineY[ui+1]); + + } + else + { + for(unsigned int ui=0;ui<8;ui+=2) + { + if(selIndex== ui/2) + dc->SetPen(*highPen); + else + dc->SetPen(*normalPen); + + dc->DrawLine(lineX[ui],lineY[ui],lineX[ui+1],lineY[ui+1]); + } + + dc->SetPen(*normalPen); + } + + + if(selMode == SELECT_MODE_CORNER) + { + //Draw the corner markers + float xC,yC; + float sizeX,sizeY; + + sizeX=sizeY=8; + switch(selIndex) + { + case 0: + xC=crop[CROP_LEFT]; + yC=crop[CROP_TOP]; + sizeX=-sizeX; + sizeY=-sizeY; + break; + case 1: + xC=1.0-crop[CROP_RIGHT]; + yC=crop[CROP_TOP]; + sizeY=-sizeY; + break; + case 2: + xC=1.0-crop[CROP_RIGHT]; + yC=1.0-crop[CROP_BOTTOM]; + break; + case 3: + sizeX=-sizeX; + xC=crop[CROP_LEFT]; + yC=1.0-crop[CROP_BOTTOM]; + break; + default: + ASSERT(false); + } + + xC=xC*(float)w; + yC=yC*(float)h; + + + //Draw the corner + dc->SetPen(*highPen); + dc->DrawLine(wxCoord(xC + 2.0f*sizeX), wxCoord(yC+sizeY), + wxCoord(xC+sizeX),wxCoord(yC+sizeY)); + dc->DrawLine(wxCoord(xC+sizeX), wxCoord(yC+sizeY), + wxCoord(xC+sizeX),wxCoord(yC+2.0f*sizeY)); + dc->SetPen(*normalPen); + } + + + + float meanX = (float)w*(crop[0] + (1.0-crop[2]))*0.5; + float meanY = (float)h*(crop[1] + (1.0-crop[3]))*0.5; + + dc->DrawCircle((int)meanX,(int)meanY,1); + if(selMode==SELECT_MODE_CENTRE) + { + dc->SetPen(*highPen); + dc->DrawCircle((int)meanX,(int)meanY,4); + } + + delete dc; + + delete highPen; + delete normalPen; + +} + + +void CropPanel::updateLinked() +{ + ASSERT(linkedPanel); + switch(linkMode) + { + case CROP_LINK_NONE: + return; + case CROP_LINK_LR: + linkedPanel->crop[CROP_LEFT]=crop[CROP_LEFT]; + linkedPanel->crop[CROP_RIGHT]=crop[CROP_RIGHT]; + break; + case CROP_LINK_LR_FLIP: + linkedPanel->crop[CROP_BOTTOM]=crop[CROP_LEFT]; + linkedPanel->crop[CROP_TOP]=crop[CROP_RIGHT]; + break; + case CROP_LINK_TB: + linkedPanel->crop[CROP_BOTTOM]=crop[CROP_BOTTOM]; + linkedPanel->crop[CROP_TOP]=crop[CROP_TOP]; + break; + case CROP_LINK_TB_FLIP: + linkedPanel->crop[CROP_LEFT]=crop[CROP_BOTTOM]; + linkedPanel->crop[CROP_RIGHT]=crop[CROP_TOP]; + break; + case CROP_LINK_BOTH: + linkedPanel->crop[CROP_LEFT]=crop[CROP_LEFT]; + linkedPanel->crop[CROP_RIGHT]=crop[CROP_RIGHT]; + linkedPanel->crop[CROP_BOTTOM]=crop[CROP_BOTTOM]; + linkedPanel->crop[CROP_TOP]=crop[CROP_TOP]; + break; + case CROP_LINK_BOTH_FLIP: + linkedPanel->crop[CROP_BOTTOM]=crop[CROP_LEFT]; + linkedPanel->crop[CROP_TOP]=crop[CROP_RIGHT]; + linkedPanel->crop[CROP_LEFT]=crop[CROP_BOTTOM]; + linkedPanel->crop[CROP_RIGHT]=crop[CROP_TOP]; + break; + default: + ASSERT(false); + + } + + linkedPanel->Refresh(); + +} + + +void CropPanel::link(CropPanel *panel,unsigned int mode) +{ + linkMode=mode; + if(linkMode== CROP_LINK_NONE) + linkedPanel=0; + else + { + linkedPanel=panel; + + for(unsigned int ui=0;uicrop[ui]=crop[ui]; + } +} + +void CropPanel::getCropValues(float *array) const +{ + array[0]=crop[CROP_LEFT]; + array[1]=crop[CROP_RIGHT]; + array[2]=crop[CROP_TOP]; + array[3]=crop[CROP_BOTTOM]; + +} + +void CropPanel::setCropValue(unsigned int index, float v) + +{ + ASSERT(index<=CROP_BOTTOM); + crop[index]=v; +} + +void CropPanel::makeCropValuesValid() +{ + for(size_t ui=0;ui<4;ui++) + { + crop[ui]=std::max(crop[ui],0.0f); + crop[ui]=std::min(crop[ui],1.0f); + } + + if(crop[CROP_LEFT] + crop[CROP_RIGHT] >1) + crop[CROP_LEFT]=crop[CROP_RIGHT]=0.2f; + + if(crop[CROP_TOP] + crop[CROP_BOTTOM] >1) + crop[CROP_TOP]=crop[CROP_BOTTOM]=0.2f; +} + +void CropPanel::onResize(wxSizeEvent &evt) +{ +#ifndef __WXMAC__ + wxPaintEvent paintEvt; + wxPostEvent(this,paintEvt); +#endif +} diff -Nru 3depict-0.0.12/src/gui/cropPanel.h 3depict-0.0.13/src/gui/cropPanel.h --- 3depict-0.0.12/src/gui/cropPanel.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/cropPanel.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * wxCropPanel.cpp - cropping window for user interaction + * 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 . +*/ + +#ifndef WXCROPPANEL_H +#define WXCROPPANEL_H + +#include + +//Selection method +enum +{ + SELECT_MODE_NONE, + SELECT_MODE_SIDE, + SELECT_MODE_CENTRE, + SELECT_MODE_CORNER, + SELECT_MODE_END_ENUM +}; + + +enum +{ + CROP_LINK_NONE, + CROP_LINK_LR, + CROP_LINK_LR_FLIP, + CROP_LINK_TB, + CROP_LINK_TB_FLIP, + CROP_LINK_BOTH, + CROP_LINK_BOTH_FLIP, +}; + +class CropPanel : public wxPanel +{ + private: + //!A panel to force the linkage to (link crop border positions) + CropPanel *linkedPanel; + + //!The link mode for the other panel + unsigned int linkMode; + + //!True if event generated programmatically (blocker bool) + bool programmaticEvent; + //!Cropping %ages for window + float crop[4]; + + //Mouse coords and crop coords at drag start (0->1) + float mouseAtDragStart[2]; + float cropAtDragStart[4]; + + //!Selection mode and index for different crop edges/corners/centre + unsigned int selMode,selIndex; + + //!Is the control currently being dragged by the user with the mouse? + bool dragging; + + //!True if the crop array has been modified. + bool hasUpdates; + + bool validCoords() const; + + + void draw() ; + + //!Get the "best" crop widget as defined by coordinates (in 0->1 space) + //returns the index of the selected item as parameter + unsigned int getBestCropWidget(float xMouse,float yMouse, unsigned int &idx) const; + + + DECLARE_EVENT_TABLE(); + public: + CropPanel(wxWindow * parent, wxWindowID id = wxID_ANY, + const wxPoint & pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = wxTAB_TRAVERSAL) ; + + + bool hasUpdate(){return hasUpdates;}; + void clearUpdate(){hasUpdates=false;}; + + void getCropValues(float *array) const; + //!Directly set the crop value, (0->1), index can be 0->3 + void setCropValue(unsigned int index, float v); + + void makeCropValuesValid(); + + //!Link this panel's updates to another. Use CROP_LINK_NONE to disable + void link(CropPanel *otherPanel,unsigned int mode); + + void OnEraseBackground(wxEraseEvent& event); + + void mouseMove(wxMouseEvent& event); + void mouseDown(wxMouseEvent& event); + void mouseReleased(wxMouseEvent& event); + void mouseLeftWindow(wxMouseEvent& event); + void mouseDoubleLeftClick(wxMouseEvent& event); + void onPaint(wxPaintEvent& evt); + void onResize(wxSizeEvent& evt); + + void updateLinked(); + ~CropPanel() {}; +}; +#endif diff -Nru 3depict-0.0.12/src/gui/dialogs/ExportPos.cpp 3depict-0.0.13/src/gui/dialogs/ExportPos.cpp --- 3depict-0.0.12/src/gui/dialogs/ExportPos.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/ExportPos.cpp 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,528 @@ +/* + * ExportPos.cpp - POS file export dialog implementation + * 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 . +*/ + + +#include "ExportPos.h" +#include "wxcommon.h" + +#include "wxcomponents.h" +#include "common/translation.h" + +#include + +// begin wxGlade: ::extracode + +// end wxGlade + +wxWindow *exportPosYieldWindow=0; +bool abortOp; +wxStopWatch *exportPosDelayTime=0; + +bool yieldCallback(bool) +{ + const unsigned int YIELD_MS=75; + + ASSERT(exportPosDelayTime); + //Rate limit the updates + if(exportPosDelayTime->Time() > YIELD_MS) + { + wxSafeYield(exportPosYieldWindow); + exportPosDelayTime->Start(); + } + + return !abortOp; +} + + +using std::list; +using std::pair; + +enum +{ + ID_BTN_ADDDATA=wxID_ANY+1, + ID_BTN_ADDNODE, + ID_BTN_ADDALL, + ID_TREE_FILTERS, + ID_LIST_SELECTED, + ID_LIST_AVAILABLE, + ID_RADIO_VISIBLE, + ID_RADIO_SELECTION, +}; + + +ExportPosDialog::ExportPosDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) + +{ + haveRefreshed=false; + exportVisible=true; + // begin wxGlade: ExportPosDialog::ExportPosDialog + lblExport = new wxStaticText(this, wxID_ANY, wxTRANS("Export:")); + radioVisible = new wxRadioButton(this,ID_RADIO_VISIBLE , wxTRANS("Visible")); + radioSelection = new wxRadioButton(this,ID_RADIO_SELECTION , wxTRANS("Selected Data")); + treeData = new wxTreeCtrl(this, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER); + lblAvailableData = new wxStaticText(this, wxID_ANY, wxTRANS("Available Data")); + listAvailable = new wxListCtrl(this, ID_LIST_AVAILABLE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER|wxLC_VRULES); + btnAddData = new wxButton(this, ID_BTN_ADDDATA, wxT(">")); + btnAddNode = new wxButton(this,ID_BTN_ADDNODE, wxT(">>")); + btnAddAll = new wxButton(this, ID_BTN_ADDALL, wxT(">>>")); + panel_2 = new wxPanel(this, wxID_ANY); + label_4 = new wxStaticText(this, wxID_ANY, wxTRANS("Selection")); + listSelected = new wxListCtrl(this, ID_LIST_SELECTED, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); + btnSave = new wxButton(this, wxID_SAVE, wxEmptyString); + btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + + btnSave->SetFocus(); + + set_properties(); + do_layout(); + // end wxGlade + + //Disable most everything. + enableSelectionControls(false); + + //Assign global variables their init value + //-- + ASSERT(!exportPosYieldWindow); + exportPosYieldWindow=this; + + ASSERT(!exportPosDelayTime); //Should not have been inited yet. + + exportPosDelayTime = new wxStopWatch(); + //-- + + //Add columns to report listviews + listSelected->InsertColumn(0,wxTRANS("Index")); + listSelected->InsertColumn(1,wxTRANS("Count")); + + listAvailable->InsertColumn(0,wxTRANS("Index")); + listAvailable->InsertColumn(1,wxTRANS("Count")); +} + +ExportPosDialog::~ExportPosDialog() +{ + delete exportPosDelayTime; + exportPosDelayTime=0; + exportPosYieldWindow=0; + //Should have called cleanup before exiting. + ASSERT(!haveRefreshed); +} + +BEGIN_EVENT_TABLE(ExportPosDialog, wxDialog) + // begin wxGlade: ExportPosDialog::event_table + EVT_BUTTON(ID_BTN_ADDDATA, ExportPosDialog::OnBtnAddData) + EVT_BUTTON(ID_BTN_ADDNODE, ExportPosDialog::OnBtnAddNode) + EVT_BUTTON(ID_BTN_ADDALL, ExportPosDialog::OnBtnAddAll) + EVT_RADIOBUTTON(ID_RADIO_VISIBLE, ExportPosDialog::OnVisibleRadio) + EVT_RADIOBUTTON(ID_RADIO_SELECTION, ExportPosDialog::OnSelectedRadio) + EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, ExportPosDialog::OnTreeFiltersSelChanged) + EVT_LIST_ITEM_ACTIVATED(ID_LIST_AVAILABLE, ExportPosDialog::OnListAvailableItemActivate) + EVT_LIST_ITEM_ACTIVATED(ID_LIST_SELECTED, ExportPosDialog::OnListSelectedItemActivate) + EVT_LIST_KEY_DOWN(ID_LIST_SELECTED, ExportPosDialog::OnListSelectedItemKeyDown) + EVT_BUTTON(wxID_SAVE, ExportPosDialog::OnSave) + EVT_BUTTON(wxID_CANCEL, ExportPosDialog::OnCancel) + + // end wxGlade +END_EVENT_TABLE() + +void ExportPosDialog::initialiseData(FilterTree &f) +{ + ASSERT(!haveRefreshed) + + //Steal the filter tree contents + f.swap(filterTree); + vector dummyPersist; + upWxTreeCtrl(filterTree,treeData,filterMap,dummyPersist,0); + + ProgressData p; + //TODO: Is trashing the devices a problem? do we have to restore them?? + std::vector *> dummyDevices; + std::vector > consoleStrings; + filterTree.refreshFilterTree(outputData,dummyDevices,consoleStrings,p,yieldCallback); + + //Delete all filter items that came out of refresh, other than ion streams + filterTree.safeDeleteFilterList(outputData,STREAM_TYPE_IONS,true); + + haveRefreshed=true; +} + +void ExportPosDialog::OnVisibleRadio(wxCommandEvent &event) +{ + ASSERT(haveRefreshed); + exportVisible=true; + listAvailable->DeleteAllItems(); + enableSelectionControls(false); +} + + +void ExportPosDialog::OnSelectedRadio(wxCommandEvent &event) +{ + ASSERT(haveRefreshed); + exportVisible=false; + enableSelectionControls(true); +} + + +void ExportPosDialog::OnTreeFiltersSelChanged(wxTreeEvent &event) +{ + wxTreeItemId id; + id=treeData->GetSelection(); + + if(!id.IsOk() || id== treeData->GetRootItem()) + { + event.Skip(); + return; + } + //Tree data contains unique identifier for vis control to do matching + wxTreeItemData *tData=treeData->GetItemData(id); + + //Clear the available list + listAvailable->DeleteAllItems(); + availableFilterData.clear(); + + const Filter *targetFilter=filterMap[((wxTreeUint *)tData)->value]; + + typedef std::pair > filterOutputData; + //Spin through the output list, looking for this filter's contribution + for(list::iterator it=outputData.begin();it!=outputData.end();++it) + { + //Is this the filter we are looking for? + if(it->first == targetFilter) + { + //huzzah. + std::string label; + + for(unsigned int ui=0;uisecond.size();ui++) + { + const IonStreamData *ionData; + ionData=(const IonStreamData *)((it->second)[ui]); + + wxColour c; + c.Set((unsigned char)(ionData->r*255), + (unsigned char)(ionData->g*255),(unsigned char)(ionData->b*255)); + //Add the item using the index as a str + stream_cast(label,ui); + listAvailable->InsertItem(ui,wxStr(label)); + + size_t basicCount; + basicCount=ionData->getNumBasicObjects(); + stream_cast(label,basicCount); + + listAvailable->SetItem(ui,1,wxStr(label)); + + listAvailable->SetItemBackgroundColour(ui,c); + + availableFilterData.push_back((it->second)[ui]); + } + } + + } +} + + +void ExportPosDialog::OnListAvailableItemActivate(wxListEvent &event) +{ + unsigned int item=event.GetIndex(); + + //If the selected item is not already in the "selected filter" list, add it + if(find(selectedFilterData.begin(),selectedFilterData.end(), + availableFilterData[item]) == selectedFilterData.end()) + selectedFilterData.push_back(availableFilterData[item]); + + //Update the selection list + updateSelectedList(); +} + +void ExportPosDialog::OnListSelectedItemActivate(wxListEvent &event) +{ + unsigned int item=event.GetIndex(); + + unsigned int thisIdx=0; + for(list::iterator it=selectedFilterData.begin(); + it!=selectedFilterData.end(); ++it) + { + if(thisIdx == item) + { + selectedFilterData.erase(it); + break; + } + + thisIdx++; + } + + //Update the selection list + updateSelectedList(); + + +} + +void ExportPosDialog::OnListSelectedItemKeyDown(wxListEvent &event) +{ + switch(event.GetKeyCode()) + { + case WXK_DELETE: + { + //Spin through the selected items + int item=-1; + for ( ;; ) + { + item = listSelected->GetNextItem(item, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + if ( item == -1 ) + break; + + list::iterator it; + + it=find(selectedFilterData.begin(),selectedFilterData.end(), + availableFilterData[item]); + //If the selected item is not already in the "selected filter" list, add it + if(it != selectedFilterData.end()) + selectedFilterData.erase(it); + } + + //Update the selection list + updateSelectedList(); + } + + } +} + +void ExportPosDialog::OnBtnAddAll(wxCommandEvent &event) +{ + selectedFilterData.clear(); + typedef std::pair > filterOutputData; + + for(list::iterator it=outputData.begin();it!=outputData.end();++it) + { + for(unsigned int uj=0;ujsecond.size();uj++) + selectedFilterData.push_back(it->second[uj]); + } + + + updateSelectedList(); +} + + +void ExportPosDialog::OnBtnAddData(wxCommandEvent &event) +{ + + int item=-1; + for ( ;; ) + { + item = listAvailable->GetNextItem(item, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + if ( item == -1 ) + break; + + //Disallow addition of duplicate entries + if(find(selectedFilterData.begin(),selectedFilterData.end(), + availableFilterData[item]) == selectedFilterData.end()) + selectedFilterData.push_back(availableFilterData[item]); + } + updateSelectedList(); + +} + +void ExportPosDialog::updateSelectedList() +{ + //Clear the available list + listSelected->DeleteAllItems(); + + unsigned int idx=0; + std::string label; + for(list::iterator it=selectedFilterData.begin(); + it!=selectedFilterData.end(); ++it) + { + const IonStreamData *ionData; + ionData=(const IonStreamData *)(*it); + + wxColour c; + c.Set((unsigned char)(ionData->r*255), + (unsigned char)(ionData->g*255), + (unsigned char)(ionData->b*255)); + //Add the item using the index as a str + stream_cast(label,idx); + listSelected->InsertItem(idx,wxStr(label)); + + size_t basicCount; + basicCount=ionData->getNumBasicObjects(); + stream_cast(label,basicCount); + + listSelected->SetItem(idx,1,wxStr(label)); + + listSelected->SetItemBackgroundColour(idx,c); + + idx++; + } + + + + if(listSelected->GetItemCount()) + { + btnSave->Enable(); + } + else + btnSave->Disable(); +} + +void ExportPosDialog::OnBtnAddNode(wxCommandEvent &event) +{ + + //Spin through the selected items + for (int item=0;itemGetItemCount(); item++) + { + //If the selected item is not already in the "selected filter" list, add it + if(find(selectedFilterData.begin(),selectedFilterData.end(), + availableFilterData[item]) == selectedFilterData.end()) + selectedFilterData.push_back(availableFilterData[item]); + } + + updateSelectedList(); +} + + + +void ExportPosDialog::OnSave(wxCommandEvent &event) +{ + exportVisible=(radioVisible->GetValue()); + EndModal(wxID_OK); +} + +void ExportPosDialog::OnCancel(wxCommandEvent &event) +{ + EndModal(wxID_CANCEL); +} + +void ExportPosDialog::getExportVec(std::vector &v) const +{ + typedef std::pair > filterOutputData; + + //If the user has selected "visible", then all outputs are to be exported + if(exportVisible) + { + v.reserve(outputData.size()); + + for(list::const_iterator it=outputData.begin(); + it!=outputData.end();++it) + { + for(unsigned int ui=0;uisecond.size();ui++) + v.push_back(it->second[ui]); + + } + } + else + { + //If the user wants to perform custom picking, then only "selected" to be + //exported + v.reserve(selectedFilterData.size()); + for(list::const_iterator it=selectedFilterData.begin(); + it!=selectedFilterData.end(); ++it) + { + v.push_back(*it); + } + + } +} + +// wxGlade: add ExportPosDialog event handlers + + +void ExportPosDialog::set_properties() +{ + // begin wxGlade: ExportPosDialog::set_properties + SetTitle(wxTRANS("Export Pos Data")); + // end wxGlade + + treeData->SetToolTip(wxTRANS("Tree of filters, select leaves to show ion data.")); + + btnAddAll->SetToolTip(wxTRANS("Add all data from all filters")); + btnAddNode->SetToolTip(wxTRANS("Add all data from currently selected filter")); + btnAddData->SetToolTip(wxTRANS("Add selected data from currently selected filter")); + radioVisible->SetValue(TRUE); +} + +void ExportPosDialog::enableSelectionControls(bool enabled) + +{ + //Enable/disable controls that are used for selection + treeData->Enable(enabled); + listAvailable->Enable(enabled); + btnAddData->Enable(enabled); + btnAddNode->Enable(enabled); + btnAddAll->Enable(enabled); + listSelected->Enable(enabled); + + //If the selection control is enabled, + //bring the tree back to life + //otherwise, grey it out. + if(enabled) + { + treeData->ExpandAll(); + treeData->SetForegroundColour(wxNullColour); + btnSave->Enable(listSelected->GetItemCount()); + } + else + { + treeData->CollapseAll(); + treeData->SetForegroundColour(*wxLIGHT_GREY); + treeData->Unselect(); + btnSave->Enable(); + } +} + +void ExportPosDialog::do_layout() +{ + // begin wxGlade: ExportPosDialog::do_layout + wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_12 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_13 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_11 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_9 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_10 = new wxBoxSizer(wxVERTICAL); + sizer_4->Add(10, 20, 0, 0, 0); + sizer_9->Add(lblExport, 0, wxTOP|wxBOTTOM, 5); + sizer_9->Add(radioVisible, 0, 0, 0); + sizer_9->Add(radioSelection, 0, 0, 0); + sizer_10->Add(treeData, 1, wxTOP|wxBOTTOM|wxEXPAND, 6); + sizer_10->Add(lblAvailableData, 0, 0, 0); + sizer_10->Add(listAvailable, 1, wxBOTTOM|wxEXPAND, 5); + sizer_9->Add(sizer_10, 1, wxEXPAND, 0); + sizer_4->Add(sizer_9, 1, wxALL|wxEXPAND, 5); + sizer_11->Add(20, 200, 0, 0, 0); + sizer_11->Add(btnAddData, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 10); + sizer_11->Add(btnAddNode, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 10); + sizer_11->Add(btnAddAll, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 10); + sizer_11->Add(panel_2, 1, wxEXPAND, 0); + sizer_4->Add(sizer_11, 0, wxEXPAND, 0); + sizer_12->Add(20, 40, 0, 0, 0); + sizer_12->Add(label_4, 0, wxTOP|wxBOTTOM, 6); + sizer_12->Add(listSelected, 1, wxEXPAND, 0); + sizer_12->Add(20, 20, 0, 0, 0); + sizer_13->Add(20, 20, 1, 0, 0); + sizer_13->Add(btnSave, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_RIGHT|wxALIGN_BOTTOM, 6); + sizer_13->Add(btnCancel, 0, wxBOTTOM|wxALIGN_RIGHT|wxALIGN_BOTTOM, 6); + sizer_12->Add(sizer_13, 0, wxEXPAND, 0); + sizer_4->Add(sizer_12, 1, wxALL|wxEXPAND, 5); + SetSizer(sizer_4); + sizer_4->Fit(this); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/ExportPos.h 3depict-0.0.13/src/gui/dialogs/ExportPos.h --- 3depict-0.0.12/src/gui/dialogs/ExportPos.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/ExportPos.h 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * ExportPos.h - Point data export dialog + * 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 . +*/ + +#include +#include +#include + +#include + +#ifndef EXPORTPOS_H +#define EXPORTPOS_H + +// begin wxGlade: ::dependencies +// end wxGlade + +// begin wxGlade: ::extracode + +// end wxGlade + +#include "backend/viscontrol.h" + + +class ExportPosDialog: public wxDialog { +public: + // begin wxGlade: ExportPosDialog::ids + // end wxGlade + + ExportPosDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + ~ExportPosDialog(); +private: + + + FilterTree filterTree; + + std::map filterMap; + + //!Have we refreshed the filterstream data list? + bool haveRefreshed; + //!Should we be exporting selected ions (false) or visible ions (true) + bool exportVisible; + //!List containing filter and ion streams to export + std::list > > outputData; + //!vector containing currently available filter streams + std::vector availableFilterData; + + //List containing currently selected filter streams + std::list selectedFilterData; + + + //!Use selectedFilterData to draw wx widget + void updateSelectedList(); + // begin wxGlade: ExportPosDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + +protected: + // begin wxGlade: ExportPosDialog::attributes + wxStaticText* lblExport; + wxRadioButton* radioVisible; + wxRadioButton* radioSelection; + wxTreeCtrl* treeData; + wxStaticText* lblAvailableData; + wxListCtrl* listAvailable; + wxButton* btnAddData; + wxButton* btnAddNode; + wxButton* btnAddAll; + wxPanel* panel_2; + wxStaticText* label_4; + wxListCtrl* listSelected; + wxButton* btnSave; + wxButton* btnCancel; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnVisibleRadio(wxCommandEvent &event); // wxGlade: + virtual void OnSelectedRadio(wxCommandEvent &event); // wxGlade: + virtual void OnTreeFiltersSelChanged(wxTreeEvent &event); // wxGlade: + virtual void OnBtnAddAll(wxCommandEvent &event); // wxGlade: + virtual void OnBtnAddData(wxCommandEvent &event); // wxGlade: + virtual void OnBtnAddNode(wxCommandEvent &event); // wxGlade: + virtual void OnSave(wxCommandEvent &event); // wxGlade: + virtual void OnCancel(wxCommandEvent &event); // wxGlade: + virtual void OnListAvailableItemActivate(wxListEvent &event); // wxGlade: + virtual void OnListSelectedItemActivate(wxListEvent &event); // wxGlade: + virtual void OnListSelectedItemKeyDown(wxListEvent &event); // wxGlade: + + void initialiseData(FilterTree &f); + void enableSelectionControls(bool enabled); + void getExportVec(std::vector &v) const; + void swapFilterTree(FilterTree &f) { f.swap(filterTree);haveRefreshed=false;} + +}; // wxGlade: end class + + +#endif // EXPORTPOS_H diff -Nru 3depict-0.0.12/src/gui/dialogs/ExportRngDialog.cpp 3depict-0.0.13/src/gui/dialogs/ExportRngDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/ExportRngDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/ExportRngDialog.cpp 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,273 @@ +/* + * ExportRngDialog.cpp - "Range" data export dialog + * 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 . +*/ + +#include "ExportRngDialog.h" +#include "wxcommon.h" + + +#include "backend/filters/rangeFile.h" + +#include + +// begin wxGlade: ::extracode + +// end wxGlade + +enum +{ + ID_LIST_ACTIVATE=wxID_ANY+1, +}; + +ExportRngDialog::ExportRngDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +{ + // begin wxGlade: ExportRngDialog::ExportRngDialog + lblRanges = new wxStaticText(this, wxID_ANY, wxTRANS("Range Sources")); + listRanges = new wxListCtrl(this, ID_LIST_ACTIVATE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); + label_3 = new wxStaticText(this, wxID_ANY, wxTRANS("Details")); + gridDetails = new wxGrid(this, wxID_ANY); + btnOK = new wxButton(this, wxID_SAVE, wxEmptyString); + btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + btnOK->SetFocus(); + + set_properties(); + do_layout(); + // end wxGlade + + //Add columns to report listviews + listRanges->InsertColumn(0,wxTRANS("Source Filter")); + listRanges->InsertColumn(1,wxTRANS("Ions")); + listRanges->InsertColumn(2,wxTRANS("Ranges")); + +} + + +BEGIN_EVENT_TABLE(ExportRngDialog, wxDialog) + // begin wxGlade: ExportRngDialog::event_table + EVT_LIST_ITEM_ACTIVATED(ID_LIST_ACTIVATE, ExportRngDialog::OnListRangeItemActivate) + EVT_BUTTON(wxID_SAVE, ExportRngDialog::OnSave) + EVT_BUTTON(wxID_CANCEL, ExportRngDialog::OnCancel) + // end wxGlade +END_EVENT_TABLE(); + + +void ExportRngDialog::OnListRangeItemActivate(wxListEvent &event) +{ + updateGrid(event.GetIndex()); + + selectedRange=event.GetIndex(); +} + +void ExportRngDialog::updateGrid(unsigned int index) +{ + const RangeFileFilter *rangeData; + rangeData=(RangeFileFilter *)rngFilters[index]; + + gridDetails->BeginBatch(); + if (gridDetails->GetNumberCols()) + gridDetails->DeleteCols(0,gridDetails->GetNumberCols()); + if (gridDetails->GetNumberRows()) + gridDetails->DeleteRows(0,gridDetails->GetNumberRows()); + + gridDetails->AppendCols(3); + gridDetails->SetColLabelValue(0,wxTRANS("Param")); + gridDetails->SetColLabelValue(1,wxTRANS("Value")); + gridDetails->SetColLabelValue(2,wxTRANS("Value2")); + + unsigned int nRows; + nRows=rangeData->getRange().getNumIons()+rangeData->getRange().getNumRanges() + 4; + gridDetails->AppendRows(nRows); + + + gridDetails->SetCellValue(0,0,wxTRANS("Ion Name")); + gridDetails->SetCellValue(0,1,wxTRANS("Num Ranges")); + unsigned int row=1; + std::string tmpStr; + + unsigned int maxNum; + maxNum=rangeData->getRange().getNumIons(); + //Add ion data, then range data + for(unsigned int ui=0;uiSetCellValue(row,0,wxStr(rangeData->getRange().getName(ui))); + stream_cast(tmpStr,rangeData->getRange().getNumRanges(ui)); + gridDetails->SetCellValue(row,1,wxStr(tmpStr)); + row++; + } + + row++; + gridDetails->SetCellValue(row,0,wxTRANS("Ion")); + gridDetails->SetCellValue(row,1,wxTRANS("Range Start")); + gridDetails->SetCellValue(row,2,wxTRANS("Range end")); + row++; + + maxNum=rangeData->getRange().getNumRanges(); + for(unsigned int ui=0;ui rngPair; + unsigned int ionID; + + rngPair=rangeData->getRange().getRange(ui); + ionID=rangeData->getRange().getIonID(ui); + gridDetails->SetCellValue(row,0, + wxStr(rangeData->getRange().getName(ionID))); + + stream_cast(tmpStr,rngPair.first); + gridDetails->SetCellValue(row,1,wxStr(tmpStr)); + + stream_cast(tmpStr,rngPair.second); + gridDetails->SetCellValue(row,2,wxStr(tmpStr)); + + row++; + } + + gridDetails->EndBatch(); +} + +void ExportRngDialog::OnSave(wxCommandEvent &event) +{ + + if(rngFilters.empty()) + EndModal(wxID_CANCEL); + + //create a file chooser for later. + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save pos..."), wxT(""), + wxT(""),wxTRANS("ORNL format RNG (*.rng)|*.rng|All Files (*)|*"),wxFD_SAVE); + //Show, then check for user cancelling export dialog + if(wxF->ShowModal() == wxID_CANCEL) + { + wxF->Destroy(); + return; + } + + std::string dataFile = stlStr(wxF->GetPath()); + + + if(((RangeFileFilter *)(rngFilters[selectedRange]))-> + getRange().write(dataFile.c_str())) + { + std::string errString; + errString=TRANS("Unable to save. Check output destination can be written to."); + + wxMessageDialog *wxD =new wxMessageDialog(this,wxStr(errString) + ,wxTRANS("Save error"),wxOK|wxICON_ERROR); + wxD->ShowModal(); + wxD->Destroy(); + return; + } + + EndModal(wxID_OK); +} + +void ExportRngDialog::OnCancel(wxCommandEvent &event) +{ + EndModal(wxID_CANCEL); +} +// wxGlade: add ExportRngDialog event handlers + + +void ExportRngDialog::addRangeData(std::vector rangeData) +{ +#ifdef DEBUG + //This function should only receive rangefile filters + for(unsigned int ui=0;uigetType() == FILTER_TYPE_RANGEFILE); +#endif + + rngFilters.resize(rangeData.size()); + std::copy(rangeData.begin(),rangeData.end(),rngFilters.begin()); + + updateRangeList(); + + if(rangeData.size()) + { + //Use the first item to populate the grid + updateGrid(0); + //select the first item + listRanges->SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + + selectedRange=0; + } +} + + +void ExportRngDialog::updateRangeList() +{ + listRanges->DeleteAllItems(); + for(unsigned int ui=0;uiInsertItem(0, wxStr(rangeData->getUserString())); + unsigned int nIons,nRngs; + nIons = rangeData->getRange().getNumIons(); + nRngs = rangeData->getRange().getNumIons(); + + stream_cast(tmpStr,nIons); + listRanges->SetItem(itemIndex, 1, wxStr(tmpStr)); + stream_cast(tmpStr,nRngs); + listRanges->SetItem(itemIndex, 2, wxStr(tmpStr)); + + } +} + +void ExportRngDialog::set_properties() +{ + // begin wxGlade: ExportRngDialog::set_properties + SetTitle(wxTRANS("Export Range")); + gridDetails->CreateGrid(0, 0); + gridDetails->SetRowLabelSize(0); + gridDetails->SetColLabelSize(0); + + listRanges->SetToolTip(wxTRANS("List of rangefiles in filter tree")); + gridDetails->EnableEditing(false); + gridDetails->SetToolTip(wxTRANS("Detailed view of selected range")); + // end wxGlade +} + + +void ExportRngDialog::do_layout() +{ + // begin wxGlade: ExportRngDialog::do_layout + wxBoxSizer* sizer_2 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_14 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_15 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_16 = new wxBoxSizer(wxVERTICAL); + sizer_16->Add(lblRanges, 0, wxLEFT|wxTOP, 5); + sizer_16->Add(listRanges, 1, wxALL|wxEXPAND, 5); + sizer_14->Add(sizer_16, 1, wxEXPAND, 0); + sizer_14->Add(10, 20, 0, 0, 0); + sizer_15->Add(label_3, 0, wxLEFT|wxTOP, 5); + sizer_15->Add(gridDetails, 1, wxALL|wxEXPAND, 5); + sizer_14->Add(sizer_15, 1, wxEXPAND, 0); + sizer_2->Add(sizer_14, 1, wxEXPAND, 0); + sizer_3->Add(20, 20, 1, 0, 0); + sizer_3->Add(btnOK, 0, wxALL, 5); + sizer_3->Add(btnCancel, 0, wxALL, 5); + sizer_2->Add(sizer_3, 0, wxEXPAND, 0); + SetSizer(sizer_2); + sizer_2->Fit(this); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/ExportRngDialog.h 3depict-0.0.13/src/gui/dialogs/ExportRngDialog.h --- 3depict-0.0.12/src/gui/dialogs/ExportRngDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/ExportRngDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * ExportRngDialog.h - Range data export dialog + * Copyright (C) 2012, 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 . +*/ + +#ifndef EXPORTRNGDIALOG_H +#define EXPORTRNGDIALOG_H + +#include +// begin wxGlade: ::dependencies +#include +// end wxGlade + +#include + +#include "backend/viscontrol.h" +class ExportRngDialog: public wxDialog { +public: + // begin wxGlade: ExportRngDialog::ids + // end wxGlade + + ExportRngDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + +private: + //!Vis controller pointer FIXME: Can we downgrade this to const? + VisController *visControl; + //!vector containing currently available filter streams + std::vector rngFilters; + + // begin wxGlade: ExportRngDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //!Use filter data to draw wx widget + void updateRangeList(); + //!Draw details of selected range into grid + void updateGrid(unsigned int index); + + unsigned int selectedRange; +protected: + // begin wxGlade: ExportRngDialog::attributes + wxStaticText* lblRanges; + wxListCtrl* listRanges; + wxStaticText* label_3; + wxGrid* gridDetails; + wxButton* btnOK; + wxButton* btnCancel; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnListRangeItemActivate(wxListEvent &event); // wxGlade: + virtual void OnSave(wxCommandEvent &event); // wxGlade: + virtual void OnCancel(wxCommandEvent &event); // wxGlade: + + void addRangeData(std::vector rangeData); + +}; // wxGlade: end class + + +#endif // EXPORTRNGDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/StashDialog.cpp 3depict-0.0.13/src/gui/dialogs/StashDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/StashDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/StashDialog.cpp 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,396 @@ +/* + * StashDialog.cpp - filter "Stash" tree editing and viewing dialog + * 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 . +*/ + +#include "StashDialog.h" + +#include "wxcommon.h" +#include "wxcomponents.h" +#include "common/translation.h" + + +using std::pair; +using std::string; +using std::stack; +// begin wxGlade: ::extracode + +// end wxGlade + +enum +{ + ID_TREE_FILTERS=wxID_ANY+1, + ID_GRID_FILTER, + ID_LIST_STASH, +}; + +StashDialog::StashDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, style) +{ + // begin wxGlade: StashDialog::StashDialog + label_5 = new wxStaticText(this, wxID_ANY, wxTRANS("Stashes")); + listStashes = new wxListCtrl(this, ID_LIST_STASH, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); + btnRemove = new wxButton(this, wxID_REMOVE, wxEmptyString); + label_6 = new wxStaticText(this, wxID_ANY, wxTRANS("Stashed Tree")); + treeFilters = new wxTreeCtrl(this, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_HIDE_ROOT); + label_7 = new wxStaticText(this, wxID_ANY, wxTRANS("Properties")); + gridProperties = new wxPropertyGrid(this, ID_GRID_FILTER); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + + set_properties(); + do_layout(); + // end wxGlade + gridProperties->CreateGrid(0, 2); + +} + +void StashDialog::ready() +{ + updateList(); + updateGrid(); + updateTree(); +} + +BEGIN_EVENT_TABLE(StashDialog, wxDialog) + // begin wxGlade: StashDialog::event_table + EVT_LIST_KEY_DOWN(ID_LIST_STASH, StashDialog::OnListKeyDown) + EVT_BUTTON(wxID_REMOVE, StashDialog::OnBtnRemove) + EVT_LIST_ITEM_SELECTED(ID_LIST_STASH, StashDialog::OnListSelected) + EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, StashDialog::OnTreeSelChange) + EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_FILTER,StashDialog::OnGridEditor) + // end wxGlade +END_EVENT_TABLE(); + +void StashDialog::setVisController(VisController *s) +{ + visControl=s; +} + +void StashDialog::set_properties() +{ + // begin wxGlade: StashDialog::set_properties + SetTitle(wxTRANS("Stashed Trees")); + SetSize(wxSize(600, 430)); + + btnRemove->SetToolTip(wxTRANS("Erase stashed item")); + treeFilters->SetToolTip(wxTRANS("Filter view for current stash")); + gridProperties->SetToolTip(wxTRANS("Settings for selected filter in current stash")); + listStashes->SetToolTip(wxTRANS("Available stashes")); + // end wxGlade +} + +void StashDialog::OnGridEditor(wxGridEvent &evt) +{ + evt.Veto(); +} + +void StashDialog::OnListKeyDown(wxListEvent &event) +{ + switch(event.GetKeyCode()) + { + case WXK_DELETE: + { + //Spin through the selected items + int item=-1; + for ( ;; ) + { + item = listStashes->GetNextItem(item, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + if ( item == -1 ) + break; + + visControl->deleteStash(listStashes->GetItemData(item)); + } + + //Update the filter list + updateList(); + updateTree(); + updateGrid(); + } + + } +} + +void StashDialog::OnListSelected(wxListEvent &event) +{ + updateTree(); + updateGrid(); +} + +void StashDialog::OnTreeSelChange(wxTreeEvent &event) +{ + updateGrid(); +} + +void StashDialog::updateList() +{ + //Generate the stash selection list + // + vector > stashes; + + visControl->getStashes(stashes); + + //Clear the existing list + listStashes->ClearAll(); + + //Fill it with "stash" entries + //Add columns to report listviews + listStashes->InsertColumn(0,wxTRANS("Stash Name"),3); + listStashes->InsertColumn(1,wxTRANS("Filter Count"),1); + for (unsigned int ui=0; uiInsertItem(ui,wxStr(stashes[ui].first)); + + //Second column is num filters + + visControl->getStashTree(stashes[ui].second,t); + stream_cast(strTmp,t.size()); + listStashes->SetItem(ui,1,wxStr(strTmp)); + + //Set the stash ID as the list data item + //this is the key to the stash val + listStashes->SetItemData(itemIdx,stashes[ui].second); + } + +} + +void StashDialog::updateGrid() +{ + gridProperties->clear(); + if(!treeFilters->GetCount()) + return; + //Get the selection from the current tree + wxTreeItemId id; + id=treeFilters->GetSelection(); + + if(!id.IsOk() || id == treeFilters->GetRootItem()) + return; + + unsigned int stashId; + + //Retrieve the stash ID + if(!getStashIdFromList(stashId)) + return; + + //Tree data contains unique identifier for vis control to do matching + wxTreeItemData *tData=treeFilters->GetItemData(id); + + unsigned int filterIdx = ((wxTreeUint *)tData)->value; + + FilterTree t; + visControl->getStashTree(stashId,t); + + Filter *targetFilter=0; + unsigned int pos=0; + //Spin through the tree iterators until we hit the target index + for(tree::iterator it=t.depthBegin();it!=t.depthEnd(); ++it) + { + if(pos == filterIdx) + { + targetFilter=*it; + break; + } + pos++; + } + + ASSERT(targetFilter); + + FilterPropGroup p; + targetFilter->getProperties(p); + + gridProperties->clearKeys(); + gridProperties->setNumGroups(p.numGroups()); + //Create the keys for the property grid to do its thing + for(unsigned int ui=0;ui propGrouping; + p.getGroup(ui,propGrouping); + + for(size_t uj=0;ujaddKey(propGrouping[uj].name,ui, + propGrouping[uj].key, + propGrouping[uj].type, + propGrouping[uj].data, + propGrouping[uj].helpText); + } + } + + //Let the property grid layout what it needs to + gridProperties->propertyLayout(); + +} + +bool StashDialog::getStashIdFromList(unsigned int &stashId) +{ + //Get the currently selected item + //Spin through the selected items + int item=-1; + unsigned int numItems=0; + for ( ;; ) + { + item = listStashes->GetNextItem(item, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + if ( item == -1 ) + break; + numItems++; + } + + //error if not only a single selected + if(numItems !=1) + return false; + + item=-1; + item = listStashes->GetNextItem(item, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + + stashId = listStashes->GetItemData(item); + + + return true; +} + +void StashDialog::updateTree() +{ + treeFilters->DeleteAllItems(); + + unsigned int stashId; + + //Get the selected stash and build the tree control + if(!getStashIdFromList(stashId)) + return; + + visControl->getStashTree(stashId,curTree); + + + uniqueIds.clear(); + //REBUILD TREE + //===== + stack treeIDs; + wxTreeItemId visibleTreeId; + //Warning: this generates an event, + //most of the time (some windows versions do not according to documentation) + treeFilters->DeleteAllItems(); + filterTreeMapping.clear(); + + int lastDepth=0; + //Add dummy root node. This will be invisible to wxTR_HIDE_ROOT controls + wxTreeItemId tid; + tid=treeFilters->AddRoot(wxT("TreeBase")); + unsigned int curTreePos=0; + + // Push on stack to prevent underflow, but don't keep a copy, + // as we will never insert or delete this from the UI + treeIDs.push(tid); + + //Depth first add + unsigned int pos=0; + for(tree::pre_order_iterator filtIt=curTree.depthBegin(); + filtIt!=curTree.depthEnd(); ++filtIt) + { + //Push or pop the stack to make it match the iterator position + if( lastDepth > curTree.depth(filtIt)) + { + while(curTree.depth(filtIt) +1 < (int)treeIDs.size()) + treeIDs.pop(); + } + else if( lastDepth < curTree.depth(filtIt)) + { + treeIDs.push(tid); + } + + + lastDepth=curTree.depth(filtIt); + + //This will use the user label or the type string. + tid=treeFilters->AppendItem(treeIDs.top(), + wxStr((*filtIt)->getUserString())); + + treeFilters->SetItemData(tid,new wxTreeUint(pos)); + pos++; + + //Record mapping to filter for later reference + filterTreeMapping.push_back(std::make_pair(curTreePos,*filtIt)); + + curTreePos++; + } + //===== + + + +} + +void StashDialog::OnBtnRemove(wxCommandEvent &event) +{ + //Spin through the list, to find the selected items + int item=-1; + for ( ;; ) + { + item = listStashes->GetNextItem(item, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + if ( item == -1 ) + break; + + visControl->deleteStash(listStashes->GetItemData(item)); + updateList(); + updateTree(); + updateGrid(); + + } + + +} + +void StashDialog::do_layout() +{ + // begin wxGlade: StashDialog::do_layout + wxBoxSizer* sizer_17 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_19 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_18 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_21 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_20 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_22 = new wxBoxSizer(wxHORIZONTAL); + sizer_17->Add(9, 8, 0, 0, 0); + sizer_20->Add(label_5, 0, wxLEFT, 5); + sizer_20->Add(listStashes, 1, wxLEFT|wxRIGHT|wxEXPAND, 5); + sizer_22->Add(btnRemove, 0, wxLEFT|wxALIGN_RIGHT, 6); + sizer_20->Add(sizer_22, 0, wxTOP|wxEXPAND, 8); + sizer_18->Add(sizer_20, 1, wxLEFT|wxEXPAND, 5); + sizer_18->Add(15, 20, 0, 0, 0); + sizer_21->Add(label_6, 0, 0, 4); + sizer_21->Add(treeFilters, 1, wxRIGHT|wxEXPAND, 5); + sizer_21->Add(label_7, 0, wxTOP, 10); + sizer_21->Add(gridProperties, 1, wxRIGHT|wxBOTTOM|wxEXPAND, 5); + sizer_18->Add(sizer_21, 1, wxRIGHT|wxEXPAND, 5); + sizer_17->Add(sizer_18, 1, wxEXPAND, 0); + sizer_17->Add(20, 20, 0, 0, 0); + sizer_19->Add(20, 20, 1, 0, 0); + sizer_19->Add(btnOK, 0, wxALL, 5); + sizer_17->Add(sizer_19, 0, wxEXPAND, 0); + SetSizer(sizer_17); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/StashDialog.h 3depict-0.0.13/src/gui/dialogs/StashDialog.h --- 3depict-0.0.12/src/gui/dialogs/StashDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/StashDialog.h 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * stashdialog.h - "Stash" filter storage edit dialog 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 . +*/ + + +#ifndef STASHDIALOG_H +#define STASHDIALOG_H + +#include +#include +#include + + +#include "backend/viscontrol.h" +// end wxGlade + +// begin wxGlade: ::extracode +#include +// end wxGlade + + +class StashDialog: public wxDialog { +public: + // begin wxGlade: StashDialog::ids + // end wxGlade + + + StashDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + + void setVisController(VisController *s); + +private: + + FilterTree curTree; + std::vector > filterTreeMapping; + UniqueIDHandler uniqueIds; + // begin wxGlade: StashDialog::methods + void set_properties(); + void do_layout(); + void updateList(); + void updateGrid(); + void updateTree(); + + bool getStashIdFromList(unsigned int &stashId); + // end wxGlade + + VisController *visControl; +protected: + // begin wxGlade: StashDialog::attributes + wxStaticText* label_5; + wxListCtrl* listStashes; + wxButton* btnRemove; + wxStaticText* label_6; + wxTreeCtrl* treeFilters; + wxStaticText* label_7; + wxPropertyGrid* gridProperties; + wxButton* btnOK; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnListKeyDown(wxListEvent &event); // wxGlade: + virtual void OnListSelected(wxListEvent &event); // wxGlade: + virtual void OnTreeSelChange(wxTreeEvent &event); // wxGlade: + virtual void OnGridEditor(wxGridEvent &event); + + virtual void OnBtnRemove(wxCommandEvent &event); + void ready(); +}; // wxGlade: end class + + + +#endif // STASHDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/animateFilterDialog.cpp 3depict-0.0.13/src/gui/dialogs/animateFilterDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/animateFilterDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateFilterDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,1220 @@ +/* + * animateFilterDialog.cpp - Framewise animation of filter properties + * 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 . +*/ +// -*- C++ -*- generated by wxGlade b48da20df8f4++ on Mon May 7 22:48:14 2012 + +#include "animateFilterDialog.h" +#include "resolutionDialog.h" + + +#include "./animateSubDialogs/realKeyFrameDialog.h" +#include "./animateSubDialogs/colourKeyFrameDialog.h" +#include "./animateSubDialogs/stringKeyFrameDialog.h" +#include "./animateSubDialogs/choiceKeyFrameDialog.h" +// begin wxGlade: ::extracode + +// end wxGlade + +#include +#include "common/translation.h" +#include "common/stringFuncs.h" +#include "wxcomponents.h" + +enum +{ + ID_FILTER_TREE_CTRL, + ID_PROPERTY_GRID, + ID_ANIMATION_GRID_CTRL, + ID_BUTTON_FRAME_REMOVE, + ID_TEXTBOX_WORKDIR, + ID_BUTTON_WORKDIR, + ID_CHECK_IMAGE_OUT, + ID_TEXTBOX_IMAGEPREFIX, + ID_TEXTBOX_IMAGESIZE, + ID_BUTTON_IMAGE_RES, + ID_CHECK_ONLYDATACHANGE, + ID_CHECK_POINT_OUT, + ID_CHECK_PLOT_OUT, + ID_CHECK_VOXEL_OUT, + ID_CHECK_RANGE_OUT, + ID_COMBO_RANGE_TYPE, + ID_SPLIT_FILTERVIEW, + ID_FRAME_SLIDER, + ID_FRAME_TEXTBOX, + ID_BTN_OK, + ID_BTN_CANCEL, + ID_FILTER_PROPERTY_VALUE_GRID +}; +enum +{ + CELL_FILTERNAME, + CELL_PROPERTYNAME, + CELL_KEYINTERPMODE, + CELL_STARTFRAME, + CELL_ENDFRAME +}; + +enum +{ + FRAME_CELL_FILTERNAME, + FRAME_CELL_PROPNAME, + FRAME_CELL_VALUE +}; + +const size_t RANGE_FORMAT_NUM_OPTIONS=3; + + +//TODO: This should be merged into aptclasses? +const char *extension[RANGE_FORMAT_NUM_OPTIONS] = +{ + "rng", + "rrng", + "env" +}; + +const char * comboRange_choices[RANGE_FORMAT_NUM_OPTIONS] = +{ + NTRANS("Oak-Ridge RNG"), + NTRANS("Cameca/Ametek RRNG"), + NTRANS("Cameca/Ametek ENV") +}; + +using std::string; +using std::cout; +using std::endl; + + +template +bool getRealKeyFrame(FrameProperties &frameProp, + FilterProperty &filterProp, RealKeyFrameDialog *r) +{ + if( r->ShowModal() != wxID_OK) + { + r->Destroy(); + return false; + } + + //Copy out the data obtained from the dialog + size_t transitionMode; + T value; + transitionMode=r->getTransitionMode(); + frameProp.setInterpMode(transitionMode); + + value=r->getStartValue(); + stream_cast(filterProp.data,value); + + frameProp.addKeyFrame(r->getStartFrame(),filterProp); + + //Add end value as needed + switch(transitionMode) + { + case TRANSITION_STEP: + break; + case TRANSITION_INTERP: + value=r->getEndValue(); + stream_cast(filterProp.data,value); + frameProp.addKeyFrame(r->getEndFrame(),filterProp); + break; + default: + ASSERT(false); + } + + r->Destroy(); + + return true; +} + +ExportAnimationDialog::ExportAnimationDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX) +{ + // begin wxGlade: ExportAnimationDialog::ExportAnimationDialog + viewNotebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); + frameViewPane = new wxPanel(viewNotebook, wxID_ANY); + filterViewPane = new wxPanel(viewNotebook, wxID_ANY); + splitPaneFilter = new wxSplitterWindow(filterViewPane, ID_SPLIT_FILTERVIEW, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); + filterRightPane = new wxPanel(splitPaneFilter, wxID_ANY); + filterLeftPane = new wxPanel(splitPaneFilter, wxID_ANY); + keyFramesSizer_staticbox = new wxStaticBox(filterRightPane, -1, wxTRANS("Key frames")); + outputDataSizer_staticbox = new wxStaticBox(frameViewPane, -1, wxTRANS("Output Data")); + filterPropertySizer_staticbox = new wxStaticBox(filterLeftPane, -1, wxTRANS("Filters and properties")); + filterTreeCtrl =new wxTreeCtrl(filterLeftPane,ID_FILTER_TREE_CTRL , wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_EDIT_LABELS); + + propertyGrid = new wxPropertyGrid(filterLeftPane, ID_PROPERTY_GRID); + animationGrid = new wxGrid(filterRightPane, ID_ANIMATION_GRID_CTRL); + keyFrameRemoveButton = new wxButton(filterRightPane, wxID_REMOVE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + labelWorkDir = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Dir : ")); + textWorkDir = new wxTextCtrl(frameViewPane, ID_TEXTBOX_WORKDIR, wxEmptyString); + buttonWorkDir = new wxButton(frameViewPane, wxID_OPEN, wxEmptyString); + checkOutOnlyChanged = new wxCheckBox(frameViewPane, ID_CHECK_ONLYDATACHANGE, wxTRANS("Output only when refresh required")); + outputDataSepLine = new wxStaticLine(frameViewPane, wxID_ANY); + labelDataType = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Data Types:")); + checkImageOutput = new wxCheckBox(frameViewPane, ID_CHECK_IMAGE_OUT, wxTRANS("3D Images")); + lblImageName = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("File Prefix: ")); + textImageName = new wxTextCtrl(frameViewPane, ID_TEXTBOX_IMAGEPREFIX, wxEmptyString); + labelImageSize = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Size : ")); + textImageSize = new wxTextCtrl(frameViewPane, ID_TEXTBOX_IMAGESIZE, wxEmptyString); + buttonImageSize = new wxButton(frameViewPane, ID_BUTTON_IMAGE_RES, wxTRANS("...")); + checkPoints = new wxCheckBox(frameViewPane, ID_CHECK_POINT_OUT, wxTRANS("Point data")); + checkPlotData = new wxCheckBox(frameViewPane, ID_CHECK_PLOT_OUT, wxTRANS("Plots")); + checkVoxelData = new wxCheckBox(frameViewPane, ID_CHECK_VOXEL_OUT, wxTRANS("Voxel data")); + checkRangeData = new wxCheckBox(frameViewPane, ID_CHECK_RANGE_OUT, wxTRANS("Range files")); + labelRangeFormat = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Format")); + + //Workaround for wx bug http://trac.wxwidgets.org/ticket/4398 + wxSortedArrayString rangeNames; + for(unsigned int ui=0;uicomboRange_choices offset. + rangeMap[TRANS(str)] = ui; + //Add to filter name wxArray + wxString wxStrTrans = wxTRANS(str); + rangeNames.Add(wxStrTrans); + } + comboRangeFormat = new wxChoice(frameViewPane, ID_COMBO_RANGE_TYPE, wxDefaultPosition, wxDefaultSize, rangeNames); + static_line_1 = new wxStaticLine(frameViewPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + labelFrame = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Frame")); + frameSlider = new wxSlider(frameViewPane, ID_FRAME_SLIDER, 1, 1, 1); + textFrame = new wxTextCtrl(frameViewPane, ID_FRAME_TEXTBOX, wxEmptyString); + framePropGrid = new wxGrid(frameViewPane, ID_FILTER_PROPERTY_VALUE_GRID); + cancelButton = new wxButton(this, wxID_CANCEL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + okButton = new wxButton(this, wxID_OK, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + + + set_properties(); + do_layout(); + // end wxGlade + + +#if wxCHECK_VERSION(2,9,0) + //Manually tuned splitter parameters + splitPaneFilter->SetMinimumPaneSize(220); + int w, h; + GetClientSize(&w,&h); + + float sashFrac=0.4; + + splitPaneFilter->SetSashPosition((int)(sashFrac*w)); +#endif + + programmaticEvent=true; + + //-- set up the default properties for dialog back-end data + imageWidth=640; + imageHeight=480; + imageSizeOK=true; + + //Plot check status + wantPlotOutput=checkPlotData->IsChecked(); + wantImageOutput=checkImageOutput->IsChecked(); + wantIonOutput=checkPoints->IsChecked(); + wantPlotOutput=checkPlotData->IsChecked(); + wantVoxelOutput=checkVoxelData->IsChecked(); + wantRangeOutput=checkRangeData->IsChecked(); + wantOnlyChanges=checkOutOnlyChanged->IsChecked(); + + string sFirst,sSecond; + stream_cast(sFirst,imageWidth); + stream_cast(sSecond,imageHeight); + textImageSize->SetValue(wxStr(string(sFirst+string("x")+sSecond))); + textImageSize->SetBackgroundColour(wxNullColour); + + comboRangeFormat->Enable(checkRangeData->IsChecked()); + + currentFrame=0; + existsConflicts=false; + //--- + + programmaticEvent=false; +} + +ExportAnimationDialog::~ExportAnimationDialog() +{ + filterTree=0; +} + +BEGIN_EVENT_TABLE(ExportAnimationDialog, wxDialog) + // begin wxGlade: ExportAnimationDialog::event_table + EVT_TREE_SEL_CHANGED(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnFilterTreeCtrlSelChanged) + EVT_GRID_CMD_EDITOR_SHOWN(ID_PROPERTY_GRID, ExportAnimationDialog::OnFilterGridCellEditorShow) + EVT_GRID_CMD_EDITOR_SHOWN(ID_ANIMATION_GRID_CTRL, ExportAnimationDialog::OnFrameGridCellEditorShow) + EVT_GRID_CMD_EDITOR_SHOWN(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnAnimateGridCellEditorShow) + EVT_SPLITTER_UNSPLIT(ID_SPLIT_FILTERVIEW, ExportAnimationDialog::OnFilterViewUnsplit) + EVT_BUTTON(wxID_REMOVE, ExportAnimationDialog::OnButtonKeyFrameRemove) + EVT_TEXT(ID_TEXTBOX_WORKDIR, ExportAnimationDialog::OnOutputDirText) + EVT_BUTTON(wxID_OPEN, ExportAnimationDialog::OnButtonWorkDir) + EVT_CHECKBOX(ID_CHECK_ONLYDATACHANGE, ExportAnimationDialog::OnCheckOutDataChange) + EVT_CHECKBOX(ID_CHECK_IMAGE_OUT, ExportAnimationDialog::OnCheckImageOutput) + EVT_TEXT(ID_TEXTBOX_IMAGEPREFIX, ExportAnimationDialog::OnImageFilePrefix) + EVT_TEXT(ID_TEXTBOX_IMAGESIZE, ExportAnimationDialog::OnTextImageSize) + EVT_BUTTON(ID_BUTTON_IMAGE_RES, ExportAnimationDialog::OnBtnResolution) + EVT_CHECKBOX(ID_CHECK_POINT_OUT, ExportAnimationDialog::OnCheckPointOutput) + EVT_CHECKBOX(ID_CHECK_PLOT_OUT, ExportAnimationDialog::OnCheckPlotOutput) + EVT_CHECKBOX(ID_CHECK_VOXEL_OUT, ExportAnimationDialog::OnCheckVoxelOutput) + EVT_CHECKBOX(ID_CHECK_RANGE_OUT, ExportAnimationDialog::OnCheckRangeOutput) + EVT_CHOICE(ID_COMBO_RANGE_TYPE, ExportAnimationDialog::OnRangeTypeCombo) + EVT_COMMAND_SCROLL(ID_FRAME_SLIDER, ExportAnimationDialog::OnFrameViewSlider) + EVT_TEXT(ID_FRAME_TEXTBOX, ExportAnimationDialog::OnTextFrame) + EVT_BUTTON(ID_BTN_CANCEL, ExportAnimationDialog::OnButtonCancel) + EVT_BUTTON(ID_BTN_OK, ExportAnimationDialog::OnButtonOK) + // end wxGlade +END_EVENT_TABLE(); + + +bool ExportAnimationDialog::getModifiedTree(size_t frame, FilterTree &t,bool &needsUp) const +{ + vector propsAtFrame; + vector propIds; + + propertyAnimator.getPropertiesAtFrame(frame,propIds,propsAtFrame); + + needsUp=false; + for(size_t ui=0;ui dummyVec; + upWxTreeCtrl(*filterTree,filterTreeCtrl,filterMap, + dummyVec,NULL); + + update(); +} + +void ExportAnimationDialog::updateFilterViewGrid() +{ + //Empty the grid + animationGrid->BeginBatch(); + if(animationGrid->GetNumberRows()) + animationGrid->DeleteRows(0,animationGrid->GetNumberRows()); + animationGrid->EndBatch(); + + + animationGrid->AppendRows(propertyAnimator.getNumProps()); + for(size_t ui=0;uigetProperties(filtPropGroup); + FilterProperty filtProp; + filtProp=filtPropGroup.getPropValue(frameProps.getPropertyKey()); + + animationGrid->SetCellValue(ui,CELL_FILTERNAME, + wxStr(filterPtr->getUserString())); + animationGrid->SetCellValue(ui,CELL_PROPERTYNAME, + wxStr(filtProp.name)); + animationGrid->SetCellValue(ui,CELL_KEYINTERPMODE, + wxCStr(INTERP_NAME[frameProps.getInterpMode()])); + + string str; + stream_cast(str,frameProps.getMinFrame()); + animationGrid->SetCellValue(ui,CELL_STARTFRAME, wxStr(str)); + stream_cast(str,frameProps.getMaxFrame()); + animationGrid->SetCellValue(ui,CELL_ENDFRAME, wxStr(str)); + } + + //Check for conflicting rows in the animation dialog, + // and highlight them in colour + set conflictRows; + if(!propertyAnimator.checkSelfConsistent(conflictRows)) + { + existsConflicts=true; + for(std::set::const_iterator it=conflictRows.begin(); + it!=conflictRows.end();++it) + { + wxGridCellAttr *colourRowAttr=new wxGridCellAttr; + colourRowAttr->SetBackgroundColour(wxColour(*wxCYAN)); + animationGrid->SetRowAttr(*it,colourRowAttr); + } + } +} + +void ExportAnimationDialog::updateFrameViewGrid() +{ + ASSERT(currentFrame <= frameSlider->GetMax()); + + //Empty the grid + framePropGrid->BeginBatch(); + if(framePropGrid->GetNumberRows()) + framePropGrid->DeleteRows(0,animationGrid->GetNumberRows()); + framePropGrid->EndBatch(); + + std::set conflictProps; + if(!propertyAnimator.checkSelfConsistent(conflictProps)) + return; + + vector alteredProperties; + vector propertyIds; + //Grab the properties that have been modified from their initial value + // and then refill the grid with this data + propertyAnimator.getPropertiesAtFrame(currentFrame, + propertyIds,alteredProperties); + + framePropGrid->AppendRows(alteredProperties.size()); + + for(size_t ui=0; uigetUserString(); + + + FilterPropGroup p; + FilterProperty prop; + //obtain filter properties + filterMap.at(idFilter)->getProperties(p); + prop=p.getPropValue(alteredProperties[ui].getPropertyKey()); + propertyName=prop.name; + + + std::string animatedValue; + animatedValue=propertyAnimator.getInterpolatedFilterData( + alteredProperties[ui].getFilterId(),prop.key,currentFrame); + //-- + + //Modify the grid properties with the appropriate data + framePropGrid->SetCellValue(ui,FRAME_CELL_FILTERNAME, + wxStr(filterName)); + framePropGrid->SetCellValue(ui,FRAME_CELL_PROPNAME, + wxStr(propertyName)); + framePropGrid->SetCellValue(ui,FRAME_CELL_VALUE, + wxStr(animatedValue)); + } + +} + +void ExportAnimationDialog::updateFrameViewSlider() +{ + + programmaticEvent=true; + + //reset the range on the frame slider + size_t maxFrameVal; + maxFrameVal=propertyAnimator.getMaxFrame(); + frameSlider->SetMin(0); + frameSlider->SetMax(maxFrameVal); + + //Update the textbox + std::string textCurrent,textMax; + stream_cast(textCurrent,frameSlider->GetValue()); + stream_cast(textMax,propertyAnimator.getMaxFrame()); + + textCurrent= (textCurrent + std::string("/") + textMax); + textFrame->SetValue( wxStr(textCurrent)); + + programmaticEvent=false; + +} + +void ExportAnimationDialog::OnTextFrame(wxCommandEvent &event) +{ + if(programmaticEvent) + return; + + string s; + s=stlStr(textFrame->GetValue()); + + bool parseOK=true; + size_t pos; + size_t frameCur; + pos = s.find('/'); + if(pos==string::npos) + parseOK=false; + else + { + string first,last; + first = s.substr(0,pos); + last=s.substr(pos+1); + + + if(stream_cast(frameCur,first)) + parseOK=false; + + + size_t frameEnd; + if(stream_cast(frameEnd,last)) + parseOK=false; + } + + if(!parseOK) + textFrame->SetBackgroundColour(*wxCYAN); + else + { + textFrame->SetBackgroundColour(wxNullColour); + + currentFrame=frameCur; + + updateFrameViewGrid(); + } + imageSizeOK=parseOK; + + update(); +} + +void ExportAnimationDialog::OnFrameViewSlider(wxScrollEvent &event) +{ + programmaticEvent=true; + size_t sliderVal=frameSlider->GetValue(); + + + std::string frameText,tmp; + stream_cast(frameText,sliderVal); + frameText+= "/"; + stream_cast(tmp,frameSlider->GetMax()); + frameText+=tmp; + + textFrame->SetValue( wxStr(frameText)); + + currentFrame=sliderVal; + updateFrameViewGrid(); + programmaticEvent=false; +} + +void ExportAnimationDialog::OnButtonCancel(wxCommandEvent &event) +{ + event.Skip(); +} + +void ExportAnimationDialog::update() +{ + programmaticEvent=true; + updateFilterViewGrid(); + updateFrameViewGrid(); + updateFrameViewSlider(); + updateOKButton(); + programmaticEvent=false; +} + +void ExportAnimationDialog::OnFilterTreeCtrlSelChanged(wxTreeEvent &event) +{ + //Get the parent filter pointer + wxTreeItemId id=filterTreeCtrl->GetSelection();; + + if(id !=filterTreeCtrl->GetRootItem() && id.IsOk()) + { + wxTreeItemData *parentData=filterTreeCtrl->GetItemData(id); + updateFilterPropertyGrid(propertyGrid, + filterMap[((wxTreeUint *)parentData)->value]); + } + + event.Skip(); +} + + +void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event) +{ + event.Veto(); + wxTreeItemId id=filterTreeCtrl->GetSelection();; + + if(id ==filterTreeCtrl->GetRootItem() || !id.IsOk()) + return; + + + unsigned int key; + key=propertyGrid->getKeyFromRow(event.GetRow()); + + //Get the filter ID value + size_t filterId; + wxTreeItemId tId = filterTreeCtrl->GetSelection(); + if(!tId.IsOk()) + return; + + wxTreeItemData *tData=filterTreeCtrl->GetItemData(tId); + filterId = ((wxTreeUint *)tData)->value; + + const Filter *f; + f=filterMap.at(filterId); + + //Obtain the filter property that was selected by the user + //-- + FilterPropGroup propGroup; + f->getProperties(propGroup); + + FilterProperty filterProp; + filterProp=propGroup.getPropValue(key); + //-- + + //Create a property entry for this, and get values from user + FrameProperties frameProp(filterId,key); + switch(filterProp.type) + { + case PROPERTY_TYPE_BOOL: + { + wxTextEntryDialog *teD = new wxTextEntryDialog(this,wxTRANS("transition frame"),wxTRANS("Frame count"), + wxT("0"),(long int)wxOK|wxCANCEL); + + std::string s; + size_t frameValue; + do + { + if(teD->ShowModal() == wxID_CANCEL) + { + teD->Destroy(); + return; + } + + s=stlStr(teD->GetValue()); + } + while(stream_cast(frameValue,s)); + ASSERT(filterProp.data == "1" || filterProp.data == "0"); + + + //Find the last property for the filter from the animator + // if available + std::string sData; + sData=propertyAnimator.getInterpolatedFilterData(filterId, + key,std::min(frameValue, + propertyAnimator.getMaxFrame())); + + if(!sData.empty()) + { + ASSERT(sData == "0" || sData == "1"); + filterProp.data=sData; + } + + //Flip the data + if(filterProp.data == "1") + filterProp.data="0"; + else + filterProp.data="1"; + + frameProp.setInterpMode(INTERP_STEP); + frameProp.addKeyFrame(frameValue,filterProp); + + teD->Destroy(); + break; + } + case PROPERTY_TYPE_CHOICE: + { + vector choiceVec; + unsigned int activeChoice; + choiceStringToVector(filterProp.data,choiceVec,activeChoice); + + ChoiceKeyFrameDialog *cD = new ChoiceKeyFrameDialog(this, + wxID_ANY,wxT("")); + cD->setChoices(choiceVec); + + if( cD->ShowModal() != wxID_OK) + { + cD->Destroy(); + return; + } + + filterProp.data=cD->getChoice(); + frameProp.setInterpMode(INTERP_STEP); + frameProp.addKeyFrame(cD->getStartFrame(),filterProp); + + cD->Destroy(); + + + break; + } + case PROPERTY_TYPE_COLOUR: + { + ColourKeyFrameDialog *colDlg = new ColourKeyFrameDialog(this, + wxID_ANY,wxTRANS("Key frame : Colour")) ; + if( colDlg->ShowModal() != wxID_OK) + { + colDlg->Destroy(); + return; + } + + //Copy out the data obtained from the dialog + size_t transitionMode; + transitionMode=colDlg->getTransitionMode(); + + frameProp.setInterpMode(transitionMode); + filterProp.data=colDlg->getStartValue(); + + frameProp.addKeyFrame(colDlg->getStartFrame(),filterProp); + //Add end value as needed + switch(transitionMode) + { + case TRANSITION_STEP: + break; + case TRANSITION_INTERP: + filterProp.data=colDlg->getEndValue(); + frameProp.setInterpMode(INTERP_LINEAR_COLOUR); + frameProp.addKeyFrame(colDlg->getEndFrame(),filterProp); + break; + default: + ASSERT(false); + } + colDlg->Destroy(); + + break; + } + case PROPERTY_TYPE_STRING: + { + //Create and show the string keyframe input dialog + StringKeyFrameDialog *sd = new StringKeyFrameDialog(this, + wxID_ANY,_("")); + + if(sd->ShowModal() != wxID_OK) + { + sd->Destroy(); + return; + } + + //set the interpolator to step-by-step interp + frameProp.setInterpMode(INTERP_LIST); + + //Grab the data vector we need to insert the keyframes + vector dataVec; + if(!sd->getStrings(dataVec)) + { + sd->Destroy(); + wxMessageDialog *wxD =new wxMessageDialog(this, + wxTRANS("File existed, but was unable to read or interpret file contents."), + wxTRANS("String load failed"),wxICON_ERROR|wxOK); + + wxD->ShowModal(); + wxD->Destroy(); + return; + } + + for(size_t ui=0;uigetStartFrame()+ui,filterProp); + } + + sd->Destroy(); + + + break; + } + case PROPERTY_TYPE_REAL: + { + RealKeyFrameDialog *r = new RealKeyFrameDialog(this, + wxID_ANY,wxTRANS("Keyframe : decimal")); + if(!getRealKeyFrame(frameProp,filterProp,r)) + return; + frameProp.setInterpMode(r->getTransitionMode()); + break; + } + case PROPERTY_TYPE_INTEGER: + { + RealKeyFrameDialog *r = new RealKeyFrameDialog(this, + wxID_ANY,wxTRANS("Keyframe : integer")); + if(!getRealKeyFrame(frameProp,filterProp,r)) + return; + frameProp.setInterpMode(r->getTransitionMode()); + break; + } + case PROPERTY_TYPE_POINT3D: + { + RealKeyFrameDialog *r = new RealKeyFrameDialog(this, + wxID_ANY,wxTRANS("Keyframe : 3D Point")); + if(!getRealKeyFrame(frameProp,filterProp,r)) + return; + //Animator needs special Linear ramping code, so select that + // if user chooses a linear ramp + if(frameProp.getInterpMode()==INTERP_LINEAR_FLOAT) + frameProp.setInterpMode(INTERP_LINEAR_POINT3D); + else + frameProp.setInterpMode(r->getTransitionMode()); + + break; + } + default: + ASSERT(false); // that should cover all data types... + } + + //Add property to animator + propertyAnimator.addProp(frameProp); + + //update the user interface controls + update(); + +} + +void ExportAnimationDialog::OnFrameGridCellEditorShow(wxGridEvent &event) +{ + event.Veto(); +} + +void ExportAnimationDialog::OnFilterViewUnsplit(wxSplitterEvent &evt) +{ + evt.Veto(); +} + +void ExportAnimationDialog::OnAnimateGridCellEditorShow(wxGridEvent &event) +{ + event.Veto(); +} + +void ExportAnimationDialog::OnButtonKeyFrameRemove(wxCommandEvent &event) +{ + if(!animationGrid->GetNumberRows()) + return; + //Obtain the IDs of the selected rows, or partially selected rows + + + //Rectangular selection + // This is an undocumented class AFAIK. :( + wxGridCellCoordsArray arrayTL(animationGrid->GetSelectionBlockTopLeft()); + wxGridCellCoordsArray arrayBR(animationGrid->GetSelectionBlockBottomRight()); + + //Row prefix or header selection + const wxArrayInt& selectedRows(animationGrid->GetSelectedRows()); + const wxGridCellCoordsArray& cells(animationGrid->GetSelectedCells()); + + vector rowsToKill; + + if(arrayTL.Count() && arrayBR.Count()) + { + wxGridCellCoords coordTL = arrayTL.Item(0); + wxGridCellCoords coordBR = arrayBR.Item(0); + + size_t rows = coordBR.GetRow() - coordTL.GetRow() +1; + + rowsToKill.resize(rows); + + for(size_t r=0; rGetGridCursorRow()); + + propertyAnimator.removeKeyFrames(rowsToKill); + //update user interface + update(); + +} + +void ExportAnimationDialog::updateOKButton() +{ + bool badStatus=false; + + badStatus|=workDir.empty(); + badStatus|=filterMap.empty(); + badStatus|=(imagePrefix.empty() && wantImageOutput); + badStatus|=(propertyAnimator.getNumProps() == 0); + + //Ensure that there were no inconsistent properties in + // the animation + std::set inconsistentProps; + badStatus|=!propertyAnimator.checkSelfConsistent(inconsistentProps); + okButton->Enable(!badStatus); +} + +void ExportAnimationDialog::OnOutputDirText(wxCommandEvent &event) +{ + if(programmaticEvent) + return; + + if(!wxDirExists(textWorkDir->GetValue())) + { + textWorkDir->SetBackgroundColour(*wxCYAN); + workDir.clear(); + } + else + { + textWorkDir->SetBackgroundColour(wxNullColour); + workDir=stlStr(textWorkDir->GetValue()); + } + + //update the user interface controls + update(); +} + + +void ExportAnimationDialog::OnButtonWorkDir(wxCommandEvent &event) +{ + //Pop up a directory dialog, to choose the base path for the new folder + wxDirDialog *wxD = new wxDirDialog(this, wxTRANS("Select or create new folder"), + wxFileSelectorDefaultWildcardStr, wxFD_SAVE); + + unsigned int res; + res = wxD->ShowModal(); + + while(res != wxID_CANCEL) + { + //If dir exists, exit + if(wxDirExists(wxD->GetPath())) + break; + + res=wxD->ShowModal(); + } + + //User aborted directory choice. + if(res==wxID_CANCEL) + { + wxD->Destroy(); + return; + } + + textWorkDir->SetValue(wxD->GetPath()); + workDir=stlStr(textWorkDir->GetValue()); + wxD->Destroy(); + + //update the user interface controls + update(); +} + +void ExportAnimationDialog::OnCheckOutDataChange(wxCommandEvent &event) +{ + if(programmaticEvent) + return; + + wantOnlyChanges=checkOutOnlyChanged->IsChecked(); +} + +void ExportAnimationDialog::OnCheckImageOutput(wxCommandEvent &event) +{ + if(programmaticEvent) + return; + + wantImageOutput=checkImageOutput->IsChecked(); + //update UI (eg OK button) + update(); +} + + +void ExportAnimationDialog::OnImageFilePrefix(wxCommandEvent &event) +{ + if(programmaticEvent) + return; + + imagePrefix=stlStr(textImageName->GetValue()); + + //update UI (eg OK button) + update(); +} + + +void ExportAnimationDialog::OnTextImageSize(wxCommandEvent &event) +{ + + if(programmaticEvent) + return; + + string s; + s=stlStr(textImageSize->GetValue()); + + bool parseOK=true; + size_t pos; + pos = s.find('x'); + if(pos==string::npos) + parseOK=false; + else + { + string first,last; + first = s.substr(0,pos); + last=s.substr(pos+1); + + + size_t w,h; + if(stream_cast(w,first)) + parseOK&=false; + + + if(stream_cast(h,last)) + parseOK&=false; + } + + if(!parseOK) + textImageSize->SetBackgroundColour(*wxCYAN); + else + textImageSize->SetBackgroundColour(wxNullColour); + + //update UI (eg OK button) + update(); + +} + +void ExportAnimationDialog::OnBtnResolution(wxCommandEvent &event) +{ + ResolutionDialog *r = new ResolutionDialog(this,wxID_ANY,wxT("Choose Resolution")); + + r->setRes(imageWidth,imageHeight); + + if(r->ShowModal() != wxID_OK) + { + r->Destroy(); + return; + } + + imageWidth=r->getWidth(); + imageHeight=r->getHeight(); + + string sWidth,sHeight; + stream_cast(sWidth,imageWidth); + stream_cast(sHeight,imageHeight); + + string s; + s=sWidth+"x" + sHeight; + textImageSize->SetValue(wxStr(s)); + + r->Destroy(); +} + + +void ExportAnimationDialog::OnCheckPointOutput(wxCommandEvent &event) +{ + wantIonOutput=checkPoints->IsChecked(); +} + + +void ExportAnimationDialog::OnCheckPlotOutput(wxCommandEvent &event) +{ + wantPlotOutput=checkPlotData->IsChecked(); +} + + +void ExportAnimationDialog::OnCheckVoxelOutput(wxCommandEvent &event) +{ + wantVoxelOutput=checkVoxelData->IsChecked(); +} + + +void ExportAnimationDialog::OnCheckRangeOutput(wxCommandEvent &event) +{ + wantRangeOutput=checkRangeData->IsChecked(); + + comboRangeFormat->Enable(checkRangeData->IsChecked()); +} + +void ExportAnimationDialog::OnRangeTypeCombo(wxCommandEvent &event) +{ + rangeExportMode=event.GetSelection(); +} + + +void ExportAnimationDialog::OnButtonOK(wxCommandEvent &event) +{ + event.Skip(); +} + +size_t ExportAnimationDialog::getRangeFormat() const +{ + return rangeExportMode; + +} + +// wxGlade: add ExportAnimationDialog event handlers + + +void ExportAnimationDialog::set_properties() +{ + // begin wxGlade: ExportAnimationDialog::set_properties + SetTitle(wxTRANS("Export Animation")); + filterTreeCtrl->SetToolTip(wxTRANS("Select filter")); + propertyGrid->CreateGrid(0, 2); + propertyGrid->SetColLabelValue(0, wxTRANS("Property")); + propertyGrid->SetColLabelValue(1, wxTRANS("Value")); + propertyGrid->SetToolTip(wxTRANS("Select property")); + animationGrid->CreateGrid(0, 5); + animationGrid->SetColLabelValue(0, wxTRANS("Filter")); + animationGrid->SetColLabelValue(1, wxTRANS("Property")); + animationGrid->SetColLabelValue(2, wxTRANS("Mode")); + animationGrid->SetColLabelValue(3, wxTRANS("Start Frame")); + animationGrid->SetColLabelValue(4, wxTRANS("End Frame")); + animationGrid->SetToolTip(wxTRANS("Keyframe table")); + keyFrameRemoveButton->SetToolTip(wxTRANS("Remove the selected keyframe from the table")); + textWorkDir->SetToolTip(wxTRANS("Enter where the animation frames will be exported to")); + buttonWorkDir->SetToolTip(wxTRANS("Browse to directory where the animation frames will be exported to")); + checkImageOutput->SetValue(1); + textImageName->SetToolTip(wxTRANS("Enter a descriptive name for output files")); + textImageSize->SetToolTip(wxTRANS("Enter the target resoltuion (image size)")); + comboRangeFormat->SetSelection(-1); + frameSlider->SetToolTip(wxTRANS("Select frame for property display")); + textFrame->SetToolTip(wxTRANS("Enter frame number to change frame (eg 1/20)")); + checkPoints->SetToolTip(wxTRANS("Save point data (POS files) in output folder?")); + checkPlotData->SetToolTip(wxTRANS("Save plots (as text files) in output folder?")); + checkVoxelData->SetToolTip(wxTRANS("Save voxel data (raw files) in output folder?")); + checkRangeData->SetToolTip(wxTRANS("Save range files in output folder?")); + framePropGrid->CreateGrid(0, 3); + framePropGrid->SetColLabelValue(0, wxTRANS("Filter")); + framePropGrid->SetColLabelValue(1, wxTRANS("Property")); + framePropGrid->SetColLabelValue(2, wxTRANS("Value")); + framePropGrid->SetToolTip(wxTRANS("Animation parameters for current frame")); + cancelButton->SetToolTip(wxTRANS("Abort animation")); + okButton->SetToolTip(wxTRANS("Run Animation")); + // end wxGlade +} + + +void ExportAnimationDialog::do_layout() +{ + // begin wxGlade: ExportAnimationDialog::do_layout + wxBoxSizer* animateSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* globalButtonSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* frameViewSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* propGridSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* frameSliderSizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* outputDataSizer = new wxStaticBoxSizer(outputDataSizer_staticbox, wxVERTICAL); + wxBoxSizer* rangeFileDropDownSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* outputImageOptionsSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* imageSizeSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* filePrefixSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* outputDirHorizSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* filterViewPaneSizerH = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* keyFramesSizer = new wxStaticBoxSizer(keyFramesSizer_staticbox, wxVERTICAL); + wxBoxSizer* keyFrameButtonSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* animationGridSizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* filterPropertySizer = new wxStaticBoxSizer(filterPropertySizer_staticbox, wxVERTICAL); + filterPropertySizer->Add(filterTreeCtrl, 1, wxALL|wxEXPAND, 3); + filterPropertySizer->Add(propertyGrid, 1, wxALL|wxEXPAND, 3); + filterLeftPane->SetSizer(filterPropertySizer); + animationGridSizer->Add(animationGrid, 1, wxALL|wxEXPAND, 3); + keyFramesSizer->Add(animationGridSizer, 1, wxEXPAND, 0); + keyFrameButtonSizer->Add(keyFrameRemoveButton, 0, wxALIGN_CENTER_HORIZONTAL, 0); + keyFramesSizer->Add(keyFrameButtonSizer, 0, wxALL|wxEXPAND, 3); + filterRightPane->SetSizer(keyFramesSizer); + splitPaneFilter->SplitVertically(filterLeftPane, filterRightPane); + filterViewPaneSizerH->Add(splitPaneFilter, 1, wxEXPAND, 0); + filterViewPane->SetSizer(filterViewPaneSizerH); + outputDirHorizSizer->Add(labelWorkDir, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 3); + outputDirHorizSizer->Add(textWorkDir, 1, wxEXPAND, 0); + outputDirHorizSizer->Add(buttonWorkDir, 0, wxLEFT|wxRIGHT, 2); + outputDataSizer->Add(outputDirHorizSizer, 0, wxALL|wxEXPAND, 4); + sizer_1->Add(20, 20, 0, 0, 0); + sizer_1->Add(checkOutOnlyChanged, 0, 0, 0); + outputDataSizer->Add(sizer_1, 0, wxBOTTOM|wxEXPAND, 5); + outputDataSizer->Add(outputDataSepLine, 0, wxTOP|wxBOTTOM|wxEXPAND, 3); + outputDataSizer->Add(labelDataType, 0, wxTOP|wxBOTTOM, 4); + outputDataSizer->Add(checkImageOutput, 0, wxLEFT|wxTOP, 3); + filePrefixSizer->Add(lblImageName, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 3); + filePrefixSizer->Add(textImageName, 1, wxALL|wxEXPAND, 4); + outputImageOptionsSizer->Add(filePrefixSizer, 0, wxALL|wxEXPAND, 3); + imageSizeSizer->Add(labelImageSize, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 3); + imageSizeSizer->Add(textImageSize, 1, wxALL|wxEXPAND, 4); + imageSizeSizer->Add(buttonImageSize, 0, wxALL, 4); + outputImageOptionsSizer->Add(imageSizeSizer, 0, wxALL|wxEXPAND, 3); + outputDataSizer->Add(outputImageOptionsSizer, 0, wxEXPAND, 0); + outputDataSizer->Add(checkPoints, 1, wxLEFT|wxBOTTOM, 3); + outputDataSizer->Add(checkPlotData, 1, wxLEFT|wxTOP, 3); + outputDataSizer->Add(checkVoxelData, 1, wxLEFT|wxTOP|wxBOTTOM, 3); + outputDataSizer->Add(checkRangeData, 1, wxALL, 3); + rangeFileDropDownSizer->Add(labelRangeFormat, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 3); + rangeFileDropDownSizer->Add(comboRangeFormat, 1, wxLEFT|wxRIGHT|wxEXPAND, 3); + outputDataSizer->Add(rangeFileDropDownSizer, 0, wxLEFT|wxBOTTOM|wxEXPAND, 5); + outputDataSizer->Add(20, 20, 2, 0, 0); + frameViewSizer->Add(outputDataSizer, 1, wxEXPAND, 0); + frameViewSizer->Add(static_line_1, 0, wxLEFT|wxRIGHT|wxEXPAND, 5); + frameSliderSizer->Add(labelFrame, 0, wxALIGN_CENTER_VERTICAL, 0); + frameSliderSizer->Add(frameSlider, 1, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); + frameSliderSizer->Add(textFrame, 0, wxALIGN_CENTER_VERTICAL, 0); + propGridSizer->Add(frameSliderSizer, 0, wxALL|wxEXPAND, 3); + propGridSizer->Add(framePropGrid, 1, wxEXPAND, 0); + frameViewSizer->Add(propGridSizer, 2, wxALL|wxEXPAND, 3); + frameViewPane->SetSizer(frameViewSizer); + viewNotebook->AddPage(filterViewPane, wxTRANS("Filter view")); + viewNotebook->AddPage(frameViewPane, wxTRANS("Frame view")); + animateSizer->Add(viewNotebook, 1, wxEXPAND, 0); + globalButtonSizer->Add(20, 1, 1, wxEXPAND, 0); + globalButtonSizer->Add(cancelButton, 0, wxALL|wxALIGN_BOTTOM, 3); + globalButtonSizer->Add(okButton, 0, wxALL|wxALIGN_BOTTOM, 3); + animateSizer->Add(globalButtonSizer, 0, wxEXPAND, 0); + SetSizer(animateSizer); + animateSizer->Fit(this); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/animateFilterDialog.h 3depict-0.0.13/src/gui/dialogs/animateFilterDialog.h --- 3depict-0.0.12/src/gui/dialogs/animateFilterDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateFilterDialog.h 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,233 @@ +/* + * animateFilterDialog - GUI for animate filter + * Copyright (C) 2013, D. Haley, A Ceguerra + + * 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 . + */ + +#ifndef ANIMATEFILTERDIALOG_H +#define ANIMATEFILTERDIALOG_H + +#include +// begin wxGlade: ::dependencies +#include +#include +#include +#include +#include +// end wxGlade + + +#include "backend/animator.h" +#include "backend/viscontrol.h" //for upWxTreeCtrl + + +// begin wxGlade: ::extracode +// end wxGlade + +enum +{ + FILENAME_IMAGE, + FILENAME_IONS, + FILENAME_RANGE, + FILENAME_PLOT, + FILENAME_VOXEL +}; + +enum +{ + RANGE_OAKRIDGE, + RANGE_AMETEK_RRNG, + RANGE_AMETEK_ENV, + RANGE_FORMATNAME_END +}; + +class ExportAnimationDialog: public wxDialog { +public: + // begin wxGlade: ExportAnimationDialog::ids + // end wxGlade + + ExportAnimationDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + ~ExportAnimationDialog(); + + //!Must be called before displaying dialog, and after setting tree + void prepare(); + + //obtain the desired filename for a particular type of output + std::string getFilename(unsigned int frame, unsigned int nameType, unsigned int number=0) const ; + //Obtain the desired width of the output image + unsigned int getImageWidth() const { return imageWidth;} + //Obtain the desired height of the output image + unsigned int getImageHeight() const { return imageHeight;}; + + //Get the number of frames that are in the animation sequence + size_t getNumFrames() const { return propertyAnimator.getMaxFrame();} + + //Return a modified version f the filter tree, applying the changes requested + // by the user + bool getModifiedTree(size_t frame, FilterTree &t,bool &needUp) const; + + //Set the tree that we are to work with + void setTree(const FilterTree &origTree) { filterTree=&origTree;}; + + //Does the user want to obtain image output? + bool wantsImages() const { return wantImageOutput;} + //Does the user want to obtain plot output? + bool wantsPlots() const { return wantPlotOutput;} + //Does the user want to obtain ion output? + bool wantsIons() const { return wantIonOutput;} + //Does the user want to obtain range output? + bool wantsRanges() const { return wantRangeOutput;} + //Does the user want to obtain range output? + bool wantsVoxels() const { return wantVoxelOutput;} + + //Does the user want all data output, or only when the data + // changes (needs a refresh) + bool wantsOnlyChanges() const { return wantOnlyChanges;} + + //!Obtain the format the user wants to save ranges in + size_t getRangeFormat() const; +private: + //!Tree of filters that can be manipulated + const FilterTree *filterTree; + //!Mapping from ID of filter to the pointer in the filter tree + map filterMap; + + //!Mapping to allow for converting entry of RNG selection combo into + // the correct range enum value + map rangeMap; + //!Default height/width desired for output images + size_t imageWidth,imageHeight; + bool imageSizeOK; + + PropertyAnimator propertyAnimator; + + //!Working directory for outputting data + string workDir; + + string imagePrefix; + //!True if any con + bool existsConflicts; + //!true if the user has selected image output functionality + bool wantImageOutput; + //!True if the user has requested ion data output + bool wantIonOutput; + //!True if the user wants plots output + bool wantPlotOutput; + //!True if the user wants to save voxel data + bool wantVoxelOutput; + //!True if the user wants to save range data + bool wantRangeOutput; + //!True if the user only wants to save data if it changes + bool wantOnlyChanges; + + //!Current frame that the user wants to see in the frame view + size_t currentFrame; + + //!Type of rangefile to export + size_t rangeExportMode; + + + //Used to jump out of wx events that are generated by + // the code, rather than the user, eg text events + bool programmaticEvent; + //UI update function + void update(); + + + //Enable/disable the OK button depending upon dialog state + void updateOKButton(); + //update function for frame view page, grid control + void updateFilterViewGrid(); + //update function for frame view page, grid contorl + void updateFrameViewGrid(); + //Updates the slider on the frame view page + void updateFrameViewSlider(); + // begin wxGlade: ExportAnimationDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + +protected: + // begin wxGlade: ExportAnimationDialog::attributes + wxStaticBox* outputDataSizer_staticbox; + wxStaticBox* keyFramesSizer_staticbox; + wxStaticBox* filterPropertySizer_staticbox; + wxTreeCtrl* filterTreeCtrl; + wxPropertyGrid* propertyGrid; + wxPanel* filterLeftPane; + wxGrid* animationGrid; + wxButton* keyFrameRemoveButton; + wxPanel* filterRightPane; + wxSplitterWindow* splitPaneFilter; + wxPanel* filterViewPane; + wxStaticText* labelWorkDir; + wxTextCtrl* textWorkDir; + wxButton* buttonWorkDir; + wxCheckBox* checkOutOnlyChanged; + wxStaticLine* outputDataSepLine; + wxStaticText* labelDataType; + wxCheckBox* checkImageOutput; + wxStaticText* lblImageName; + wxTextCtrl* textImageName; + wxStaticText* labelImageSize; + wxTextCtrl* textImageSize; + wxButton* buttonImageSize; + wxCheckBox* checkPoints; + wxCheckBox* checkPlotData; + wxCheckBox* checkVoxelData; + wxCheckBox* checkRangeData; + wxStaticText* labelRangeFormat; + wxChoice* comboRangeFormat; + wxStaticLine* static_line_1; + wxStaticText* labelFrame; + wxSlider* frameSlider; + wxTextCtrl* textFrame; + wxGrid* framePropGrid; + wxPanel* frameViewPane; + wxNotebook* viewNotebook; + wxButton* cancelButton; + wxButton* okButton; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnFilterTreeCtrlSelChanged(wxTreeEvent &event); // wxGlade: + virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // wxGlade: + virtual void OnAnimateGridCellEditorShow(wxGridEvent &event); // wxGlade: + virtual void OnFrameGridCellEditorShow(wxGridEvent &event); // wxGlade: + virtual void OnButtonKeyFrameRemove(wxCommandEvent &event); // wxGlade: + virtual void OnOutputDirText(wxCommandEvent &event); // wxGlade: + virtual void OnButtonWorkDir(wxCommandEvent &event); // wxGlade: + virtual void OnCheckOutDataChange(wxCommandEvent &event); // wxGlade: + virtual void OnCheckImageOutput(wxCommandEvent &event); // wxGlade: + virtual void OnImageFilePrefix(wxCommandEvent &event); // wxGlade: + virtual void OnTextImageSize(wxCommandEvent &event); // wxGlade: + virtual void OnBtnResolution(wxCommandEvent &event); // wxGlade: + virtual void OnCheckPointOutput(wxCommandEvent &event); // wxGlade: + virtual void OnCheckPlotOutput(wxCommandEvent &event); // wxGlade: + virtual void OnCheckVoxelOutput(wxCommandEvent &event); // wxGlade: + virtual void OnCheckRangeOutput(wxCommandEvent &event); // wxGlade: + virtual void OnRangeTypeCombo(wxCommandEvent &event); // wxGlade: + virtual void OnFrameViewSlider(wxScrollEvent &event); // wxGlade: + virtual void OnTextFrame(wxCommandEvent &event); // wxGlade: + virtual void OnButtonCancel(wxCommandEvent &event); // wxGlade: + virtual void OnButtonOK(wxCommandEvent &event); // wxGlade: + virtual void OnFilterViewUnsplit(wxSplitterEvent &event); // wxGlade: + +}; // wxGlade: end class + + +#endif // ANIMATEFILTERDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,130 @@ +/* + * choiceKeyFrameDialog.cpp - Keyframe selection for optioned properties + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Sun Sep 23 22:52:41 2012 + +#include "choiceKeyFrameDialog.h" + +// begin wxGlade: ::extracode + +// end wxGlade + +#include "wxcommon.h" + + +ChoiceKeyFrameDialog::ChoiceKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE) +{ + // begin wxGlade: ChoiceKeyFrameDialog::ChoiceKeyFrameDialog + labelFrame = new wxStaticText(this, wxID_ANY, wxT("Frame")); + textFrame = new wxTextCtrl(this, ID_TEXT_FRAME, wxEmptyString); + labelSelection = new wxStaticText(this, wxID_ANY, wxT("Selection")); + comboChoice = new wxComboBox(this, ID_COMBO_CHOICE, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxCB_SIMPLE|wxCB_READONLY); + btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + + startFrameOK=false; + + + set_properties(); + do_layout(); + // end wxGlade +} + + +BEGIN_EVENT_TABLE(ChoiceKeyFrameDialog, wxDialog) + // begin wxGlade: ChoiceKeyFrameDialog::event_table + EVT_COMBOBOX(ID_COMBO_CHOICE, ChoiceKeyFrameDialog::OnChoiceCombo) + EVT_TEXT(ID_TEXT_FRAME, ChoiceKeyFrameDialog::OnFrameText) + // end wxGlade +END_EVENT_TABLE(); + + +void ChoiceKeyFrameDialog::OnChoiceCombo(wxCommandEvent &event) +{ + choice=comboChoice->GetSelection(); +} + +void ChoiceKeyFrameDialog::OnFrameText(wxCommandEvent &event) +{ + if(validateTextAsStream(textFrame,startFrame)) + startFrameOK=true; + + updateOKButton(); +} + +// wxGlade: add ChoiceKeyFrameDialog event handlers + +void ChoiceKeyFrameDialog::updateOKButton() +{ + btnOK->Enable(startFrameOK); +} + +void ChoiceKeyFrameDialog::buildCombo(size_t defaultChoice) +{ + ASSERT(choiceStrings.size()); + + + comboChoice->Clear(); + + for(size_t ui=0;uiAppend(wxStr(choiceStrings[ui])); + + comboChoice->SetSelection(defaultChoice); +} + + +void ChoiceKeyFrameDialog::setChoices(const std::vector &choices, + size_t defChoice) +{ + choiceStrings=choices; + + buildCombo(defChoice); + choice=defChoice; +} + +void ChoiceKeyFrameDialog::set_properties() +{ + // begin wxGlade: ChoiceKeyFrameDialog::set_properties + SetTitle(wxT("Key Frame")); + // end wxGlade +} + + +void ChoiceKeyFrameDialog::do_layout() +{ + // begin wxGlade: ChoiceKeyFrameDialog::do_layout + wxBoxSizer* frameSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* textSizer = new wxBoxSizer(wxHORIZONTAL); + textSizer->Add(labelFrame, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 20); + textSizer->Add(textFrame, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 5); + frameSizer->Add(textSizer, 0, wxALL|wxEXPAND, 10); + comboSizer->Add(labelSelection, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); + comboSizer->Add(comboChoice, 0, wxLEFT, 5); + frameSizer->Add(comboSizer, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 10); + buttonSizer->Add(20, 20, 1, 0, 0); + buttonSizer->Add(btnCancel, 0, wxRIGHT, 5); + buttonSizer->Add(btnOK, 0, wxLEFT, 5); + frameSizer->Add(buttonSizer, 0, wxALL|wxEXPAND, 5); + SetSizer(frameSizer); + frameSizer->Fit(this); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * choiceKeyFrameDialog.h - Keyframe selection for optioned properties + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Sun Sep 23 22:52:41 2012 + +#include +// begin wxGlade: ::dependencies +// end wxGlade + +#include + +#ifndef CHOICEKEYFRAMEDIALOG_H +#define CHOICEKEYFRAMEDIALOG_H + + +// begin wxGlade: ::extracode +enum +{ + ID_TEXT_FRAME, + ID_COMBO_CHOICE +}; +// end wxGlade + + +class ChoiceKeyFrameDialog: public wxDialog { +public: + // begin wxGlade: ChoiceKeyFrameDialog::ids + // end wxGlade + + ChoiceKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + + //Set the choices that are allowed to be selected + void setChoices(const std::vector &choices,size_t defaultChoice=0); + + //Obtain the choice from the user + size_t getChoiceIndex() const { return choice;}; + + std::string getChoice() const { return choiceStrings[choice];}; + + size_t getStartFrame() const { return startFrame;} +private: + // begin wxGlade: ChoiceKeyFrameDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //List of choices that can go into the combo box + std::vector choiceStrings; + + //Drop-down value chosen by user + size_t choice; + + //True if the start frame entered by user is valid + bool startFrameOK; + + //Current start frame + size_t startFrame; + + //enable or disable the OK button based upon validation results + void updateOKButton(); + + //build up the combo box items + void buildCombo(size_t defaultChoice); +protected: + // begin wxGlade: ChoiceKeyFrameDialog::attributes + wxStaticText* labelFrame; + wxTextCtrl* textFrame; + wxStaticText* labelSelection; + wxComboBox* comboChoice; + wxButton* btnCancel; + wxButton* btnOK; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnChoiceCombo(wxCommandEvent &event); // wxGlade: + virtual void OnFrameText(wxCommandEvent &event); // wxGlade: +}; // wxGlade: end class + + +#endif // CHOICEKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,295 @@ +/* + * colourKeyFrameDialog.cpp - Colour property keyframe selection dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Fri Sep 14 09:37:57 2012 + +#include "colourKeyFrameDialog.h" +#include "common/stringFuncs.h" +#include "wxcommon.h" +#include "common/translation.h" + +#include + + +using std::string; + +// begin wxGlade: ::extracode +enum{ + ID_COMBO_TRANSITION, + ID_BTN_START_VALUE, + ID_BTN_FINAL_VALUE, + ID_TEXT_INITIAL_VALUE, + ID_TEXT_FRAME_START, + ID_TEXT_FRAME_END +}; + +// end wxGlade + +//FIXME: Is currently duplicated from realKeyframeDialog. Needs to be +// unified +enum +{ + TRANSITION_STEP, + TRANSITION_INTERP, + TRANSITION_END +}; + + +ColourKeyFrameDialog::ColourKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX) +{ + // begin wxGlade: ColourKeyFrameDialog::ColourKeyFrameDialog + sizerMainArea_staticbox = new wxStaticBox(this, -1, wxTRANS("Keyframe Data")); + labelTransition = new wxStaticText(this, wxID_ANY, wxTRANS("Transition")); + //FIXME: THis is declared in animator.h - use that def. + const wxString comboTransition_choices[] = { + wxTRANS("Step"), + wxTRANS("Ramp") + }; + comboTransition = new wxComboBox(this, ID_COMBO_TRANSITION, _(""), wxDefaultPosition, wxDefaultSize, 2, comboTransition_choices, wxCB_DROPDOWN|wxCB_READONLY); + labelFrameStart = new wxStaticText(this, wxID_ANY, wxTRANS("Start Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textFrameStart = new wxTextCtrl(this, ID_TEXT_FRAME_START, wxEmptyString); + labelFrameEnd = new wxStaticText(this, wxID_ANY, wxTRANS("End Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textFrameEnd = new wxTextCtrl(this, ID_TEXT_FRAME_END, wxEmptyString); + verticalLine = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + labelStartVal = new wxStaticText(this, wxID_ANY, wxTRANS("Initial Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + btnStartColour = new wxButton(this, ID_BTN_START_VALUE, wxTRANS("startColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + labelFinalVal = new wxStaticText(this, wxID_ANY, wxTRANS("Final Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + btnEndColour = new wxButton(this, ID_BTN_FINAL_VALUE, wxTRANS("endColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + buttonCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + buttonOK = new wxButton(this, wxID_OK, wxEmptyString); + + comboTransition->SetSelection(1); + transitionMode=TRANSITION_INTERP; + endFrameOK=startFrameOK=false; + startRed=startGreen=startBlue=0; + endRed=endGreen=endBlue=0; + + + updateOKButton(); + updateButtonColours(); + + set_properties(); + do_layout(); + // end wxGlade +} + + +BEGIN_EVENT_TABLE(ColourKeyFrameDialog, wxDialog) + // begin wxGlade: ColourKeyFrameDialog::event_table + EVT_COMBOBOX(ID_COMBO_TRANSITION, ColourKeyFrameDialog::OnComboTransition) + EVT_TEXT(ID_TEXT_FRAME_START, ColourKeyFrameDialog::OnTextStartFrame) + EVT_TEXT(ID_TEXT_FRAME_END, ColourKeyFrameDialog::OnTextEndFrame) + EVT_BUTTON(ID_BTN_START_VALUE, ColourKeyFrameDialog::OnBtnStartColour) + EVT_BUTTON(ID_BTN_FINAL_VALUE, ColourKeyFrameDialog::OnBtnEndColour) + // end wxGlade +END_EVENT_TABLE(); + +size_t ColourKeyFrameDialog::getStartFrame() const +{ + ASSERT(startFrameOK); + return startFrame; +} + +size_t ColourKeyFrameDialog::getEndFrame() const +{ + ASSERT(endFrameOK); + return endFrame; +} + +std::string ColourKeyFrameDialog::getEndValue() const +{ + ASSERT(transitionMode!=TRANSITION_STEP); + std::string s; + genColString(endRed,endGreen,endBlue,s); + return s; +} + +std::string ColourKeyFrameDialog::getStartValue() const +{ + std::string s; + genColString(startRed,startGreen,startBlue,s); + return s; +} + +void ColourKeyFrameDialog::OnComboTransition(wxCommandEvent &event) +{ + ASSERT(event.GetInt() < TRANSITION_END); + + transitionMode=event.GetInt(); + + btnEndColour->Enable(transitionMode != TRANSITION_STEP); + textFrameEnd->Enable(transitionMode!=TRANSITION_STEP); +} + +void ColourKeyFrameDialog::OnTextStartFrame(wxCommandEvent &event) +{ + startFrameOK=validateTextAsStream(textFrameStart,startFrame); + updateOKButton(); +} + + +void ColourKeyFrameDialog::OnTextEndFrame(wxCommandEvent &event) +{ + endFrameOK=validateTextAsStream(textFrameEnd,endFrame); + updateOKButton(); +} + + +void ColourKeyFrameDialog::OnBtnStartColour(wxCommandEvent &event) +{ + wxColourData d; + wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); + + if( colDg->ShowModal() == wxID_OK) + { + wxColour c; + //Change the colour + c=colDg->GetColourData().GetColour(); + + startRed=c.Red(); + startGreen=c.Green(); + startBlue=c.Blue(); + + updateButtonColours(); + } +} + + +void ColourKeyFrameDialog::OnBtnEndColour(wxCommandEvent &event) +{ + wxColourData d; + wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); + + if( colDg->ShowModal() == wxID_OK) + { + wxColour c; + //Change the colour + c=colDg->GetColourData().GetColour(); + + endRed=c.Red(); + endGreen=c.Green(); + endBlue=c.Blue(); + + updateButtonColours(); + } + + colDg->Destroy(); +} + +void ColourKeyFrameDialog::updateOKButton() +{ + bool isOK=true; + isOK&=startFrameOK; + isOK&=endFrameOK; + + //Ensure start frame is > end frame + if(isOK) + { + isOK&=(startFrameSetBackgroundColour(*wxCYAN); + textFrameEnd->SetBackgroundColour(*wxCYAN); + } + else + { + textFrameStart->SetBackgroundColour(wxNullColour); + textFrameEnd->SetBackgroundColour(wxNullColour); + } + } + + buttonOK->Enable(isOK); +} + +void ColourKeyFrameDialog::updateButtonColours() +{ + wxColour colD; + colD.Set(startRed,startGreen,startBlue); + btnStartColour->SetForegroundColour(colD); + + colD.Set(endRed,endGreen,endBlue); + btnEndColour->SetForegroundColour(colD); + +} +// wxGlade: add ColourKeyFrameDialog event handlers + + +void ColourKeyFrameDialog::set_properties() +{ + // begin wxGlade: ColourKeyFrameDialog::set_properties + SetTitle(wxTRANS("Key Frame : Colour")); + comboTransition->SetSelection(-1); + btnStartColour->SetToolTip(wxTRANS("Colour at the start of the transtition")); + btnEndColour->SetToolTip(wxTRANS("Colour at end of transition")); + // end wxGlade +} + + +void ColourKeyFrameDialog::do_layout() +{ + // begin wxGlade: ColourKeyFrameDialog::do_layout + wxBoxSizer* sizerTop = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerBUttons = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* sizerMainArea = new wxStaticBoxSizer(sizerMainArea_staticbox, wxHORIZONTAL); + wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerRightFinal = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerRightInitial = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerEndFrame = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerStartFrame = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerTransition = new wxBoxSizer(wxHORIZONTAL); + sizerTop->Add(20, 5, 0, 0, 0); + sizerMainArea->Add(10, 20, 0, 0, 0); + sizerLeft->Add(20, 10, 0, 0, 0); + sizerTransition->Add(labelTransition, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 14); + sizerTransition->Add(comboTransition, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 5); + sizerLeft->Add(sizerTransition, 1, wxEXPAND, 0); + sizerStartFrame->Add(labelFrameStart, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); + sizerStartFrame->Add(textFrameStart, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); + sizerLeft->Add(sizerStartFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerEndFrame->Add(labelFrameEnd, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 12); + sizerEndFrame->Add(textFrameEnd, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); + sizerLeft->Add(sizerEndFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerLeft->Add(20, 10, 0, 0, 0); + sizerMainArea->Add(sizerLeft, 2, wxEXPAND, 0); + sizerMainArea->Add(verticalLine, 0, wxLEFT|wxRIGHT|wxEXPAND, 5); + sizerRight->Add(20, 20, 1, 0, 0); + sizerRightInitial->Add(20, 20, 1, 0, 0); + sizerRightInitial->Add(labelStartVal, 2, wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); + sizerRightInitial->Add(btnStartColour, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3); + sizerRightInitial->Add(20, 20, 1, 0, 0); + sizerRight->Add(sizerRightInitial, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerRightFinal->Add(20, 20, 1, 0, 0); + sizerRightFinal->Add(labelFinalVal, 2, wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 9); + sizerRightFinal->Add(btnEndColour, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3); + sizerRightFinal->Add(20, 20, 1, 0, 0); + sizerRight->Add(sizerRightFinal, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerRight->Add(20, 20, 1, 0, 0); + sizerMainArea->Add(sizerRight, 2, wxEXPAND, 0); + sizerMainArea->Add(10, 20, 0, 0, 0); + sizerTop->Add(sizerMainArea, 1, wxEXPAND, 0); + sizerBUttons->Add(20, 20, 1, 0, 0); + sizerBUttons->Add(buttonCancel, 0, wxALL, 4); + sizerBUttons->Add(buttonOK, 0, wxALL, 4); + sizerTop->Add(sizerBUttons, 0, wxEXPAND, 0); + SetSizer(sizerTop); + sizerTop->Fit(this); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,101 @@ +/* + * colourKeyFrameDialog.h -Colour property keyframe selection dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Fri Sep 14 09:37:57 2012 +#ifndef COLOURKEYFRAMEDIALOG_H +#define COLOURKEYFRAMEDIALOG_H + + +#include +// begin wxGlade: ::dependencies +#include + +// end wxGlade + + + +// begin wxGlade: ::extracode +// end wxGlade + + +class ColourKeyFrameDialog: public wxDialog { +public: + // begin wxGlade: ColourKeyFrameDialog::ids + // end wxGlade + + ColourKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + + size_t getTransitionMode() const { return transitionMode;}; + + //Get the staring colour as a hex string + std::string getStartValue() const; + //Get the ending colour as a hex string + std::string getEndValue() const; + + size_t getStartFrame() const ; + + size_t getEndFrame() const ; +private: + // begin wxGlade: ColourKeyFrameDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //Starting red, green and blue values for transition + unsigned char startRed,startGreen, startBlue; + unsigned char endRed,endGreen, endBlue; + size_t startFrame,endFrame; + size_t transitionMode; + + bool startFrameOK,endFrameOK; + + //!Update the OK button's enabled/disabled state + // based upon text field validity + void updateOKButton(); + //!Update the colour chooser buttons appearance + void updateButtonColours(); + +protected: + // begin wxGlade: ColourKeyFrameDialog::attributes + wxStaticBox* sizerMainArea_staticbox; + wxStaticText* labelTransition; + wxComboBox* comboTransition; + wxStaticText* labelFrameStart; + wxTextCtrl* textFrameStart; + wxStaticText* labelFrameEnd; + wxTextCtrl* textFrameEnd; + wxStaticLine* verticalLine; + wxStaticText* labelStartVal; + wxButton* btnStartColour; + wxStaticText* labelFinalVal; + wxButton* btnEndColour; + wxButton* buttonCancel; + wxButton* buttonOK; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnComboTransition(wxCommandEvent &event); // wxGlade: + virtual void OnTextStartFrame(wxCommandEvent &event); // wxGlade: + virtual void OnTextEndFrame(wxCommandEvent &event); // wxGlade: + virtual void OnBtnStartColour(wxCommandEvent &event); // wxGlade: + virtual void OnBtnEndColour(wxCommandEvent &event); // wxGlade: +}; // wxGlade: end class + + +#endif // COLOURKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/realKeyFrameDialog.h 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/realKeyFrameDialog.h --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/realKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/realKeyFrameDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,341 @@ +/* + * realKeyFrameDialog.h - Real value keyframe selection dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Tue Aug 28 22:07:07 2012 +#ifndef REALKEYFRAMEDIALOG_H +#define REALKEYFRAMEDIALOG_H + +// begin wxGlade: ::dependencies +// end wxGlade + +#include "wxcommon.h" + +enum +{ + TRANSITION_STEP, + TRANSITION_INTERP, + TRANSITION_END +}; + + +// begin wxGlade: ::extracode +enum +{ + ID_COMBO_TRANSITION, + ID_TEXT_FRAME_START, + ID_TEXT_FRAME_END, + ID_TEXT_FINAL_VALUE, + ID_TEXT_INITIAL_VALUE, +}; +// end wxGlade + +template +class RealKeyFrameDialog: public wxDialog +{ +public: + // begin wxGlade: RealKeyFrameDialog::ids + // end wxGlade + + RealKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + + //!Return the keyframe transition style selected by user + size_t getTransitionMode() const { return transitionMode;} + + //!Return the initial frame from user + size_t getEndFrame() const { return endFrame;} + //!Return the start frame, as was given by user + size_t getStartFrame() const { return startFrame;} + + //!Return the initial value, as given by user + T getEndValue() const { return endValue;} + //!Return the start value, as was given by user + T getStartValue() const { return startValue;} +private: + size_t transitionMode; + size_t startFrame, endFrame; + T startValue, endValue; + + bool startFrameOK,endFrameOK; + bool startValueOK,endValueOK; + + void updateOKButton(); + + // begin wxGlade: RealKeyFrameDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + +protected: + // begin wxGlade: RealKeyFrameDialog::attributes + wxStaticBox* sizerMainArea_staticbox; + wxStaticText* labelTransition; + wxComboBox* comboTransition; + wxStaticText* labelFrameStart; + wxTextCtrl* textFrameStart; + wxStaticText* labelFrameEnd; + wxTextCtrl* textFrameEnd; + wxStaticLine* verticalLine; + wxStaticText* labelStartVal; + wxTextCtrl* textStartVal; + wxStaticText* labelEndVal; + wxTextCtrl* textEndVal; + wxButton* buttonCancel; + wxButton* buttonOK; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnComboTransition(wxCommandEvent &event); // wxGlade: + virtual void OnTextStartFrame(wxCommandEvent &event); // wxGlade: + virtual void OnTextEndFrame(wxCommandEvent &event); // wxGlade: + virtual void OnTextStartValue(wxCommandEvent &event); // wxGlade: + virtual void OnTextEndValue(wxCommandEvent &event); // wxGlade: +}; // wxGlade: end class + +using std::string; + +bool validatePoint3D(wxTextCtrl *t, Point3D &i) +{ + bool isOK; + std::string s; + s= stlStr(t->GetValue()); + + //string cannot be empty + bool condition; + condition = s.empty() || !i.parse(s); + + if(condition) + { + //OK, so bad things happened. Prevent the user from doing this + isOK=false; + + //if it is bad and non-empty, highlight it as such + // if it is empty, then just set it to normal colour + if(s.empty()) + t->SetBackgroundColour(wxNullColour); + else + t->SetBackgroundColour(*wxCYAN); + } + else + { + t->SetBackgroundColour(wxNullColour); + isOK=true; + } + + + return isOK; +} + +template +RealKeyFrameDialog::RealKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX) +{ + // begin wxGlade: RealKeyFrameDialog::RealKeyFrameDialog + sizerMainArea_staticbox = new wxStaticBox(this, -1, wxT("Keyframe Data")); + labelTransition = new wxStaticText(this, wxID_ANY, wxT("Transition")); + //FIXME: This is declared in animator.h, use it! + const wxString comboTransition_choices[] = { + wxT("Step"), + wxT("Ramp") + }; + comboTransition = new wxComboBox(this, ID_COMBO_TRANSITION, wxT(""), wxDefaultPosition, wxDefaultSize, 2, comboTransition_choices, wxCB_DROPDOWN|wxCB_READONLY); + labelFrameStart = new wxStaticText(this, wxID_ANY, wxT("Start Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textFrameStart = new wxTextCtrl(this, ID_TEXT_FRAME_START, wxEmptyString); + labelFrameEnd = new wxStaticText(this, wxID_ANY, wxT("End Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textFrameEnd = new wxTextCtrl(this, ID_TEXT_FRAME_END, wxEmptyString); + verticalLine = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + labelStartVal = new wxStaticText(this, wxID_ANY, wxT("Start Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textStartVal = new wxTextCtrl(this, ID_TEXT_INITIAL_VALUE, wxEmptyString); + labelEndVal = new wxStaticText(this, wxID_ANY, wxT("End Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textEndVal = new wxTextCtrl(this, ID_TEXT_FINAL_VALUE, wxEmptyString); + buttonCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + buttonOK = new wxButton(this, wxID_OK, wxEmptyString); + + startFrameOK=endFrameOK=startValueOK=endValueOK=false; + + const int DEFAULT_TRANSITION=TRANSITION_INTERP; + comboTransition->SetSelection(DEFAULT_TRANSITION); + transitionMode=DEFAULT_TRANSITION; + + set_properties(); + do_layout(); + // end wxGlade +} + + + +BEGIN_EVENT_TABLE_TEMPLATE1(RealKeyFrameDialog, wxDialog,T) + // begin wxGlade: RealKeyFrameDialog::event_table + EVT_COMBOBOX(ID_COMBO_TRANSITION, RealKeyFrameDialog::OnComboTransition) + EVT_TEXT(ID_TEXT_FRAME_START, RealKeyFrameDialog::OnTextStartFrame) + EVT_TEXT(ID_TEXT_FRAME_END, RealKeyFrameDialog::OnTextEndFrame) + EVT_TEXT(ID_TEXT_INITIAL_VALUE, RealKeyFrameDialog::OnTextStartValue) + EVT_TEXT(ID_TEXT_FINAL_VALUE, RealKeyFrameDialog::OnTextEndValue) + // end wxGlade +END_EVENT_TABLE(); + +template +void RealKeyFrameDialog::updateOKButton() +{ + bool isOK=true; + isOK&=startFrameOK; + //step transitions need to be handled without end frame + isOK&=endFrameOK || transitionMode==TRANSITION_STEP; + + //Ensure start frame is > end frame + if(isOK && transitionMode != TRANSITION_STEP) + { + isOK&=(startFrameSetBackgroundColour(*wxCYAN); + textFrameEnd->SetBackgroundColour(*wxCYAN); + } + else + { + textFrameStart->SetBackgroundColour(wxNullColour); + textFrameEnd->SetBackgroundColour(wxNullColour); + } + } + + isOK&=startValueOK; + isOK&=endValueOK || transitionMode==TRANSITION_STEP; + + buttonOK->Enable(isOK); +} + +template +void RealKeyFrameDialog::OnComboTransition(wxCommandEvent &event) +{ + ASSERT(event.GetInt() < TRANSITION_END); + + transitionMode=event.GetInt(); + + textEndVal->Enable(transitionMode != TRANSITION_STEP); + textFrameEnd->Enable(transitionMode!=TRANSITION_STEP); +} + + +template +void RealKeyFrameDialog::OnTextStartFrame(wxCommandEvent &event) +{ + startFrameOK=validateTextAsStream(textFrameStart,startFrame); + updateOKButton(); +} + +template +void RealKeyFrameDialog::OnTextEndFrame(wxCommandEvent &event) +{ + endFrameOK=validateTextAsStream(textFrameEnd,endFrame); + updateOKButton(); +} + +template +void RealKeyFrameDialog::OnTextStartValue(wxCommandEvent &event) +{ + startValueOK=validateTextAsStream(textStartVal,startValue); + updateOKButton(); +} + +template<> +void RealKeyFrameDialog::OnTextStartValue(wxCommandEvent &evt) +{ + startValueOK=validatePoint3D(textStartVal,startValue); + updateOKButton(); +} + + +template +void RealKeyFrameDialog::OnTextEndValue(wxCommandEvent &event) +{ + endValueOK=validateTextAsStream(textEndVal,endValue); + updateOKButton(); +} + +template<> +void RealKeyFrameDialog::OnTextEndValue(wxCommandEvent &evt) +{ + endValueOK=validatePoint3D(textEndVal,endValue); + updateOKButton(); +} + +// wxGlade: add RealKeyFrameDialog event handlers + + +template +void RealKeyFrameDialog::set_properties() +{ + // begin wxGlade: RealKeyFrameDialog::set_properties + comboTransition->SetSelection(-1); + // end wxGlade +} + + +template +void RealKeyFrameDialog::do_layout() +{ + // begin wxGlade: RealKeyFrameDialog::do_layout + wxBoxSizer* sizerTop = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerBUttons = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* sizerMainArea = new wxStaticBoxSizer(sizerMainArea_staticbox, wxHORIZONTAL); + wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerRightEnd = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerRightStart = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerEndFrame = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerStartFrame = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerTransition = new wxBoxSizer(wxHORIZONTAL); + sizerTop->Add(20, 5, 0, 0, 0); + sizerMainArea->Add(10, 20, 0, 0, 0); + sizerLeft->Add(20, 10, 0, 0, 0); + sizerTransition->Add(labelTransition, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 14); + sizerTransition->Add(comboTransition, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 5); + sizerLeft->Add(sizerTransition, 1, wxEXPAND, 0); + sizerStartFrame->Add(labelFrameStart, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); + sizerStartFrame->Add(textFrameStart, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); + sizerLeft->Add(sizerStartFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerEndFrame->Add(labelFrameEnd, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 12); + sizerEndFrame->Add(textFrameEnd, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); + sizerLeft->Add(sizerEndFrame, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerLeft->Add(20, 10, 0, 0, 0); + sizerMainArea->Add(sizerLeft, 1, wxEXPAND, 0); + sizerMainArea->Add(verticalLine, 0, wxLEFT|wxRIGHT|wxEXPAND, 5); + sizerRight->Add(20, 20, 1, 0, 0); + sizerRightStart->Add(labelStartVal, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); + sizerRightStart->Add(textStartVal, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); + sizerRight->Add(sizerRightStart, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerRightEnd->Add(labelEndVal, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 9); + sizerRightEnd->Add(textEndVal, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 4); + sizerRight->Add(sizerRightEnd, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizerRight->Add(20, 20, 1, 0, 0); + sizerMainArea->Add(sizerRight, 1, wxEXPAND, 0); + sizerMainArea->Add(10, 20, 0, 0, 0); + sizerTop->Add(sizerMainArea, 1, wxEXPAND, 0); + sizerBUttons->Add(20, 20, 1, 0, 0); + sizerBUttons->Add(buttonCancel, 0, wxALL, 4); + sizerBUttons->Add(buttonOK, 0, wxALL, 4); + sizerTop->Add(sizerBUttons, 0, wxEXPAND, 0); + SetSizer(sizerTop); + sizerTop->Fit(this); + Layout(); + // end wxGlade +} + + + +#endif // REALKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,393 @@ +/* + * stringKeyFrameDialog.cpp - String value keyframe selection dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Sat Sep 22 21:13:08 2012 + +#include "stringKeyFrameDialog.h" + +#include "common/translation.h" + +#include "wxcommon.h" + +using std::string; +using std::vector; + +// begin wxGlade: ::extracode +enum +{ + ID_TEXT_START_FRAME, + ID_RADIO_FROM_FILE, + ID_TEXT_FROM_FILE, + ID_RADIO_FROM_TABLE, + ID_GRID_STRINGS +}; +// end wxGlade + + +StringKeyFrameDialog::StringKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +{ + // begin wxGlade: StringKeyFrameDialog::StringKeyFrameDialog + labelStartFrame = new wxStaticText(this, wxID_ANY, wxTRANS("Start Frame: ")); + textStartFrame = new wxTextCtrl(this, ID_TEXT_START_FRAME, wxEmptyString); + radioFromFile = new wxRadioButton(this, ID_RADIO_FROM_FILE, wxTRANS("From File")); + textFilename = new wxTextCtrl(this, ID_TEXT_FROM_FILE, wxEmptyString); + btnChooseFile = new wxButton(this, wxID_OPEN, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + radioFromTable = new wxRadioButton(this, ID_RADIO_FROM_TABLE, wxTRANS("From Table")); + gridStrings = new wxGrid(this, ID_GRID_STRINGS); + btnStringAdd = new wxButton(this, wxID_ADD, wxEmptyString); + btnRemove = new wxButton(this, wxID_REMOVE, wxEmptyString); + btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + + + + set_properties(); + do_layout(); + // end wxGlade + startFrame=0; + startFrameOK=filenameOK=false; + string s; + stream_cast(s,startFrame); + textStartFrame->SetValue(wxStr(s)); + + radioFromFile->SetValue(true); + + dataSourceFromFile=radioFromFile->GetValue(); +} + + +BEGIN_EVENT_TABLE(StringKeyFrameDialog, wxDialog) + // begin wxGlade: StringKeyFrameDialog::event_table + EVT_TEXT(ID_TEXT_START_FRAME, StringKeyFrameDialog::OnTextStart) + EVT_RADIOBUTTON(ID_RADIO_FROM_FILE, StringKeyFrameDialog::OnFileRadio) + EVT_TEXT(ID_TEXT_FROM_FILE, StringKeyFrameDialog::OnTextFilename) + EVT_BUTTON(wxID_OPEN, StringKeyFrameDialog::OnBtnChooseFile) + EVT_RADIOBUTTON(ID_RADIO_FROM_TABLE, StringKeyFrameDialog::OnTableRadio) + EVT_GRID_CMD_CELL_CHANGE(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridCellChange) + EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridEditorShown) + EVT_BUTTON(wxID_ADD, StringKeyFrameDialog::OnBtnAdd) + EVT_BUTTON(wxID_REMOVE, StringKeyFrameDialog::OnBtnRemove) + // end wxGlade +END_EVENT_TABLE(); + +size_t StringKeyFrameDialog::getStartFrame() const +{ + ASSERT(startFrameOK); + return startFrame; +} + +void StringKeyFrameDialog::buildGrid() +{ + gridStrings->BeginBatch(); + //Empty the grid + if(gridStrings->GetNumberCols()) + gridStrings->DeleteCols(0,gridStrings->GetNumberCols()); + if(gridStrings->GetNumberRows()) + gridStrings->DeleteRows(0,gridStrings->GetNumberRows()); + + gridStrings->AppendCols(2); + gridStrings->SetColLabelValue(0,wxTRANS("Frame")); + gridStrings->SetColLabelValue(1,wxTRANS("Value")); + + gridStrings->AppendRows(valueStrings.size()); + + wxGridCellAttr *readOnlyColAttr=new wxGridCellAttr; + readOnlyColAttr->SetReadOnly(true); + gridStrings->SetColAttr(0,readOnlyColAttr); + + for(size_t ui=0;uiSetCellValue(ui,0,wxStr(pos)); + gridStrings->SetCellValue(ui,1,wxStr(valueStrings[ui])); + } + gridStrings->EndBatch(); +} + +bool StringKeyFrameDialog::getStrings(vector &res) const +{ + if(dataSourceFromFile) + { + vector > dataVec; + if(loadTextStringData(dataFilename.c_str(), dataVec,"\t")) + return false; + + res.reserve(dataVec.size()); + for(size_t ui=0;uiGetValue(); + if(dataSourceFromFile) + { + //Disable grid & enable text box + gridStrings->Enable(false); + textFilename->Enable(true); + btnChooseFile->Enable(true); + } + else + { + //Enable grid & disable text box + gridStrings->Enable(true); + textFilename->Enable(false); + btnChooseFile->Enable(false); + } +} + +void StringKeyFrameDialog::OnTableRadio(wxCommandEvent &event) +{ + dataSourceFromFile=!radioFromTable->GetValue(); + if(dataSourceFromFile) + { + //Disable grid & enable text box + gridStrings->Enable(false); + textFilename->Enable(true); + btnChooseFile->Enable(true); + } + else + { + //Enable grid & disable text box + gridStrings->Enable(true); + textFilename->Enable(false); + btnChooseFile->Enable(false); + } +} +void StringKeyFrameDialog::OnTextFilename(wxCommandEvent &event) +{ + if(!wxFileExists(textFilename->GetValue())) + { + textFilename->SetBackgroundColour(*wxCYAN); + filenameOK=false; + dataFilename.clear(); + } + else + { + textFilename->SetBackgroundColour(wxNullColour); + filenameOK=true; + dataFilename=stlStr(textFilename->GetValue()); + } + + updateOKButton(); +} + +void StringKeyFrameDialog::updateOKButton() +{ + bool isOK=true; + isOK&=startFrameOK; + + if(dataSourceFromFile) + isOK&=filenameOK; + else + isOK&=(bool)(valueStrings.size()); + + btnOK->Enable(isOK); +} + +void StringKeyFrameDialog::OnGridCellChange(wxGridEvent &event) +{ + std::string s; + s=stlStr(gridStrings->GetCellValue(event.GetRow(),event.GetCol())); + valueStrings[event.GetRow()] = s; +} + +void StringKeyFrameDialog::OnGridEditorShown(wxGridEvent &event) +{ + event.Skip(); + wxLogDebug(wxT("Event handler (StringKeyFrameDialog::OnGridEditorShown) not implemented yet")); //notify the user that he hasn't implemented the event handler yet +} + +void StringKeyFrameDialog::OnBtnChooseFile(wxCommandEvent &event) +{ + //Pop up a directory dialog, to choose the base path for the new folder + wxFileDialog *wxD = new wxFileDialog(this,wxTRANS("Select text file..."), wxT(""), + wxT(""),wxTRANS("Text files (*.txt)|*.txt;|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST); + + unsigned int res; + res = wxD->ShowModal(); + + while(res != wxID_CANCEL) + { + //If dir exists, exit + if(wxFileExists(wxD->GetPath())) + break; + + res=wxD->ShowModal(); + } + + //User aborted directory choice. + if(res==wxID_CANCEL) + { + wxD->Destroy(); + return; + } + + textFilename->SetValue(wxD->GetPath()); + wxD->Destroy(); +} + + +void StringKeyFrameDialog::OnBtnAdd(wxCommandEvent &event) +{ + wxMouseState wxm = wxGetMouseState(); + if(wxm.ShiftDown()) + valueStrings.resize(valueStrings.size() + 5,""); + else if (wxm.CmdDown()) + valueStrings.resize(valueStrings.size() + 10,""); + else + valueStrings.push_back(""); + buildGrid(); + updateOKButton(); +} + +void StringKeyFrameDialog::OnBtnRemove(wxCommandEvent &event) +{ + if(!gridStrings->GetNumberRows()) + return; + // Whole selected rows. + const wxArrayInt& rows(gridStrings->GetSelectedRows()); + for (size_t i = rows.size(); i--; ) + { + valueStrings.erase(valueStrings.begin() + rows[i], + valueStrings.begin()+rows[i]+1); + } + + + if(!rows.size()) + { + + //Obtain the IDs of the selected rows, or partially selected rows + wxGridCellCoordsArray selectedRows = gridStrings->GetSelectedCells(); + + wxGridCellCoordsArray arrayTL(gridStrings->GetSelectionBlockTopLeft()); + wxGridCellCoordsArray arrayBR(gridStrings->GetSelectionBlockBottomRight()); + + //This is an undocumented class AFAIK. :( + if(arrayTL.Count() && arrayBR.Count()) + { + //Grab the coordinates f the selection block, + // top left (TL) and bottom right (BR) + wxGridCellCoords coordTL = arrayTL.Item(0); + wxGridCellCoords coordBR = arrayBR.Item(0); + + size_t rows = coordBR.GetRow() - coordTL.GetRow()+1; + + ASSERT(coordTL.GetRow()+rows-1GetGridCursorRow(); + ASSERT(rowToKillSetToolTip(wxTRANS("Frame offset for data start")); + textFilename->SetToolTip(wxTRANS("File to use as string data source, one value per row")); + btnChooseFile->SetToolTip(wxTRANS("Select file to use as data source")); + radioFromTable->SetToolTip(wxTRANS("Use table below for data source")); + gridStrings->CreateGrid(0, 2); + gridStrings->SetColLabelValue(0, wxTRANS("Frame")); + gridStrings->SetColSize(0, 1); + gridStrings->SetColLabelValue(1, wxTRANS("Value")); + gridStrings->SetColSize(1, 3); + btnStringAdd->SetToolTip(wxTRANS("Add new data rows to table, hold shift/cmd to insert multiple rows")); + btnRemove->SetToolTip(wxTRANS("Remove selected strings from table")); + btnCancel->SetToolTip(wxTRANS("Abort value selection and return to previous window")); + btnOK->SetToolTip(wxTRANS("Accept data values")); + // end wxGlade +} + + +void StringKeyFrameDialog::do_layout() +{ + // begin wxGlade: StringKeyFrameDialog::do_layout + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* footerSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* gridAreaSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* gridButtonSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* fromFileSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* startFrameSizer = new wxBoxSizer(wxHORIZONTAL); + startFrameSizer->Add(labelStartFrame, 0, wxALIGN_CENTER_VERTICAL, 0); + startFrameSizer->Add(textStartFrame, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 6); + startFrameSizer->Add(20, 20, 1, 0, 0); + mainSizer->Add(startFrameSizer, 0, wxALL|wxEXPAND, 6); + fromFileSizer->Add(radioFromFile, 0, wxALIGN_CENTER_VERTICAL, 0); + fromFileSizer->Add(textFilename, 1, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 6); + fromFileSizer->Add(btnChooseFile, 0, wxLEFT|wxRIGHT, 6); + mainSizer->Add(fromFileSizer, 0, wxALL|wxEXPAND, 6); + mainSizer->Add(radioFromTable, 0, wxLEFT, 6); + gridAreaSizer->Add(gridStrings, 1, wxALL|wxEXPAND, 5); + gridButtonSizer->Add(btnStringAdd, 0, wxBOTTOM, 5); + gridButtonSizer->Add(btnRemove, 0, 0, 0); + gridAreaSizer->Add(gridButtonSizer, 0, wxRIGHT|wxEXPAND, 5); + mainSizer->Add(gridAreaSizer, 1, wxEXPAND, 0); + footerSizer->Add(20, 20, 1, 0, 0); + footerSizer->Add(btnCancel, 0, wxALL, 5); + footerSizer->Add(btnOK, 0, wxALL, 5); + mainSizer->Add(footerSizer, 0, wxEXPAND, 0); + SetSizer(mainSizer); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h --- 3depict-0.0.12/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,101 @@ +/* + * stringKeyFrameDialog.h -String value keyframe selection dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Sat Sep 22 21:13:08 2012 + +#include +// begin wxGlade: ::dependencies +#include +// end wxGlade + +#include + + +#ifndef STRINGKEYFRAMEDIALOG_H +#define STRINGKEYFRAMEDIALOG_H + + +class StringKeyFrameDialog: public wxDialog { +public: + // begin wxGlade: StringKeyFrameDialog::ids + // end wxGlade + + StringKeyFrameDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + + //!Data + size_t getStartFrame() const ; + + bool getStrings(std::vector &res) const; + +private: + // begin wxGlade: StringKeyFrameDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //!Should we be using a file as the string data source? + bool dataSourceFromFile; + + //!File to use as the data source + std::string dataFilename; + + //!Initial frame to use for value strings + size_t startFrame; + + //strings that are to be used as the data for each frame + std::vector valueStrings; + + //!Check to see if the various data elements are OK + bool startFrameOK, filenameOK,gridOK; + + //Enable/disable OK button, checking dialog content validity + void updateOKButton(); + + //Build the grid UI from the internal string value data + void buildGrid(); + +protected: + // begin wxGlade: StringKeyFrameDialog::attributes + wxStaticText* labelStartFrame; + wxTextCtrl* textStartFrame; + wxRadioButton* radioFromFile; + wxTextCtrl* textFilename; + wxButton* btnChooseFile; + wxRadioButton* radioFromTable; + wxGrid* gridStrings; + wxButton* btnStringAdd; + wxButton* btnRemove; + wxButton* btnCancel; + wxButton* btnOK; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnTextStart(wxCommandEvent &event); // wxGlade: + virtual void OnFileRadio(wxCommandEvent &event); // wxGlade: + virtual void OnTextFilename(wxCommandEvent &event); // wxGlade: + virtual void OnBtnChooseFile(wxCommandEvent &event); // wxGlade: + virtual void OnTableRadio(wxCommandEvent &event); // wxGlade: + virtual void OnGridCellChange(wxGridEvent &event); // wxGlade: + virtual void OnGridEditorShown(wxGridEvent &event); // wxGlade: + virtual void OnBtnAdd(wxCommandEvent &event); // wxGlade: + virtual void OnBtnRemove(wxCommandEvent &event); // wxGlade: +}; // wxGlade: end class + + +#endif // STRINGKEYFRAMEDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/autosaveDialog.cpp 3depict-0.0.13/src/gui/dialogs/autosaveDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/autosaveDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/autosaveDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * autosaveDialog.cpp - Selection of autosaves for hard program restarts + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Thu Jun 7 12:47:44 2012 + +#include "autosaveDialog.h" +#include "wxcommon.h" +#include "common/translation.h" +// begin wxGlade: ::extracode + +// end wxGlade + + + +AutosaveDialog::AutosaveDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +{ + + selectedItem=(size_t)-1; + haveRemovedItems=false; + + // begin wxGlade: AutosaveDialog::AutosaveDialog + const wxString *listStates_choices = NULL; + listStates = new wxListBox(this, ID_LIST_STATES, wxDefaultPosition, wxDefaultSize, 0, listStates_choices, wxLB_SINGLE|wxLB_NEEDED_SB); + btnRemoveAll = new wxButton(this, ID_REMOVE_ALL, wxTRANS("Remove &All")); + btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + + + btnOK->Enable(false); + set_properties(); + do_layout(); + // end wxGlade + + //Force setting focus on the list control, because otherwise, pressing ESCAPE doesn't work for the user + listStates->SetFocus(); +} + + +BEGIN_EVENT_TABLE(AutosaveDialog, wxDialog) + // begin wxGlade: AutosaveDialog::event_table + EVT_LISTBOX_DCLICK(ID_LIST_STATES, AutosaveDialog::OnListStatesDClick) + EVT_LISTBOX(ID_LIST_STATES, AutosaveDialog::OnListStates) + EVT_BUTTON(ID_REMOVE_ALL, AutosaveDialog::OnRemoveAll) + EVT_BUTTON(wxID_CANCEL, AutosaveDialog::OnCancel) + EVT_BUTTON(wxID_OK, AutosaveDialog::OnOK) + // end wxGlade +END_EVENT_TABLE(); + +void AutosaveDialog::OnListStates(wxCommandEvent &event) +{ + //Get the first selected item + selectedItem= listStates->GetSelection(); + + //Enable the OK button if and only if there is a valid + // selection + btnOK->Enable(selectedItem != -1); + +} + +void AutosaveDialog::OnListStatesDClick(wxCommandEvent &event) +{ + EndModal(wxID_OK); +} + + +void AutosaveDialog::OnRemoveAll(wxCommandEvent &event) +{ + selectedItem=-1; + btnOK->Enable(false); + + haveRemovedItems=true; + btnRemoveAll->Enable(false); + listStates->Clear(); + listStates->Enable(false); + //Force setting focus now on the cancel button , + //because otherwise, pressing ESCAPE doesn't work + // on the list control + btnCancel->SetFocus(); +} + + +void AutosaveDialog::OnCancel(wxCommandEvent &event) +{ + EndModal(wxID_CANCEL); +} + + +void AutosaveDialog::OnOK(wxCommandEvent &event) +{ + //Require an item to be selected + ASSERT(selectedItem != -1) + + EndModal(wxID_OK); +} + + +// wxGlade: add AutosaveDialog event handlers + +void AutosaveDialog::setItems( const std::vector &newItems) +{ + for(size_t ui=0;uiInsert(wxStr(newItems[ui]),ui); +} + +void AutosaveDialog::set_properties() +{ + // begin wxGlade: AutosaveDialog::set_properties + SetTitle(wxTRANS("Restore state?")); + // end wxGlade +} + + +void AutosaveDialog::do_layout() +{ + // begin wxGlade: AutosaveDialog::do_layout + wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* labelHeader = new wxStaticText(this, wxID_ANY, wxTRANS("Multiple autosave states were found; would you like to restore one?"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + sizer_1->Add(labelHeader, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 8); + sizer_1->Add(listStates, 1, wxALL|wxEXPAND, 8); + sizer_2->Add(btnRemoveAll, 0, wxLEFT|wxBOTTOM, 8); + sizer_2->Add(20, 20, 1, 0, 0); + sizer_2->Add(btnCancel, 0, wxLEFT|wxRIGHT|wxBOTTOM, 8); + sizer_2->Add(btnOK, 0, wxRIGHT|wxBOTTOM, 8); + sizer_1->Add(sizer_2, 0, wxEXPAND, 0); + SetSizer(sizer_1); + sizer_1->Fit(this); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/autosaveDialog.h 3depict-0.0.13/src/gui/dialogs/autosaveDialog.h --- 3depict-0.0.12/src/gui/dialogs/autosaveDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/autosaveDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * autosaveDialog.h - Selection dialog on recovery from autosave files + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.5 on Thu Jun 7 12:47:44 2012 + +#include +// begin wxGlade: ::dependencies +// end wxGlade + + +#ifndef AUTOSAVEDIALOG_H +#define AUTOSAVEDIALOG_H +#include + +// begin wxGlade: ::extracode +enum +{ + ID_LIST_STATES = wxID_ANY+1, + ID_REMOVE_ALL +}; +// end wxGlade + + +class AutosaveDialog: public wxDialog { +public: + // begin wxGlade: AutosaveDialog::ids + // end wxGlade + + AutosaveDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=wxT(""), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + +private: + // begin wxGlade: AutosaveDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //! the index of the selected item, -1 otherwise + size_t selectedItem; + + //True if the remove all button was + // depressed + bool haveRemovedItems; +protected: + // begin wxGlade: AutosaveDialog::attributes + wxListBox* listStates; + wxButton* btnRemoveAll; + wxButton* btnCancel; + wxButton* btnOK; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnListStates(wxCommandEvent &event); // wxGlade: + virtual void OnListStatesDClick(wxCommandEvent &event); // wxGlade: + virtual void OnRemoveAll(wxCommandEvent &event); // wxGlade: + virtual void OnCancel(wxCommandEvent &event); // wxGlade: + virtual void OnOK(wxCommandEvent &event); // wxGlade: + + //Set the items that are to be displayed in the listbox. + void setItems(const std::vector &items); + //!Get the item that was selected, returning the position of the selected + // item in the original vector + unsigned int getSelectedItem() const { return selectedItem;}; + + //Has the user require cited to remove items? + bool removedItems() const {return haveRemovedItems;}; + +}; // wxGlade: end class + + +#endif // AUTOSAVEDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/filterErrorDialog.cpp 3depict-0.0.13/src/gui/dialogs/filterErrorDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/filterErrorDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/filterErrorDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * filterErrorDialog.cpp - Dialog for displaying error notices computed from filter tree + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.3 on Sun Jun 24 00:03:00 2012 + +#include "filterErrorDialog.h" +#include "wxcommon.h" +#include "common/translation.h" +//Art for buttons +#include +// begin wxGlade: ::extracode +// end wxGlade + +using std::string; + + +FilterErrorDialog::FilterErrorDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +{ + // begin wxGlade: FilterErrorDialog::FilterErrorDialog + textErrorMessage = new wxTextCtrl(this, wxID_ANY, wxEmptyString,wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE|wxTE_READONLY); + bitmapError = new wxStaticBitmap(this, wxID_ANY, wxArtProvider::GetBitmap(wxART_ERROR)); + labelError = new wxStaticText(this, wxID_ANY, wxTRANS("Error")); + bitmapWarning = new wxStaticBitmap(this, wxID_ANY,wxArtProvider::GetBitmap(wxART_WARNING)); + labelWarning = new wxStaticText(this, wxID_ANY, wxTRANS("Warning")); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + + SetTitle(wxTRANS("Filter Errors")); + set_properties(); + do_layout(); + // end wxGlade +} + + +void FilterErrorDialog::set_properties() +{ + // begin wxGlade: FilterErrorDialog::set_properties + SetTitle(wxTRANS("Filter Errors")); + SetSize(wxSize(551, 414)); + // end wxGlade +} + +void FilterErrorDialog::SetText(const std::vector &text) +{ + std::string bigMessage; + for(unsigned int ui=0;uiClear(); + textErrorMessage->AppendText(wxStr(bigMessage)); +} + +void FilterErrorDialog::do_layout() +{ + // begin wxGlade: FilterErrorDialog::do_layout + wxBoxSizer* sizerMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerTop = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerKey = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerWarn = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerError = new wxBoxSizer(wxHORIZONTAL); + sizerTop->Add(textErrorMessage, 4, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 6); + sizerKey->Add(10, 10, 0, 0, 0); + sizerError->Add(bitmapError, 0, 0, 0); + sizerError->Add(labelError, 0, wxALIGN_CENTER_VERTICAL, 0); + sizerKey->Add(sizerError, 0, wxTOP|wxEXPAND, 5); + sizerWarn->Add(bitmapWarning, 0, 0, 0); + sizerWarn->Add(labelWarning, 0, wxALIGN_CENTER_VERTICAL, 0); + sizerKey->Add(sizerWarn, 0, wxTOP|wxEXPAND, 6); + sizerKey->Add(20, 20, 0, 0, 0); + sizerTop->Add(sizerKey, 1, wxEXPAND, 0); + sizerMain->Add(sizerTop, 1, wxEXPAND, 0); + sizerMain->Add(btnOK, 0, wxALL|wxALIGN_RIGHT, 5); + SetSizer(sizerMain); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/filterErrorDialog.h 3depict-0.0.13/src/gui/dialogs/filterErrorDialog.h --- 3depict-0.0.12/src/gui/dialogs/filterErrorDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/filterErrorDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * filterErrorDialog.h - Dialog for displaying error notices computed from filter tree + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.3 on Sun Jun 24 00:03:00 2012 + +#include + +#include +// begin wxGlade: ::dependencies +// end wxGlade + + +#ifndef FILTERERRORDIALOG_H +#define FILTERERRORDIALOG_H + + +// begin wxGlade: ::extracode +// end wxGlade + + +class FilterErrorDialog: public wxDialog { +public: + // begin wxGlade: FilterErrorDialog::ids + // end wxGlade + + FilterErrorDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=wxT(""), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + + void SetText(const std::vector &text); +private: + // begin wxGlade: FilterErrorDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + +protected: + // begin wxGlade: FilterErrorDialog::attributes + wxTextCtrl* textErrorMessage; + wxStaticBitmap* bitmapError; + wxStaticText* labelError; + wxStaticBitmap* bitmapWarning; + wxStaticText* labelWarning; + wxButton* btnOK; + // end wxGlade +}; // wxGlade: end class + + +#endif // FILTERERRORDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/prefDialog.cpp 3depict-0.0.13/src/gui/dialogs/prefDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/prefDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/prefDialog.cpp 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,627 @@ +/* + * prefDialog.cpp - mathgl plot wrapper 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 . +*/ + +// -*- C++ -*- generated by wxGlade HG on Fri Dec 3 22:26:29 2010 + +#include "prefDialog.h" + +#include "backend/filters/allFilter.h" +#include "backend/viscontrol.h" +#include "common/stringFuncs.h" + +#include "wxcommon.h" +#include "wxcomponents.h" + +#include + + +using std::vector; + + + +// begin wxGlade: ::extracode +// end wxGlade +enum +{ + ID_LIST_FILTERS = wxID_ANY+1, + ID_GRID_PROPERTIES, + ID_BTN_RESET_FILTER, + ID_BTN_RESET_FILTER_ALL, + ID_START_CHECK_CONTROL, + ID_START_CHECK_PLOTLIST, + ID_START_CHECK_RAWDATA, + ID_START_COMBO_PANEL, + ID_MOUSE_MOVE_SLIDER, + ID_MOUSE_ZOOM_SLIDER, +}; + + +//Number that +enum +{ + STARTUP_COMBO_SELECT_SHOW_ALL, + STARTUP_COMBO_SELECT_REMEMBER, + STARTUP_COMBO_SELECT_SPECIFY +}; + + +PrefDialog::PrefDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, style) +{ + SetTitle(wxTRANS("Preferences")); + // begin wxGlade: prefDialog::prefDialog + notePrefPanels = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); + notePrefPanels_pane_3 = new wxPanel(notePrefPanels, wxID_ANY); + panelStartup = new wxPanel(notePrefPanels, wxID_ANY); + panelFilters = new wxPanel(notePrefPanels, wxID_ANY); +#ifndef DISABLE_ONLINE_UPDATE + updateSizer_staticbox = new wxStaticBox(panelStartup, -1, wxTRANS("Online Updates")); +#endif + sizer_2_staticbox = new wxStaticBox(panelStartup, -1, wxTRANS("Panel Display")); + sizerCamSpeed_staticbox = new wxStaticBox(notePrefPanels_pane_3, -1, wxTRANS("Camera Speed")); + filterPropSizer_staticbox = new wxStaticBox(panelFilters, -1, wxTRANS("Filter Defaults")); + lblFilters = new wxStaticText(panelFilters, wxID_ANY, wxTRANS("Available Filters")); + listFilters = new wxListBox(panelFilters, ID_LIST_FILTERS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_SORT); + filterGridProperties = new wxPropertyGrid(panelFilters, ID_GRID_PROPERTIES); + filterBtnResetAllFilters = new wxButton(panelFilters, ID_BTN_RESET_FILTER_ALL, wxTRANS("Reset All")); + filterResetDefaultFilter = new wxButton(panelFilters, ID_BTN_RESET_FILTER, wxTRANS("Reset")); + const wxString comboPanelStartMode_choices[] = { + wxNTRANS("Show all panels"), + wxNTRANS("Remember last"), + wxNTRANS("Show Selected") + }; + comboPanelStartMode = new wxComboBox(panelStartup, ID_START_COMBO_PANEL, wxT(""), wxDefaultPosition, wxDefaultSize, 3, comboPanelStartMode_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY); + chkControl = new wxCheckBox(panelStartup, ID_START_CHECK_CONTROL, wxTRANS("Control Pane")); + chkRawData = new wxCheckBox(panelStartup, ID_START_CHECK_RAWDATA, wxTRANS("Raw Data Panel")); + chkPlotlist = new wxCheckBox(panelStartup, ID_START_CHECK_PLOTLIST, wxTRANS("Plot List")); +#ifndef DISABLE_ONLINE_UPDATE + checkAllowOnlineUpdate = new wxCheckBox(panelStartup, wxID_ANY, wxTRANS("Periodically notify about available updates")); +#endif + lblMoveSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Move Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + labelSlowCamMoveRate = new wxStaticText(notePrefPanels_pane_3,wxID_ANY, wxTRANS("(slow)")); + sliderCamMoveRate = new wxSlider(notePrefPanels_pane_3, ID_MOUSE_MOVE_SLIDER, 25, 1, 400,wxDefaultPosition,wxDefaultSize,wxSL_HORIZONTAL|wxSL_LABELS); + labelFastCamMoveRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(fast)")); + lblZoomSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Zoom Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + labelSlowCamZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(slow)")); + sliderCamZoomRate = new wxSlider(notePrefPanels_pane_3, ID_MOUSE_ZOOM_SLIDER, 25, 1, 400,wxDefaultPosition,wxDefaultSize,wxSL_HORIZONTAL|wxSL_LABELS); + labelSlowFastZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(fast)")); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString); + + filterGridProperties->CreateGrid(0, 2); + filterGridProperties->EnableDragRowSize(false); + filterGridProperties->SetColLabelValue(0, wxTRANS("Param")); + filterGridProperties->SetColLabelValue(1, wxTRANS("Value")); + + bool enable=(comboPanelStartMode->GetSelection() == STARTUP_COMBO_SELECT_SPECIFY); + + chkRawData->Enable(enable); + chkControl->Enable(enable); + chkPlotlist->Enable(enable); + + comboPanelStartMode->SetSelection(0); + programmaticEvent=false; + curFilter=0; + + set_properties(); + do_layout(); + // end wxGlade +} + +PrefDialog::~PrefDialog() +{ + filterGridProperties->Destroy(); +} + +BEGIN_EVENT_TABLE(PrefDialog, wxDialog) + // begin wxGlade: PrefDialog::event_table + EVT_LISTBOX(ID_LIST_FILTERS, PrefDialog::OnFilterListClick) + EVT_GRID_CMD_CELL_CHANGE(ID_GRID_PROPERTIES, PrefDialog::OnFilterCellChange) + EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_PROPERTIES,PrefDialog::OnFilterGridCellEditorShow) + EVT_BUTTON(ID_BTN_RESET_FILTER,PrefDialog::OnResetFilterButton) + EVT_BUTTON(ID_BTN_RESET_FILTER_ALL,PrefDialog::OnResetFilterAllButton) + EVT_COMBOBOX(ID_START_COMBO_PANEL, PrefDialog::OnStartupPanelCombo) + EVT_COMMAND_SCROLL(ID_MOUSE_ZOOM_SLIDER, PrefDialog::OnMouseZoomSlider) + EVT_COMMAND_SCROLL(ID_MOUSE_MOVE_SLIDER, PrefDialog::OnMouseMoveSlider) + // end wxGlade +END_EVENT_TABLE(); + + +void PrefDialog::createFilterListing() +{ + listFilters->Clear(); + + wxString s; + vector v; + for(size_t ui=0;uitypeString()); + v.push_back(filterDefaults[ui]->getType()); + listFilters->Append(s); + } + + std::sort(v.begin(),v.end()); + unsigned int pos=0; + for(unsigned int ui=0;ui=v.size() || v[pos] != ui) + { + //This is a bit of a hack, but it works. + Filter *t; + t=makeFilter(ui); + s = wxStr(t->typeString()); + listFilters->Append(s); + delete t; + } + else + pos++; + } + +} + +void PrefDialog::initialise() +{ + createFilterListing(); + + //Transfer the movement rates from class to the slider + ASSERT(mouseZoomRatePercent >=sliderCamZoomRate->GetMin() && + mouseZoomRatePercent <=sliderCamZoomRate->GetMax()); + ASSERT(mouseMoveRatePercent >=sliderCamMoveRate->GetMin() && + mouseMoveRatePercent <=sliderCamMoveRate->GetMax()); + + + sliderCamZoomRate->SetValue(mouseZoomRatePercent); + sliderCamMoveRate->SetValue(mouseMoveRatePercent); + + + +} + +void PrefDialog::cleanup() +{ + for(unsigned int ui=0;ui &defs) const +{ + defs.resize(filterDefaults.size()); + + for(unsigned int ui=0;uicloneUncached(); +} + +void PrefDialog::setFilterDefaults(const vector &defs) +{ + filterDefaults.resize(defs.size()); + + for(unsigned int ui=0;uicloneUncached(); +} + +void PrefDialog::OnFilterListClick(wxCommandEvent &event) +{ + + //get the string associated with the current click + string s; + + //Check to see if we need to delete the current filter + //or if we have it as a default + if(find(filterDefaults.begin(),filterDefaults.end(), + curFilter) == filterDefaults.end()) + delete curFilter; + + + Filter *f=0; + s=stlStr(listFilters->GetString(event.GetSelection())); + + for(size_t ui=0;uigetUserString() == s) + { + f=filterDefaults[ui]; + break; + } + } + + if(!f) + f=makeFilterFromDefUserString(s); + + ASSERT(f); + updateFilterProp(f); + + curFilter=f; +} + + +void PrefDialog::OnFilterCellChange(wxGridEvent &event) +{ + //Disallow programmatic event from causing filter update (stack loop->overflow) + if(programmaticEvent) + { + event.Veto(); + return; + } + + //Grab the changed value + std::string value; + int row=event.GetRow(); + value = stlStr(filterGridProperties->GetCellValue( + row,1)); + programmaticEvent=true; + + bool needUpdate; + curFilter->setProperty(filterGridProperties->getKeyFromRow(row), + value,needUpdate); + + if(find(filterDefaults.begin(),filterDefaults.end(), + curFilter) == filterDefaults.end()) + filterDefaults.push_back(curFilter); + + updateFilterProp(curFilter); + programmaticEvent=false; +} + + + +//This function modifies the properties before showing the cell content editor.T +//This is needed only for certain data types (colours, bools) other data types are edited +//using the default editor and modified using ::OnGridFilterPropertyChange +void PrefDialog::OnFilterGridCellEditorShow(wxGridEvent &event) +{ + //Find where the event occurred (cell & property) + const GRID_PROPERTY *item=0; + + unsigned int key; + key=filterGridProperties->getKeyFromRow(event.GetRow()); + + item=filterGridProperties->getProperty(key); + + bool needUpdate; + switch(item->type) + { + case PROPERTY_TYPE_BOOL: + { + std::string s; + //Toggle the property in the grid + if(item->data == "0") + s= "1"; + else + s="0"; + curFilter->setProperty(key,s,needUpdate); + + event.Veto(); + + updateFilterProp(curFilter); + break; + } + case PROPERTY_TYPE_COLOUR: + { + //Show a wxColour choose dialog. + wxColourData d; + + unsigned char r,g,b,a; + parseColString(item->data,r,g,b,a); + + d.SetColour(wxColour(r,g,b,a)); + wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); + + + if( colDg->ShowModal() == wxID_OK) + { + wxColour c; + //Change the colour + c=colDg->GetColourData().GetColour(); + + std::string s; + genColString(c.Red(),c.Green(),c.Blue(),s); + + //Pass the new colour to the viscontrol system, which updates + //the filters + curFilter->setProperty(key,s,needUpdate); + } + + //Set the filter property + //Disallow direct editing of the grid cell + event.Veto(); + + + updateFilterProp(curFilter); + break; + } + case PROPERTY_TYPE_CHOICE: + break; + default: + //we will handle this after the user has edited the cell contents + break; + } + + //Add to the modified filter defaults as needed + if(find(filterDefaults.begin(),filterDefaults.end(), + curFilter) == filterDefaults.end()) + filterDefaults.push_back(curFilter); +} + +void PrefDialog::OnResetFilterButton(wxCommandEvent &evt) +{ + + if(!curFilter) + { + evt.Skip(); + return; + } + + //Erase the filter from the modified defaults list + for(size_t ui=0;uiGetString( + listFilters->GetSelection())); + curFilter=makeFilterFromDefUserString(s); + + //Update the prop grid + updateFilterProp(curFilter); + break; + } + } + +} + +void PrefDialog::OnResetFilterAllButton(wxCommandEvent &evt) +{ + if(!curFilter) + { + evt.Skip(); + return; + } + + //Check to see if we have it in the non-"true" default list + for(size_t ui=0;uiGetString( + listFilters->GetSelection())); + + curFilter=makeFilterFromDefUserString(s); + updateFilterProp(curFilter); +} + + +void PrefDialog::updateFilterProp(const Filter *f) +{ + if(!(f->canBeHazardous())) + { + filterGridProperties->Enable(true); + updateFilterPropertyGrid(filterGridProperties,f); + } + else + { + //If the filter is potentially hazardous, + //then we will disallow editing of the properties. + //and give a notice to that effect + filterGridProperties->BeginBatch(); + filterGridProperties->Enable(false); + wxGridCellAttr *readOnlyColAttr=new wxGridCellAttr; + + //Empty the grid + //then fill it up with a note. + if(filterGridProperties->GetNumberCols()) + filterGridProperties->DeleteCols(0,filterGridProperties->GetNumberCols()); + if(filterGridProperties->GetNumberRows()) + filterGridProperties->DeleteRows(0,filterGridProperties->GetNumberRows()); + + filterGridProperties->AppendRows(1); + filterGridProperties->AppendCols(1); + filterGridProperties->AutoSizeColumn(0,true); + filterGridProperties->SetColAttr(0,readOnlyColAttr); + filterGridProperties->SetColLabelValue(0,wxTRANS("Notice")); + + filterGridProperties->SetCellValue(0,0, + wxTRANS("For security reasons, defaults are not modifiable for this filter")); + + filterGridProperties->EndBatch(); + + //Set the column size so you can see the message + filterGridProperties->SetColSize(0, filterGridProperties->GetSize().GetWidth() + - filterGridProperties->GetScrollThumb(wxVERTICAL) - 15); + + } +} + +//-------------- End Filter page----------------------- + +//-------------- Startup panel page----------------------- + +void PrefDialog::OnStartupPanelCombo(wxCommandEvent &event) +{ + setStartupCheckboxEnables(event.GetSelection()); +} + +void PrefDialog::setStartupCheckboxEnables(unsigned int value) +{ + bool enable=( value == STARTUP_COMBO_SELECT_SPECIFY); + + chkRawData->Enable(enable); + chkControl->Enable(enable); + chkPlotlist->Enable(enable); + switch(value) + { + case STARTUP_COMBO_SELECT_SHOW_ALL: + comboPanelStartMode->SetToolTip(wxTRANS("Show all panels when starting program")); + break; + case STARTUP_COMBO_SELECT_REMEMBER: + comboPanelStartMode->SetToolTip(wxTRANS("Show panels visible at last shutdown when starting program")); + + chkRawData->SetValue(true); + chkControl->SetValue(true); + chkPlotlist->SetValue(true); + break; + case STARTUP_COMBO_SELECT_SPECIFY: + comboPanelStartMode->SetToolTip(wxTRANS("Show selected panels when starting program")); + break; + default: + ASSERT(false); + } +} +void PrefDialog::setPanelDefaults(unsigned int panelMode, bool panelControl, + bool panelRaw,bool panelPlotlist) +{ + ASSERT(panelMode < comboPanelStartMode->GetCount()); + + chkRawData->SetValue(panelRaw); + chkControl->SetValue(panelControl); + chkPlotlist->SetValue(panelPlotlist); + + comboPanelStartMode->SetSelection(panelMode); + setStartupCheckboxEnables(panelMode); + +} +void PrefDialog::getPanelDefaults(unsigned int &panelMode, bool &panelControl, + bool &panelRaw,bool &panelPlotlist) const +{ + panelControl=chkControl->IsChecked(); + panelRaw=chkRawData->IsChecked(); + panelPlotlist=chkPlotlist->IsChecked(); + + panelMode=comboPanelStartMode->GetSelection(); +} + + +//-------------- End Startup panel page----------------------- + + +//------------Mouse page ----------- +void PrefDialog::OnMouseZoomSlider(wxScrollEvent &event) +{ + mouseZoomRatePercent=sliderCamZoomRate->GetValue(); +} +void PrefDialog::OnMouseMoveSlider(wxScrollEvent &event) +{ + mouseMoveRatePercent=sliderCamMoveRate->GetValue(); +} +//------------End mouse page------------- +// wxGlade: add PrefDialog event handlers + + +void PrefDialog::set_properties() +{ + // begin wxGlade: PrefDialog::set_properties + SetTitle(wxTRANS("Preferences")); + SetSize(wxSize(640, 487)); + comboPanelStartMode->SetToolTip(wxTRANS("Set the method of panel layout when starting the program")); + comboPanelStartMode->SetSelection(0); +#ifndef DISABLE_ONLINE_UPDATE + checkAllowOnlineUpdate->SetToolTip(wxTRANS("Lets the program check the internet to see if updates to the program version are available, then notifies you about updates now and again.")); +#endif + sliderCamMoveRate->SetToolTip(wxTRANS("Camera translation, orbit and swivel rates. ")); + sliderCamZoomRate->SetToolTip(wxTRANS("Camera zooming rate.")); + + filterResetDefaultFilter->SetToolTip(wxTRANS("Reset the filter initial values back to program defaults")); + filterBtnResetAllFilters->SetToolTip(wxTRANS("Reset all filter initial values back to program defaults")); + + // end wxGlade +} + + +void PrefDialog::do_layout() +{ + // begin wxGlade: PrefDialog::do_layout + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* exitButtonSizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* sizerCamSpeed = new wxStaticBoxSizer(sizerCamSpeed_staticbox, wxVERTICAL); + wxBoxSizer* sizer_6_copy = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_6 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); +#ifndef DISABLE_ONLINE_UPDATE + wxStaticBoxSizer* updateSizer = new wxStaticBoxSizer(updateSizer_staticbox, wxVERTICAL); +#endif + wxStaticBoxSizer* sizer_2 = new wxStaticBoxSizer(sizer_2_staticbox, wxVERTICAL); + wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_4 = new wxBoxSizer(wxVERTICAL); + wxStaticBoxSizer* filterPropSizer = new wxStaticBoxSizer(filterPropSizer_staticbox, wxHORIZONTAL); + wxBoxSizer* filterRightSideSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* resetButtonSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* filterLeftSizer = new wxBoxSizer(wxVERTICAL); + filterLeftSizer->Add(lblFilters, 0, 0, 0); + filterLeftSizer->Add(listFilters, 1, wxEXPAND, 0); + filterPropSizer->Add(filterLeftSizer, 1, wxEXPAND, 0); + filterPropSizer->Add(20, 20, 0, 0, 0); + filterRightSideSizer->Add(filterGridProperties, 1, wxEXPAND, 0); + resetButtonSizer->Add(filterBtnResetAllFilters, 0, 0, 0); + resetButtonSizer->Add(filterResetDefaultFilter, 0, 0, 0); + resetButtonSizer->Add(20, 20, 1, 0, 0); + filterRightSideSizer->Add(resetButtonSizer, 0, wxEXPAND, 0); + filterPropSizer->Add(filterRightSideSizer, 2, wxEXPAND, 0); + panelFilters->SetSizer(filterPropSizer); + sizer_2->Add(comboPanelStartMode, 0, 0, 0); + sizer_3->Add(20, 20, 0, 0, 0); + sizer_4->Add(chkControl, 0, 0, 0); + sizer_4->Add(chkRawData, 0, 0, 0); + sizer_4->Add(chkPlotlist, 0, 0, 0); + sizer_3->Add(sizer_4, 1, wxEXPAND, 0); + sizer_2->Add(sizer_3, 1, wxEXPAND, 0); + sizer_1->Add(sizer_2, 0, wxALL|wxEXPAND, 5); +#ifndef DISABLE_ONLINE_UPDATE + updateSizer->Add(checkAllowOnlineUpdate, 0, 0, 0); + sizer_1->Add(updateSizer, 0, wxALL|wxEXPAND, 5); +#endif + panelStartup->SetSizer(sizer_1); + sizer_6->Add(lblMoveSpeed, 0, wxALIGN_CENTER_VERTICAL, 0); + sizer_6->Add(20, 20, 0, 0, 0); + sizer_6->Add(labelSlowCamMoveRate, 0, wxALIGN_CENTER_VERTICAL, 0); + sizer_6->Add(sliderCamMoveRate, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizer_6->Add(labelFastCamMoveRate, 0, wxALIGN_CENTER_VERTICAL, 0); + sizerCamSpeed->Add(sizer_6, 1, wxEXPAND, 0); + sizer_6_copy->Add(lblZoomSpeed, 0, wxALIGN_CENTER_VERTICAL, 0); + sizer_6_copy->Add(20, 20, 0, 0, 0); + sizer_6_copy->Add(labelSlowCamZoomRate, 0, wxALIGN_CENTER_VERTICAL, 0); + sizer_6_copy->Add(sliderCamZoomRate, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); + sizer_6_copy->Add(labelSlowFastZoomRate, 0, wxALIGN_CENTER_VERTICAL, 0); + sizerCamSpeed->Add(sizer_6_copy, 1, wxEXPAND, 0); + notePrefPanels_pane_3->SetSizer(sizerCamSpeed); + notePrefPanels->AddPage(panelFilters, wxTRANS("Pref")); + notePrefPanels->AddPage(panelStartup, wxTRANS("Startup")); + notePrefPanels->AddPage(notePrefPanels_pane_3, wxTRANS("Camera")); + panelSizer->Add(notePrefPanels, 2, wxEXPAND, 0); + exitButtonSizer->Add(20, 20, 1, wxEXPAND, 0); + exitButtonSizer->Add(btnOK, 0, wxTOP, 8); + exitButtonSizer->Add(btnCancel, 0, wxLEFT|wxTOP|wxBOTTOM, 8); + exitButtonSizer->Add(10, 20, 0, 0, 0); + panelSizer->Add(exitButtonSizer, 0, wxEXPAND, 0); + SetSizer(panelSizer); + Layout(); + // end wxGlade +} + diff -Nru 3depict-0.0.12/src/gui/dialogs/prefDialog.h 3depict-0.0.13/src/gui/dialogs/prefDialog.h --- 3depict-0.0.12/src/gui/dialogs/prefDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/prefDialog.h 2013-04-10 20:58:51.000000000 +0000 @@ -0,0 +1,146 @@ +// -*- C++ -*- generated by wxGlade HG on Fri Dec 3 22:26:29 2010 +/* + * prefDialog.h - program preferences management dialog + * 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 . + */ +#ifndef PREFDIALOG_H +#define PREFDIALOG_H + + +#include +// begin wxGlade: ::dependencies +#include +#include "wxcomponents.h" +// end wxGlade + + + +#include "backend/filter.h" +#include "backend/viscontrol.h" + +// begin wxGlade: ::extracode +// end wxGlade + +//As a courtesy, we do not allow online update checking under linux +//its pointless, as linux systems usually have proper package management +#if defined( __linux__) + #define DISABLE_ONLINE_UPDATE +#endif + +class PrefDialog: public wxDialog +{ + +private: + // begin wxGlade: PrefDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //the user specified defaults. This class must clean up this pointer + std::vector filterDefaults; + + //!Current default filter setting (def. filter panel). Is null iff using hard-coded version + Filter *curFilter; + + bool programmaticEvent; + //!Generate the list of filters which can have their defaults set + void createFilterListing(); + + //!Enable/disable the check controls ont he startup panel as needed + void setStartupCheckboxEnables(unsigned int comboSel); + + //!Update the filter property grid, as needed + void updateFilterProp(const Filter *f); + + //!Percentile speeds for mouse zoom and move + unsigned int mouseZoomRatePercent,mouseMoveRatePercent; +protected: + // begin wxGlade: PrefDialog::attributes + wxStaticBox* sizerCamSpeed_staticbox; + wxStaticBox* updateSizer_staticbox; + wxStaticBox* sizer_2_staticbox; + wxStaticBox* filterPropSizer_staticbox; + wxStaticText* lblFilters; + wxListBox* listFilters; + wxPropertyGrid* filterGridProperties; + wxButton* filterBtnResetAllFilters; + wxButton* filterResetDefaultFilter; + wxPanel* panelFilters; + wxComboBox* comboPanelStartMode; + wxCheckBox* chkControl; + wxCheckBox* chkRawData; + wxCheckBox* chkPlotlist; +#ifndef DISABLE_ONLINE_UPDATE + wxCheckBox* checkAllowOnlineUpdate; +#endif + wxPanel* panelStartup; + wxStaticText* lblMoveSpeed; + wxNotebook* notePrefPanels; + wxButton* btnOK; + wxButton* btnCancel; + wxSlider* sliderCamMoveRate; + wxStaticText* labelFastCamMoveRate; + wxStaticText* labelSlowCamMoveRate; + wxStaticText* lblZoomSpeed; + wxStaticText* labelSlowCamZoomRate; + wxSlider* sliderCamZoomRate; + wxStaticText* labelSlowFastZoomRate; + wxPanel* notePrefPanels_pane_3; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + // begin wxGlade: PrefDialog::ids + // end wxGlade + PrefDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=_(""), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER); + virtual ~PrefDialog(); + virtual void OnFilterListClick(wxCommandEvent &event); // wxGlade: + virtual void OnFilterCellChange(wxGridEvent &event); // wxGlade: + virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // wxGlade: + virtual void OnResetFilterButton(wxCommandEvent &event); // wxGlade: + virtual void OnResetFilterAllButton(wxCommandEvent &event); // wxGlade: + + //set the filter defaults. note that the incoming pointers are cloned, and control is NOT transferred to this class + void setFilterDefaults(const std::vector &defs); + //Get the filter defaults. Note clones are returned, not the originals + void getFilterDefaults(std::vector &defs) const; + + void setPanelDefaults(unsigned int panelMode, bool panelControl, + bool panelRaw,bool panelPlotlist); + void getPanelDefaults(unsigned int &panelMode, bool &panelControl, + bool &panelRaw,bool &panelPlotlist) const; + +#ifndef DISABLE_ONLINE_UPDATE + bool getAllowOnlineUpdate() const { return checkAllowOnlineUpdate->IsChecked();}; + void setAllowOnlineUpdate(bool allowed) { checkAllowOnlineUpdate->SetValue(allowed);}; +#endif + void setMouseZoomRate(unsigned int rate) { mouseZoomRatePercent=rate;}; + void setMouseMoveRate(unsigned int rate) { mouseMoveRatePercent=rate;}; + + unsigned int getMouseZoomRate() const { return mouseZoomRatePercent;}; + unsigned int getMouseMoveRate() const { return mouseMoveRatePercent;}; + + virtual void OnStartupPanelCombo(wxCommandEvent &event); // wxGlade: + void OnMouseMoveSlider(wxScrollEvent &event); + void OnMouseZoomSlider(wxScrollEvent &event); + + void initialise(); + void cleanup(); +}; // wxGlade: end class + + +#endif // PREFDIALOG_H diff -Nru 3depict-0.0.12/src/gui/dialogs/resolutionDialog.cpp 3depict-0.0.13/src/gui/dialogs/resolutionDialog.cpp --- 3depict-0.0.12/src/gui/dialogs/resolutionDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/resolutionDialog.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,506 @@ +/* + * resolutionDialog.cpp - Resolution chooser dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.3 on Mon May 7 00:46:06 2012 + +#include "resolutionDialog.h" + +#include "wxcommon.h" +#include "common/translation.h" + +#include + +// begin wxGlade: ::extracode + +// end wxGlade + + +enum +{ + ID_RESET=wxID_ANY+1, + ID_TEXT_WIDTH, + ID_TEXT_HEIGHT, + ID_LOCK_ASPECT +}; + +const float MOUSEWHEEL_RATE_MULTIPLIER=1.0f; + +ResolutionDialog::ResolutionDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +{ + // begin wxGlade: ResolutionDialog::ResolutionDialog + labelWidth = new wxStaticText(this, wxID_ANY, wxTRANS("Width :"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); + textWidth = new wxTextCtrl(this, ID_TEXT_WIDTH, wxT("")); + labelHeight = new wxStaticText(this, wxID_ANY, wxTRANS("Height :")); + textHeight = new wxTextCtrl(this, ID_TEXT_HEIGHT, wxT("")); + checkLockAspect = new wxCheckBox(this, ID_LOCK_ASPECT, wxTRANS("Lock Aspect")); + static_line_1 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + panelImage = new wxPanel(this, wxID_ANY); + static_line_2 = new wxStaticLine(this, wxID_ANY); + btnReset = new wxButton(this, ID_RESET, wxTRANS("Reset")); + btnOK = new wxButton(this, wxID_OK, wxEmptyString); + button_2 = new wxButton(this, wxID_CANCEL, wxEmptyString); + +#if wxCHECK_VERSION(2, 9, 0) + textWidth->Bind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this); + textHeight->Bind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this); + SetBackgroundStyle(wxBG_STYLE_PAINT); +#else + textWidth->Connect(wxID_ANY, wxEVT_MOUSEWHEEL, + wxMouseEventHandler(ResolutionDialog::OnMouseWheelWidth),NULL,this); + textHeight->Connect(wxID_ANY, wxEVT_MOUSEWHEEL, + wxMouseEventHandler(ResolutionDialog::OnMouseWheelHeight),NULL,this); +#endif + + + + set_properties(); + do_layout(); + // end wxGlade + + programmaticEvent=0; + + updateImage(); + + btnOK->SetFocus(); +} + + +BEGIN_EVENT_TABLE(ResolutionDialog, wxDialog) + // begin wxGlade: ResolutionDialog::event_table + EVT_TEXT(ID_TEXT_WIDTH, ResolutionDialog::OnTextWidth) + EVT_TEXT(ID_TEXT_HEIGHT, ResolutionDialog::OnTextHeight) + EVT_CHECKBOX(ID_LOCK_ASPECT, ResolutionDialog::OnCheckLockAspect) + EVT_BUTTON(ID_RESET, ResolutionDialog::OnBtnReset) + EVT_BUTTON(wxID_OK, ResolutionDialog::OnBtnOK) + EVT_BUTTON(wxID_CANCEL, ResolutionDialog::OnBtnCancel) + EVT_PAINT(ResolutionDialog::OnPaint) + EVT_KEY_DOWN(ResolutionDialog::OnKeypress) + // end wxGlade +END_EVENT_TABLE(); + +void ResolutionDialog::updateImage() +{ + wxPaintEvent paintEvt; + wxPostEvent(this,paintEvt); +} + +void ResolutionDialog::setRes(unsigned int w, unsigned int h, bool asReset) +{ + //Increment programmatic lock counter + programmaticEvent++; + + std::string s; + stream_cast(s,w); + textWidth->SetValue(wxStr(s)); + + stream_cast(s,h); + textHeight->SetValue(wxStr(s)); + + resWidth=w; + resHeight=h; + + //do we want to use this as the reset value? + if(asReset) + { + resOrigWidth=w; + resOrigHeight=h; + + if(resOrigWidth) + aspect=(float)resOrigHeight/(float)resOrigWidth; + else + aspect=0; + } + + programmaticEvent--; +} + +void ResolutionDialog::OnTextWidth(wxCommandEvent &event) +{ + + if(programmaticEvent) + return; + + programmaticEvent++; + + //Validate that string is numerical + //--- + wxString s =event.GetString(); + std::string textStr; + textStr=stlStr(s); + if(textStr.find_first_not_of("0123456789")!=std::string::npos ) + { + stream_cast(textStr,resWidth); + textWidth->SetValue(wxStr(textStr)); + programmaticEvent--; + return; + } + //--- + + + int width; + textStr = stlStr(textWidth->GetValue()); + + if(stream_cast(width,textStr)) + { + programmaticEvent--; + return; + } + resWidth=width; + + //if we are locking the aspect ratio, set the other text box to have the same ratio + if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) + { + resHeight=(unsigned int)(width*aspect); + stream_cast(textStr,resHeight); + textHeight->SetValue(wxStr(textStr)); + } + + + updateImage(); + + programmaticEvent--; +} + +void ResolutionDialog::OnTextHeight(wxCommandEvent &event) +{ + + if(programmaticEvent) + return; + + programmaticEvent++; + + + //Validate that string is numerical + //--- + wxString s =event.GetString(); + std::string textStr; + textStr=stlStr(s); + if(textStr.find_first_not_of("0123456789")!=std::string::npos ) + { + stream_cast(textStr,resHeight); + textHeight->SetValue(wxStr(textStr)); + programmaticEvent--; + return; + } + //--- + + + int height; + textStr = stlStr(textHeight->GetValue()); + + if(stream_cast(height,textStr)) + { + programmaticEvent--; + return; + } + + resHeight=height; + + //if we are locking the aspect ratio, set the other text box to preserve the same ratio + if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) + { + resWidth=(unsigned int)(height/aspect); + stream_cast(textStr,resWidth); + textWidth->SetValue(wxStr(textStr)); + } + + updateImage(); + + programmaticEvent--; +} + + +void ResolutionDialog::OnCheckLockAspect(wxCommandEvent &event) +{ + //Recompute the desired aspect + if(resWidth) + aspect=(float)resHeight/(float)resWidth; + else + aspect=0; +} + + +void ResolutionDialog::OnBtnReset(wxCommandEvent &event) +{ + setRes(resOrigWidth,resOrigHeight); + + //Recompute the desired aspect as per the original + if(resOrigWidth) + aspect=(float)resOrigHeight/(float)resOrigWidth; + else + aspect=0; +} + + +void ResolutionDialog::OnBtnOK(wxCommandEvent &event) +{ + finishDialog(); +} + + +void ResolutionDialog::OnBtnCancel(wxCommandEvent &event) +{ + EndModal(wxID_CANCEL); +} + +void ResolutionDialog::OnMouseWheelWidth(wxMouseEvent &event) +{ + + bool haveCtrl,haveShift; + haveShift=event.ShiftDown(); + haveCtrl=event.CmdDown(); + + //normal move rate + float moveRate=(float)event.GetWheelRotation()/(float)event.GetWheelDelta()*MOUSEWHEEL_RATE_MULTIPLIER; + + //scroll rate multiplier for this scroll event + { + float multiplier; + if(haveShift) + multiplier=5.0f; + else if(haveCtrl) + multiplier=10.0f; + else + multiplier=1.0f; + + moveRate*=multiplier; + } + + + if(resWidth+moveRate <= 0) + return; + + programmaticEvent++; + setRes((unsigned int)(resWidth+moveRate),resHeight); + + //if we are locking the aspect ratio, set the other text box to preserve the same ratio + if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) + { + std::string textStr; + resHeight=(unsigned int)(resWidth*aspect); + stream_cast(textStr,resHeight); + textHeight->SetValue(wxStr(textStr)); + } + + updateImage(); + programmaticEvent--; +} + +void ResolutionDialog::OnMouseWheelHeight(wxMouseEvent &event) +{ + + + bool haveCtrl,haveShift; + haveShift=event.ShiftDown(); + haveCtrl=event.CmdDown(); + + //normal move rate + float moveRate=(float)event.GetWheelRotation()/(float)event.GetWheelDelta()*MOUSEWHEEL_RATE_MULTIPLIER; + + //scroll rate multiplier for this scroll event + { + float multiplier; + if(haveShift) + multiplier=5.0f; + else if(haveCtrl) + multiplier=10.0f; + else + multiplier=1.0f; + + moveRate*=multiplier; + } + + + + if(resHeight+moveRate <= 0) + return; + + programmaticEvent++; + + setRes(resWidth,(unsigned int)(resHeight+moveRate)); + + //if we are locking the aspect ratio, set the other text box to preserve the same ratio + if(checkLockAspect->IsChecked() && aspect > std::numeric_limits::epsilon()) + { + std::string textStr; + resWidth=(unsigned int)(resHeight/aspect); + stream_cast(textStr,resWidth); + textWidth->SetValue(wxStr(textStr)); + } + + updateImage(); + programmaticEvent--; +} + +void ResolutionDialog::OnPaint(wxPaintEvent &event) +{ +#ifdef __APPLE__ + wxDC *dialogDC = new wxClientDC(this); +#else + wxDC *dialogDC = new wxAutoBufferedPaintDC(this); +#endif + + int widthLabelY,heightLabelY,checkBoxY,connectorX; + int tmpY,tmpX,tmp; + + labelWidth->GetPosition(&connectorX,&tmpY); + labelWidth->GetSize(&tmpX,&tmp); + widthLabelY=tmpY + tmp/2; + + labelHeight->GetPosition(&tmpX,&tmpY); + labelHeight->GetSize(&tmpX,&tmp); + heightLabelY=tmpY + tmp/2; + + checkLockAspect->GetPosition(&tmpX,&tmpY); + checkLockAspect->GetSize(&tmpX,&tmp); + checkBoxY=tmpY + tmp/2; + + //Draw the connecting lines in an "E" shape + const int LINE_STANDOFF=8; + + dialogDC->DrawLine(connectorX-LINE_STANDOFF/2,widthLabelY, + connectorX-LINE_STANDOFF,widthLabelY); + dialogDC->DrawLine(connectorX-LINE_STANDOFF/2,heightLabelY, + connectorX-LINE_STANDOFF,heightLabelY); + dialogDC->DrawLine(connectorX-LINE_STANDOFF/2,checkBoxY, + connectorX-LINE_STANDOFF,checkBoxY); + + dialogDC->DrawLine(connectorX-LINE_STANDOFF,checkBoxY, + connectorX-LINE_STANDOFF,widthLabelY); + + + delete dialogDC; + +#ifdef __APPLE__ + wxDC *paintDC = new wxClientDC(panelImage); +#else + wxDC *paintDC = new wxAutoBufferedPaintDC(panelImage); +#endif + + drawImageRectangle(paintDC); + + delete paintDC; +} + +void ResolutionDialog::drawImageRectangle(wxDC *paintDC) +{ + paintDC->Clear(); + int width,height; + width=resWidth; + height=resHeight; + + + if(!(width && height)) + return; + + + int panelHeight,panelWidth; + + panelImage->GetClientSize(&panelWidth,&panelHeight); + + + float scaleFactor; + //Rescale the dimensions to fit + // into image panel + scaleFactor=std::min((float)panelHeight/(float)height, + (float)panelWidth/(float)width); + + width=(unsigned int)(width*scaleFactor); + height=(unsigned int)(height*scaleFactor); + + int startX,startY; + + startX = (int)((float)(panelWidth - width)*0.5f); + startY = (int)((float)(panelHeight - height)*0.5f); + + paintDC->DrawRectangle(startX,startY,width,height); + +} + +void ResolutionDialog::OnKeypress(wxKeyEvent &evt) +{ + if( evt.GetKeyCode() == WXK_RETURN) + finishDialog(); + evt.Skip(); +} + +// wxGlade: add ResolutionDialog event handlers + +void ResolutionDialog::finishDialog() +{ + //programmatic event counter should be decremented to zero + ASSERT(!programmaticEvent); + +#if wxCHECK_VERSION(2, 9, 0) + textWidth->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this); + textHeight->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this); +#else + textWidth->Disconnect(); + textHeight->Disconnect(); +#endif + EndModal(wxID_OK); +} + +void ResolutionDialog::set_properties() +{ + // begin wxGlade: ResolutionDialog::set_properties + SetTitle(wxTRANS("Resolution Selection")); + // end wxGlade +} + + +void ResolutionDialog::do_layout() +{ + // begin wxGlade: ResolutionDialog::do_layout + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* upperSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* leftSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* heightTextSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* widthTextSizer = new wxBoxSizer(wxHORIZONTAL); + upperSizer->Add(10, 20, 0, 0, 0); + leftSizer->Add(20, 20, 2, 0, 0); + widthTextSizer->Add(labelWidth, 0, wxALIGN_CENTER_VERTICAL, 0); + widthTextSizer->Add(textWidth, 0, wxALL|wxALIGN_CENTER_VERTICAL, 8); + leftSizer->Add(widthTextSizer, 1, wxEXPAND, 0); + heightTextSizer->Add(labelHeight, 0, wxALIGN_CENTER_VERTICAL, 0); + heightTextSizer->Add(textHeight, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5); + leftSizer->Add(heightTextSizer, 1, wxEXPAND, 0); + leftSizer->Add(checkLockAspect, 0, wxALIGN_CENTER_VERTICAL, 3); + leftSizer->Add(20, 20, 2, 0, 0); + upperSizer->Add(leftSizer, 0, wxLEFT|wxEXPAND, 8); + upperSizer->Add(10, 10, 0, 0, 0); + upperSizer->Add(static_line_1, 0, wxEXPAND, 0); + upperSizer->Add(panelImage, 5, wxALL|wxEXPAND, 5); + mainSizer->Add(upperSizer, 1, wxEXPAND, 0); + mainSizer->Add(static_line_2, 0, wxEXPAND, 0); + buttonSizer->Add(btnReset, 0, wxALL, 5); + buttonSizer->Add(20, 20, 1, 0, 0); + buttonSizer->Add(btnOK, 0, wxALL, 5); + buttonSizer->Add(button_2, 0, wxALL, 5); + mainSizer->Add(buttonSizer, 0, wxTOP|wxBOTTOM|wxEXPAND, 5); + SetSizer(mainSizer); + mainSizer->Fit(this); + Layout(); + // end wxGlade +} + + + + + diff -Nru 3depict-0.0.12/src/gui/dialogs/resolutionDialog.h 3depict-0.0.13/src/gui/dialogs/resolutionDialog.h --- 3depict-0.0.12/src/gui/dialogs/resolutionDialog.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/dialogs/resolutionDialog.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,103 @@ +/* + * resolutionDialog.h - Resolution chooser dialog + * 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 . +*/ +// -*- C++ -*- generated by wxGlade 0.6.3 on Mon May 7 00:46:06 2012 + +#include +// begin wxGlade: ::dependencies +#include +// end wxGlade + + +#ifndef RESOLUTIONDIALOG_H +#define RESOLUTIONDIALOG_H + +//!resolution chooser dialog +class ResolutionDialog: public wxDialog { +public: + // begin wxGlade: ResolutionDialog::ids + // end wxGlade + + ResolutionDialog(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE); + +private: + //Resolution width and height or the final output + unsigned int resWidth,resHeight; + + //!Reset value for resolution + unsigned int resOrigWidth,resOrigHeight; + + //!Programmatic event counter + // Non-zero if event is being generated programatically + int programmaticEvent; + + //!aspect ratio for when locking aspect. Zero if undefined + float aspect; + + // begin wxGlade: ResolutionDialog::methods + void set_properties(); + void do_layout(); + // end wxGlade + //!Finish up the dialog + void finishDialog(); + //!Update the drawn image representing the output shape + void updateImage(); + + //!Draw the image rectangle + void drawImageRectangle(wxDC *dc); +protected: + // begin wxGlade: ResolutionDialog::attributes + wxStaticText* labelWidth; + wxTextCtrl* textWidth; + wxStaticText* labelHeight; + wxTextCtrl* textHeight; + wxCheckBox* checkLockAspect; + wxStaticLine* static_line_1; + wxPanel* panelImage; + wxStaticLine* static_line_2; + wxButton* btnReset; + wxButton* btnOK; + wxButton* button_2; + // end wxGlade + + DECLARE_EVENT_TABLE(); + + +public: + virtual void OnTextWidth(wxCommandEvent &event); // wxGlade: + virtual void OnTextHeight(wxCommandEvent &event); // wxGlade: + virtual void OnCheckLockAspect(wxCommandEvent &event); // wxGlade: + virtual void OnBtnReset(wxCommandEvent &event); // wxGlade: + virtual void OnBtnOK(wxCommandEvent &event); // wxGlade: + virtual void OnBtnCancel(wxCommandEvent &event); // wxGlade: + virtual void OnMouseWheelWidth(wxMouseEvent &event); + virtual void OnMouseWheelHeight(wxMouseEvent &event); + virtual void OnPaint(wxPaintEvent &event); + + virtual void OnKeypress(wxKeyEvent &evt); + + + //!get the width as entered in the dialog + unsigned int getWidth() const {return resWidth;}; + //!Get the height as entered in the dialog box + unsigned int getHeight() const {return resHeight;}; + //!Set the resolution and update text boxes + void setRes(unsigned int w, unsigned int h, bool asReset=false); +}; // wxGlade: end class + + +#endif // RES_H diff -Nru 3depict-0.0.12/src/gui/glPane.cpp 3depict-0.0.13/src/gui/glPane.cpp --- 3depict-0.0.12/src/gui/glPane.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glPane.cpp 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,1092 @@ +/* + * glPane.cpp - OpenGL panel implementation + * 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 . +*/ + + +#include + +#include "wxcommon.h" + +#include "common/stringFuncs.h" +#include "glPane.h" + + +// include OpenGL +#ifdef __WXMAC__ +#include "OpenGL/glu.h" +#include "OpenGL/gl.h" + +#else +#include +#include + +#endif + +#include "common/translation.h" + +//Unclear why, but windows does not allow GL_BGR, +//needs some other define BGR_EXT (NFI), which is 0x80E0 +#if defined(WIN32) || defined(WIN64) + #define GL_BGR 0x80E0 +#endif + + +enum +{ + ID_KEYPRESS_TIMER=wxID_ANY+1, +}; + +//Double tap delay (ms), for axis reversal +const unsigned int DOUBLE_TAP_DELAY=500; + +BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas) +EVT_MOTION(BasicGLPane::mouseMoved) +EVT_ERASE_BACKGROUND(BasicGLPane::OnEraseBackground) +EVT_LEFT_DOWN(BasicGLPane::mouseDown) +EVT_LEFT_UP(BasicGLPane::mouseReleased) +EVT_MIDDLE_UP(BasicGLPane::mouseReleased) +EVT_MIDDLE_DOWN(BasicGLPane::mouseDown) +EVT_RIGHT_UP(BasicGLPane::mouseReleased) +EVT_RIGHT_DOWN(BasicGLPane::mouseDown) +EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow) +EVT_SIZE(BasicGLPane::resized) +EVT_KEY_DOWN(BasicGLPane::keyPressed) +EVT_CHAR(BasicGLPane::charEvent) +EVT_KEY_UP(BasicGLPane::keyReleased) +EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved) +EVT_PAINT(BasicGLPane::render) +EVT_TIMER(ID_KEYPRESS_TIMER,BasicGLPane::OnAxisTapTimer) +END_EVENT_TABLE() + +//Controls camera pan/translate/pivot speed; Radii per pixel or distance/pixel +const float CAMERA_MOVE_RATE=0.05; + +// Controls zoom speed, in err, zoom units.. Ahem. +const float CAMERA_SCROLL_RATE=0.05; +//Zoom speed for keyboard +const float CAMERA_KEYBOARD_SCROLL_RATE=1; + +int attribList[] = {WX_GL_RGBA, + WX_GL_DEPTH_SIZE, + 16, + WX_GL_DOUBLEBUFFER, + 1, + 0,0}; + +BasicGLPane::BasicGLPane(wxWindow* parent) : +wxGLCanvas(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas"),attribList) +{ + haveCameraUpdates=false; + applyingDevice=false; + paneInitialised=false; + + keyDoubleTapTimer=new wxTimer(this,ID_KEYPRESS_TIMER); + lastKeyDoubleTap=(unsigned int)-1; + + mouseMoveFactor=mouseZoomFactor=1.0f; + dragging=false; + lastMoveShiftDown=false; + selectionMode=false; + lastKeyFlags=lastMouseFlags=0; +} + +BasicGLPane::~BasicGLPane() +{ + keyDoubleTapTimer->Stop(); + delete keyDoubleTapTimer; +} + +bool BasicGLPane::displaySupported() const +{ +#if wxCHECK_VERSION(2,9,0) + return IsDisplaySupported(attribList); +#else + ASSERT(false); + //Lets hope so. If its not, then its just going to fail anyway. + //If it is, then returning false would simply create a roadblock. + //Either way, you shouldn't get here. + return true; +#endif +} + +void BasicGLPane::setSceneInteractionAllowed(bool enabled) +{ + currentScene.lockInteraction(!enabled); +} + +unsigned int BasicGLPane::selectionTest(const wxPoint &p,bool &shouldRedraw) +{ + + if(currentScene.isInteractionLocked()) + { + shouldRedraw=false; + return -1; + } + + //TODO: Refactor. Much of this could be pushed into the scene, + //and hence out of this wx panel. + + //Push on the matrix stack + glPushMatrix(); + + GLint oldViewport[4]; + glGetIntegerv(GL_VIEWPORT, oldViewport); + //5x5px picking region. Picking is done by modifying the view + //to enlarge the selected region. + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPickMatrix(p.x, oldViewport[3]-p.y,5, 5, oldViewport); + glMatrixMode(GL_MODELVIEW); + + int lastSelected = currentScene.getLastSelected(); + int selectedObject=currentScene.glSelect(); + + //If the object selection hasn't changed, we don't need to redraw + //if it has changed, we should redraw + shouldRedraw = (lastSelected !=selectedObject); + + //Restore the previous matrix + glPopMatrix(); + + //Restore the viewport + int w, h; + GetClientSize(&w, &h); + glViewport(0, 0, (GLint) w, (GLint) h); + + return selectedObject; +} + +unsigned int BasicGLPane::hoverTest(const wxPoint &p,bool &shouldRedraw) +{ + + if(currentScene.isInteractionLocked()) + { + shouldRedraw=false; + return -1; + } + //Push on the matrix stack + glPushMatrix(); + + GLint oldViewport[4]; + glGetIntegerv(GL_VIEWPORT, oldViewport); + //5x5px picking region. Picking is done by modifying the view + //to enlarge the selected region. + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPickMatrix(p.x, oldViewport[3]-p.y,5, 5, oldViewport); + glMatrixMode(GL_MODELVIEW); + + unsigned int lastHover = currentScene.getLastHover(); + unsigned int hoverObject=currentScene.glSelect(false); + + //FIXME: Should be able to make this more efficient + shouldRedraw = lastHover!=(unsigned int)-1; + + //Set the scene's hover value + currentScene.setLastHover(hoverObject); + currentScene.setHoverMode(hoverObject != (unsigned int)-1); + + //Restore the previous matirx + glPopMatrix(); + + //Restore the viewport + int w, h; + GetClientSize(&w, &h); + glViewport(0, 0, (GLint) w, (GLint) h); + + return hoverObject; +} + +// some useful events to use +void BasicGLPane::mouseMoved(wxMouseEvent& event) +{ + if (applyingDevice) return; + enum + { + CAM_MOVE, //Movement of some kind + CAM_TRANSLATE, //translate camera + CAM_PIVOT, //Pivot around view and across directions + CAM_ROLL //Roll around view direction + }; + + + if(selectionMode ) + { + if(currentScene.isInteractionLocked()) + { + event.Skip(); + return; + } + + + wxPoint p=event.GetPosition(); + + unsigned int mouseFlags=0; + unsigned int keyFlags=0; + wxMouseState wxm = wxGetMouseState(); + + if(wxm.CmdDown()) + keyFlags|=FLAG_CMD; + if(wxm.ShiftDown()) + keyFlags|=FLAG_SHIFT; + + if(wxm.LeftDown()) + mouseFlags|= SELECT_BUTTON_LEFT; + if(wxm.RightDown()) + mouseFlags|= SELECT_BUTTON_RIGHT; + if(wxm.MiddleDown()) + mouseFlags|= SELECT_BUTTON_MIDDLE; + + //We can get a mouse move event which reports no buttons before a mouse-up event, + //this occurs frequently under windows, but sometimes under GTK + if(!mouseFlags) + { + event.Skip(); + return; + } + + int w, h; + GetClientSize(&w, &h); + + + currentScene.applyDevice((float)draggingStart.x/(float)w, + (float)draggingStart.y/(float)h, + p.x/(float)w,p.y/(float)h, + keyFlags,mouseFlags, + false); + + lastMouseFlags=mouseFlags; + lastKeyFlags=keyFlags; + Refresh(); + return; + } + + if(!dragging) + { + wxPoint p=event.GetPosition(); + + //Do a hover test + bool doRedraw=false; + hoverTest(p,doRedraw); + + if(doRedraw) + Refresh(); + + return; + } + + wxPoint draggingCurrent = event.GetPosition(); + + //left-right and up-down move values + float lrMove,udMove; + + //Movement rate multiplier -- initialise to user value + float camMultRate=mouseMoveFactor; + if(event.m_shiftDown) + { + //Commit the current temp cam using the last camera rate + //and then restart the motion. + if(!lastMoveShiftDown && currentScene.haveTempCam()) + currentScene.commitTempCam(); + + camMultRate*=5.0f; + + lastMoveShiftDown=true; + + } + else + { + //Commit the current temp cam using the last camera rate + //and then restart the motion. + if(lastMoveShiftDown && currentScene.haveTempCam()) + currentScene.commitTempCam(); + + lastMoveShiftDown=false; + } + + lrMove=CAMERA_MOVE_RATE*camMultRate*(draggingCurrent.x - draggingStart.x); + udMove=CAMERA_MOVE_RATE*camMultRate*(draggingCurrent.y - draggingStart.y); + + lrMove*=2.0f*M_PI/180.0; + udMove*=2.0f*M_PI/180.0; + unsigned int camMode=0; + //Decide camera movement mode + bool translateMode; + + translateMode=event.CmdDown(); + + bool swingMode; + #if defined(WIN32) || defined(WIN64) || defined(__APPLE__) + swingMode=wxGetKeyState(WXK_ALT); + #else + swingMode=wxGetKeyState(WXK_TAB); + #endif + + if(translateMode && !swingMode) + camMode=CAM_TRANSLATE; + else if(swingMode && !translateMode) + camMode=CAM_PIVOT; + else if(swingMode && translateMode) + camMode=CAM_ROLL; + else + camMode=CAM_MOVE; + + switch(camMode) + { + case CAM_TRANSLATE: + currentScene.discardTempCam(); + currentScene.setTempCam(); + currentScene.getTempCam()->translate(lrMove,-udMove); + break; + case CAM_PIVOT: + currentScene.discardTempCam(); + currentScene.setTempCam(); + currentScene.getTempCam()->pivot(lrMove,udMove); + break; + case CAM_MOVE: + currentScene.setTempCam(); + currentScene.getTempCam()->move(lrMove,udMove); + break; + case CAM_ROLL: + currentScene.setTempCam(); + currentScene.getTempCam()->roll(atan2(udMove,lrMove)); + + break; + default: + ASSERT(false); + break; + } + + if(!event.m_leftDown) + { + dragging=false; + currentScene.commitTempCam(); + } + + haveCameraUpdates=true; + + Refresh(false); +} + +void BasicGLPane::mouseDown(wxMouseEvent& event) +{ + + wxPoint p=event.GetPosition(); + + //Do not re-trigger if dragging or doing a scene update. + //This can cause a selection test to occur whilst + //a temp cam is activated in the scene, or a binding refresh is underway, + //which is currently considered bad + if(!dragging && !applyingDevice && !selectionMode + && !currentScene.isInteractionLocked()) + { + //Check to see if the user has clicked an object in the scene + bool redraw; + selectionTest(p,redraw); + + + //If the selected object is valid, then + //we did select an object. Treat this as a selection event + if(currentScene.getLastSelected() != (unsigned int)-1) + { + selectionMode=true; + currentScene.setSelectionMode(true); + } + else + { + //we aren't setting, it -- it shouldn't be the case + ASSERT(selectionMode==false); + + //Prevent right button from triggering camera drag + if(!event.LeftDown()) + { + event.Skip(); + return; + } + + //If not a valid selection, this is a camera drag. + dragging=true; + } + + draggingStart = event.GetPosition(); + //Set keyboard focus to self, to receive key events + SetFocus(); + + if(redraw) + Refresh(); + } + + event.Skip(); +} + +void BasicGLPane::mouseWheelMoved(wxMouseEvent& event) +{ + const float SHIFT_MULTIPLIER=5; + + float cameraMoveRate=-(float)event.GetWheelRotation()/(float)event.GetWheelDelta(); + + cameraMoveRate*=mouseZoomFactor; + + if(event.ShiftDown()) + cameraMoveRate*=SHIFT_MULTIPLIER; + + cameraMoveRate*=CAMERA_SCROLL_RATE; + //Move by specified delta + currentScene.getActiveCam()->forwardsDolly(cameraMoveRate); + + //if we are using a temporary camera, update that too + if(currentScene.haveTempCam()) + currentScene.getTempCam()->forwardsDolly(cameraMoveRate); + + haveCameraUpdates=true; + Refresh(); + event.Skip(); +} + +void BasicGLPane::mouseReleased(wxMouseEvent& event) +{ + if(currentScene.isInteractionLocked()) + { + event.Skip(); + return; + } + + if(selectionMode ) + { + //If user releases all buttons, then allow the up + if(!event.LeftIsDown() && + !event.RightIsDown() && !event.MiddleIsDown()) + { + wxPoint p=event.GetPosition(); + + int w, h; + GetClientSize(&w, &h); + applyingDevice=true; + + + currentScene.applyDevice((float)draggingStart.x/(float)w, + (float)draggingStart.y/(float)h, + p.x/(float)w,p.y/(float)h, + lastKeyFlags,lastMouseFlags, + true); + + applyingDevice=false; + + + selectionMode=false; + currentScene.setSelectionMode(selectionMode); + + Refresh(); + } + event.Skip(); + return; + } + + + if(currentScene.haveTempCam()) + currentScene.commitTempCam(); + currentScene.finaliseCam(); + + haveCameraUpdates=true; + dragging=false; + + Refresh(); + event.Skip(); + +} + +void BasicGLPane::rightClick(wxMouseEvent& event) +{ +} + +void BasicGLPane::mouseLeftWindow(wxMouseEvent& event) +{ + if(selectionMode) + { + wxPoint p=event.GetPosition(); + + int w, h; + GetClientSize(&w, &h); + + applyingDevice=true; + currentScene.applyDevice((float)draggingStart.x/(float)w, + (float)draggingStart.y/(float)h, + p.x/(float)w,p.y/(float)h, + lastKeyFlags,lastMouseFlags, + true); + + selectionMode=false; + currentScene.setSelectionMode(selectionMode); + Refresh(); + applyingDevice=false; + + event.Skip(); + return; + + } + + if(event.m_leftDown) + { + if(currentScene.haveTempCam()) + { + currentScene.commitTempCam(); + dragging=false; + } + } + event.Skip(); +} + +void BasicGLPane::keyPressed(wxKeyEvent& event) +{ + + switch(event.GetKeyCode()) + { + case WXK_SPACE: + { + unsigned int visibleDir; + + //Use modifier keys to alter the direction of visibility + //First compute the part of the keymask that does not + //reflect the double tap + // needs to be control in apple as cmd-space open spotlight + unsigned int keyMask; +#ifdef __APPLE__ + #if wxCHECK_VERSION(2,9,0) + keyMask = (event.RawControlDown() ? 1 : 0); + #else + keyMask = (event.ControlDown() ? 1 : 0); + #endif +#else + keyMask = (event.CmdDown() ? 1 : 0); +#endif + keyMask |= (event.ShiftDown() ? 2 : 0); + + //Now determine if we are the same mask as last time + bool isKeyDoubleTap=(lastKeyDoubleTap==keyMask); + //double tapping allows for selection of reverse direction + keyMask |= ( isKeyDoubleTap ? 4 : 0); + + visibleDir=-1; + + //Hardwire key combo->Mapping + switch(keyMask) + { + //Space only + case 0: + visibleDir=3; + break; + //Command down +space + case 1: + visibleDir=0; + break; + //Shift +space + case 2: + visibleDir=2; + break; + //NO CASE 3 + //Double+space + case 4: + visibleDir=5; + break; + //Doublespace+Cmd + case 5: + visibleDir=4; + break; + + //Space+Double+shift + case 6: + visibleDir=1; + break; + default: + ; + } + + if(visibleDir!=(unsigned int)-1) + { + + if(isKeyDoubleTap) + { + //It was a double tap. Reset the tapping and stop the timer + lastKeyDoubleTap=(unsigned int)-1; + keyDoubleTapTimer->Stop(); + } + else + { + lastKeyDoubleTap=keyMask & (~(0x04)); + keyDoubleTapTimer->Start(DOUBLE_TAP_DELAY,wxTIMER_ONE_SHOT); + } + + + currentScene.ensureVisible(visibleDir); + parentStatusBar->SetStatusText(wxTRANS("Use shift/ctrl-space or double tap to alter reset axis")); + parentStatusBar->SetBackgroundColour(*wxCYAN) + ; + parentStatusTimer->Start(statusDelay,wxTIMER_ONE_SHOT); + Refresh(); + haveCameraUpdates=true; + } + } + break; + } + event.Skip(); +} + +void BasicGLPane::setGlClearColour(float r, float g, float b) +{ + ASSERT(r >= 0.0f && r <= 1.0f); + ASSERT(g >= 0.0f && g <= 1.0f); + ASSERT(b >= 0.0f && b <= 1.0f); + + //Let openGL know that we have changed the colour. + glClearColor( r, g, b, 0.0f); + + currentScene.setBackgroundColour(r,g,b); + + Refresh(); +} + +void BasicGLPane::keyReleased(wxKeyEvent& event) +{ + + float cameraMoveRate=CAMERA_KEYBOARD_SCROLL_RATE; + + if(event.ShiftDown()) + cameraMoveRate*=5; + + switch(event.GetKeyCode()) + { + case '-': + case WXK_NUMPAD_SUBTRACT: + case WXK_SUBTRACT: + { + //Do a backwards dolly by fixed amount + currentScene.getActiveCam()->forwardsDolly(cameraMoveRate); + if(currentScene.haveTempCam()) + currentScene.getTempCam()->forwardsDolly(cameraMoveRate); + break; + } + case '+': + case '=': + case WXK_NUMPAD_ADD: + case WXK_ADD: + { + //Reverse direction of motion + cameraMoveRate= -cameraMoveRate; + + //Do a forwards dolly by fixed amount + currentScene.getActiveCam()->forwardsDolly(cameraMoveRate); + if(currentScene.haveTempCam()) + currentScene.getTempCam()->forwardsDolly(cameraMoveRate); + break; + } + default: + ; + } + + Refresh(); + event.Skip(); +} + +void BasicGLPane::charEvent(wxKeyEvent& event) +{ + +} + + +void BasicGLPane::resized(wxSizeEvent& evt) +{ + wxGLCanvas::OnSize(evt); + + prepare3DViewport(0,0,getWidth(),getHeight()); + wxClientDC *dc=new wxClientDC(this); + Refresh(); + delete dc; +} + +bool BasicGLPane::prepare3DViewport(int tlx, int tly, int brx, int bry) +{ + + if(!paneInitialised) + return false; + + //Prevent NaN. + if(!(bry-tly)) + return false; + GLint dims[2]; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); + + //Ensure that the opengGL function didn't tell us porkies, + // (well, check during debug builds) + ASSERT(dims[0] && dims[1]); + + //check for exceeding max viewport and we have some space + if(dims[0] <(brx-tlx) || dims[1] < bry-tly || + (!dims[0] || !dims[1] )) + return false; + + glViewport( tlx, tly, brx-tlx, bry-tly); + + currentScene.setWinSize(brx-tlx,bry-tly); + + //Assume no perspective transform + //use scene camera to achieve this + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + float aspect = (float)(brx-tlx)/(float)(bry-tly); + + currentScene.setAspect(aspect); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + float r,g,b; + currentScene.getBackgroundColour(r,g,b); + glClearColor( r, g, b,1.0f ); + glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT); + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + + + + glEnable(GL_LIGHT0); + + + glShadeModel(GL_SMOOTH); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ) ; + + glEnable(GL_POINT_SMOOTH); + glEnable(GL_LINE_SMOOTH); + + + +// SetPosition( wxPoint(0,0) ); + + return true; +} + +int BasicGLPane::getWidth() +{ + return GetClientSize().x; +} + +int BasicGLPane::getHeight() +{ + return GetClientSize().y; +} + +void BasicGLPane::render( wxPaintEvent& evt ) +{ + //Prevent calls to openGL if pane not visible + if (!IsShown()) + return; + + wxGLCanvas::SetCurrent(); + if(!paneInitialised) + { + paneInitialised=true; + prepare3DViewport(0,0,getWidth(),getHeight()); + } + + wxPaintDC(this); + currentScene.draw(); + glFlush(); + SwapBuffers(); +} + +void BasicGLPane::OnEraseBackground(wxEraseEvent &evt) +{ + //Do nothing. This is to help eliminate flicker apparently +} + +void BasicGLPane::updateClearColour() +{ + float rClear,gClear,bClear; + currentScene.getBackgroundColour(rClear,gClear,bClear); + //Can't set the opengl window without a proper context + ASSERT(paneInitialised); + setGlClearColour(rClear,gClear,bClear); + //Let openGL know that we have changed the colour. + glClearColor( rClear, gClear, + bClear,1.0f); +} + +bool BasicGLPane::saveImage(unsigned int width, unsigned int height, + const char *filename, bool showProgress, bool needPostPaint) +{ + GLint dims[2]; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); + + //Opengl should not be giving us zero dimensions here. + // if it does, just abandon saving the image as a fallback + ASSERT(dims[0] && dims[1]); + if(!dims[0] || !dims[1]) + return false; + + //create new image + wxImage *image = new wxImage(width,height); + + //We cannot seem to draw outside the current viewport. + //in a cross platform manner. + //fall back to stitching the image together by hand + char *pixels; + + + pixels= new char[3*width*height]; + int panelWidth,panelHeight; + GetClientSize(&panelWidth,&panelHeight); + + float oldAspect = currentScene.getAspect(); + currentScene.setAspect((float)panelHeight/(float)panelWidth); + + //Check + if((unsigned int)width > panelWidth || (unsigned int)height> panelHeight) + { + unsigned int numTilesX,numTilesY; + numTilesX = width/panelWidth; + numTilesY = height/panelHeight; + if(panelWidth % width) + numTilesX++; + + if(panelHeight% height) + numTilesY++; + + //Construct the image using "tiles": what we do is + //use the existing viewport size (as we cannot reliably change it + //without handling an OnSize event to resize the underlying + //system buffer (eg hwnd under windows.)) + //and then use this to reconstruct the image in a piece wise manner + float tileStart[2]; + + float fractionWidth=(float)panelWidth/(float)width; + float fractionHeight=(float)panelHeight/(float)height; + + unsigned int thisTileNum=0; + + wxProgressDialog *wxD=0; + if(showProgress) + { + wxD = new wxProgressDialog(wxTRANS("Image progress"), + wxTRANS("Rendering tiles..."), numTilesX*numTilesY); + + wxD->Show(); + } + + std::string tmpStr,tmpStrTwo; + stream_cast(tmpStrTwo,numTilesX*numTilesY); + + for(unsigned int tileX=0;tileXUpdate(thisTileNum,wxStr(tmpStr)); + + + tileStart[1]=(fractionHeight*(float)tileY-0.5); + //Adjust the viewport such that the render generates the tile for + //this view. Coordinates are in normalised device coords (-1 to 1) + currentScene.restrictView(tileStart[0],tileStart[1], + tileStart[0]+fractionWidth,tileStart[1]+fractionHeight); + + //Clear the buffers and draw the openGL scene + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + currentScene.draw(); + + //Force openGL to block execution until draw complete + glFlush(); + glFinish(); + + //Grab the image generated for this tile + glReadBuffer(GL_BACK); + //Set the pixel alignment to one byte, so that openGL unpacks + //correctly into our buffer. + glPushAttrib(GL_PACK_ALIGNMENT); + glPixelStorei(GL_PACK_ALIGNMENT,1); + + //Read image + glReadPixels(0, 0, panelWidth,panelHeight, + GL_BGR, GL_UNSIGNED_BYTE, pixels); + glPopAttrib(); + + + //Copy the data into its target location, + char *pixel; + unsigned int pixX,pixY; + pixX=0; + pixY=0; + unsigned int cutoffX,cutoffY; + cutoffX= std::min((tileX+1)*panelWidth,width); + cutoffY= std::min((tileY+1)*panelHeight,height); + for (unsigned int ui=tileX*panelWidth; ui<=cutoffX; ui++) + { + pixY=0; + for (unsigned int uj=tileY*panelHeight; uj<=cutoffY; uj++) + { + pixel=pixels+(3*(pixY*panelWidth+ pixX)); + image->SetRGB(ui,(height-1)-uj,pixel[2],pixel[1],pixel[0]); + pixY++; + } + pixX++; + } + } + + } + //Disable the view restriction + currentScene.unrestrictView(); + if(showProgress) + wxD->Destroy(); + + } + else + { + //"Resize" the viewport. This wont cause the underlying buffer to resize + //so the imae will reduce, but be surrounded by borders. + //Its a bit of a hack, but it should work + prepare3DViewport(0,0,width,height); + + //Clear the buffers and draw the openGL scene + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + currentScene.draw(); + glFinish(); + + SwapBuffers(); + glReadBuffer(GL_BACK); + + //Set the pixel alignment to one byte, so that openGL unpacks + //correctly into our buffer. + glPushAttrib(GL_PACK_ALIGNMENT); + glPixelStorei(GL_PACK_ALIGNMENT,1); + //Read the image + glReadPixels(0, 0, width,height, + GL_BGR, GL_UNSIGNED_BYTE, pixels); + + + glPopAttrib(); + + char *pixel; + + //copy rows & columns into image + for(unsigned int ui=0;uiSetRGB(ui,(height-1)-uj,pixel[2],pixel[1],pixel[0]); + } + } + + //Restore viewport + prepare3DViewport(0,0,getWidth(),getHeight()); + } + + delete[] pixels; + + bool isOK=image->SaveFile(wxCStr(filename),wxBITMAP_TYPE_PNG); + + currentScene.setAspect(oldAspect); + delete image; + + if (needPostPaint) { + wxPaintEvent event; + wxPostEvent(this,event); + } + + return isOK; +} + +void BasicGLPane::OnAxisTapTimer(wxTimerEvent &evt) +{ + lastKeyDoubleTap=(unsigned int)-1; +} + + +bool BasicGLPane::saveImageSequence(unsigned int resX, unsigned int resY, unsigned int nFrames, + wxString &path,wxString &prefix, wxString &ext) +{ + //OK, lets animate! + // + + + ASSERT(!currentScene.haveTempCam()); + std::string outFile; + wxProgressDialog *wxD = new wxProgressDialog(wxTRANS("Animation progress"), + wxTRANS("Rendering sequence..."), nFrames,this,wxPD_CAN_ABORT ); + + wxD->Show(); + std::string tmpStr,tmpStrTwo; + stream_cast(tmpStrTwo,nFrames); + for(unsigned int ui=0;uimove(angle,0); + + //Save the result + outFile = string(stlStr(path))+ string("/") + + string(stlStr(prefix))+digitStr+ string(".") + string(stlStr(ext)); + if(!saveImage(resX,resY,outFile.c_str(),false, false)) + return false; + + //Update the progress bar + stream_cast(tmpStr,ui+1); + //Tell user which image from the animation we are saving + tmpStr = std::string(TRANS("Saving Image ")) + tmpStr + std::string(TRANS(" of ")) + tmpStrTwo + "..."; + if(!wxD->Update(ui,wxStr(tmpStr))) + break; + + Refresh(); + } + + //Discard the current temp. cam to return the scene back to normal + currentScene.discardTempCam(); + wxD->Destroy(); + + wxPaintEvent event; + wxPostEvent(this,event); + return true; + +} diff -Nru 3depict-0.0.12/src/gui/glPane.h 3depict-0.0.13/src/gui/glPane.h --- 3depict-0.0.12/src/gui/glPane.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glPane.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * gLPane.h - WxWidgets opengl Pane. + * 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 . +*/ +#ifndef GLPANE_H +#define GLPANE_H + +#include + +#include "gl/scene.h" + + +class BasicGLPane : public wxGLCanvas +{ +private: + wxStatusBar *parentStatusBar; + wxTimer *parentStatusTimer; + unsigned int statusDelay; + //In some implementation of openGL in wx. + //calling GL funcs before Paint() will crash program + bool paneInitialised; + //Is the user engaged in a drag operation? + bool dragging; + + //Where is the start of the mouse drag? + wxPoint draggingStart; + bool lastMoveShiftDown; + + //True if an object has been mouse-overed for selection + bool selectionMode; + //The scene ID value for the currently selected object + unsigned int curSelectedObject; + //The scene ID value for object currently being "hovered" over + unsigned int hoverObject; + + //!Last mouseflags/keyflags during selection event + unsigned int lastMouseFlags,lastKeyFlags; + + //Test for a object selection. Returns -1 if no selection + //or object ID if selection OK. Also sets lastSelected & scene + unsigned int selectionTest(const wxPoint &p, bool &shouldRedraw); + + //Test for a object hover under cursor Returns -1 if no selection + //or object ID if selection OK. Also sets last hover and scene + unsigned int hoverTest(const wxPoint &p, bool &shouldRedraw); + + //!Are there updates to the camera Properties due to camera motion? + bool haveCameraUpdates; + + //!Are we currently applying a device in the scene? + bool applyingDevice; + + //Parameters for modifying mouse speed + float mouseZoomFactor,mouseMoveFactor; + + unsigned int lastKeyDoubleTap; + + wxTimer *keyDoubleTapTimer; +public: + bool displaySupported() const; + + //Enable/Disable the scene interaction for user objects? + void setSceneInteractionAllowed(bool enabled=true); + + //!The scene object, holds all info about 3D drawable components + Scene currentScene; + + //!Must be called before user has a chance to perform interaction + void setParentStatus(wxStatusBar *statusBar, + wxTimer *timer,unsigned int statDelay) + { parentStatusBar=statusBar;parentStatusTimer=timer;statusDelay=statDelay;}; + + bool hasCameraUpdates() const {return haveCameraUpdates;}; + + void clearCameraUpdates() {haveCameraUpdates=false;}; + + BasicGLPane(wxWindow* parent); + ~BasicGLPane(); + + void resized(wxSizeEvent& evt); + + int getWidth(); + int getHeight(); + + + void setMouseMoveFactor(float f) { mouseMoveFactor=f;}; + void setMouseZoomFactor(float f) { mouseZoomFactor=f;}; + + //!Is the window initialised? + bool isInited() { return paneInitialised;} + + //!Set the background colour (openGL clear colour) + void setGlClearColour(float r,float g,float b); + //!Pull in the colour from the scene + void updateClearColour(); + //!Render the view using the scene + void render(wxPaintEvent& evt); + //!Construct a 3D viewport, ready for openGL output. Returns false if initialisation failed + bool prepare3DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y); + //!Save an image to file, return false on failure + bool saveImage(unsigned int width, unsigned int height,const char *filename, bool showProgress=true, bool needPostPaint=true); + //!Save an image sequence to files by orbiting the camera + bool saveImageSequence(unsigned int width, unsigned int height, unsigned int nFrames, + wxString &path, wxString &prefix, wxString &extension); + + //!Get the background colour + void getGlClearColour(float &r,float &g,float &b) { currentScene.getBackgroundColour(r,g,b);} + // events + void mouseMoved(wxMouseEvent& event); + void mouseDown(wxMouseEvent& event); + void mouseWheelMoved(wxMouseEvent& event); + void mouseReleased(wxMouseEvent& event); + void rightClick(wxMouseEvent& event); + void mouseLeftWindow(wxMouseEvent& event); + void keyPressed(wxKeyEvent& event); + void keyReleased(wxKeyEvent& event); + void charEvent(wxKeyEvent& event); + void OnEraseBackground(wxEraseEvent &); + void OnAxisTapTimer(wxTimerEvent &); + bool setFullscreen(bool fullscreen); + bool setMouseVisible(bool visible); + + + DECLARE_EVENT_TABLE() +}; + +#endif diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/animateFilterDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/animateFilterDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/animateFilterDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/animateFilterDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,572 @@ + + + + + + /*\n * animateFilterDialog - GUI for animate filter\n * Copyright (C) 2012, D. Haley, A Ceguerra \n \n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n \n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n \n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n + + Export Animation + Enter parameters for exporting animatio frames + + wxVERTICAL + + wxEXPAND + 0 + + + + + Filter view + Frame view + + + + Enter animation key frames for each filter's property + + wxHORIZONTAL + + wxEXPAND + 0 + + + + wxSPLIT_VERTICAL + filterRightPane + filterLeftPane + + + + wxVERTICAL + + + wxALL|wxEXPAND + 3 + + + + Select filter + ID_FILTER_TREE_CTRL + + OnFilterTreeCtrlSelChanged + + + + + wxALL|wxEXPAND + 3 + + + ID_PROPERTY_GRID + Select property; double click to fill key frames with default values + 1 + 1 + 1 + 10 + 1 + 1 + 1 + wxGrid.wxGridSelectCells + + Property + Value + + + OnPropGridDClick + OnFilterGridCellEditorShow + + + + + + + + + wxVERTICAL + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxALL|wxEXPAND + 3 + + + ID_FILTER_GRID_CTRL + Key frame table + 1 + 1 + 1 + 0 + 1 + 1 + 1 + wxGrid.wxGridSelectCells + + Filter + Property + Mode + Start Frame + End Frame + + + OnAnimateDClick + + + + + + + wxALL|wxEXPAND + 3 + + + wxHORIZONTAL + + wxALIGN_CENTER_HORIZONTAL + 0 + + + + REMOVE + + Remove the selected key frame from the table + ID_BUTTON_FRAME_REMOVE + + OnButtonKeyFrameRemove + + + + + + + + + + + + + + Viewer for animation parameters for each frame + + wxHORIZONTAL + + wxEXPAND + 0 + + + wxVERTICAL + + + wxALL|wxEXPAND + 4 + + + wxHORIZONTAL + + wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL + 3 + + + 1 + Enter or browse to directory where the animation frames will be exported to + + + + + wxEXPAND + 0 + + + Enter where the animation frames will be exported to + ID_TEXTBOX_WORKDIR + + OnOutputDirText + + + + + wxLEFT|wxRIGHT + 2 + + + OPEN + + Browse to directory where the animation frames will be exported to + ID_BUTTON_WORKDIR + + OnButtonWorkDir + + + + + + + wxBOTTOM|wxEXPAND + 5 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + 0 + + + 1 + + ID_CHECK_ONLYDATACHANGE + + OnCheckOutDataChange + + + + + + + wxTOP|wxBOTTOM|wxEXPAND + 3 + + + + 1 + + + + wxTOP|wxBOTTOM + 4 + + + 1 + + + + + wxLEFT|wxTOP + 3 + + + 1 + + ID_CHECK_IMAGE_OUT + + OnCheckImageOutput + + + + + wxEXPAND + 0 + + + wxVERTICAL + + wxALL|wxEXPAND + 3 + + + wxHORIZONTAL + + wxLEFT|wxALIGN_CENTER_VERTICAL + 3 + + + 1 + Enter the target resolution (width) + + + + + wxALL|wxEXPAND + 4 + + + Enter the target resolution (width) + ID_TEXTBOX_IMAGEPREFIX + + OnImageFilePrefix + + + + + + + wxALL|wxEXPAND + 3 + + + wxHORIZONTAL + + wxLEFT|wxALIGN_CENTER_VERTICAL + 3 + + + 1 + Enter the target resolution (width) + + + + + wxALL|wxEXPAND + 4 + + + Enter the target resolution (width) + ID_TEXTBOX_IMAGESIZE + + OnTextImageSize + + + + + wxALL + 4 + + + + ID_BUTTON_IMAGE_RES + + OnBtnResolution + + + + + + + + + wxLEFT|wxBOTTOM + 3 + + + + ID_CHECK_POINT_OUNT + + OnCheckPointOutput + + + + + wxLEFT|wxTOP + 3 + + + + ID_CHECK_PLOT_OUT + + OnCheckPlotOutput + + + + + wxLEFT|wxTOP|wxBOTTOM + 3 + + + + ID_CHECK_VOXEL_OUT + + OnCheckVoxelOutput + + + + + wxALL + 3 + + + + ID_CHECK_RANGE_OUT + + OnCheckRangeOutput + + + + + wxLEFT|wxBOTTOM|wxEXPAND + 5 + + + wxHORIZONTAL + + wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL + 3 + + + 1 + + + + + wxLEFT|wxRIGHT|wxEXPAND + 3 + + + -1 + ID_COMBO_RANGE_TYPE + + ORNL RNG + CAMECA RRNG + CAMECA ENV + + + OnRangeTypeCombo + + + + + + + 0 + + + 20 + 20 + + + + + + wxLEFT|wxRIGHT|wxEXPAND + 5 + + + + 1 + + + + wxALL|wxEXPAND + 3 + + + wxVERTICAL + + wxALL|wxEXPAND + 3 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + Use the slider or enter the frame to view animation parameters + + + + + wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + + Slider to select frame + ID_FRAME_SLIDER + 1, 1 + 1 + + OnFrameSlider + + + + + wxALIGN_CENTER_VERTICAL + 0 + + + Enter frame number + ID_FRAME_TEXTBOX + + OnTextFrame + + + + + + + wxEXPAND + 0 + + + ID_FILTER_PROPERTY_VALUE_GRID + Animation parameters for current frame + 1 + 1 + 1 + 0 + 1 + 1 + 1 + wxGrid.wxGridSelectCells + + Filter + Property + Value + + + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxEXPAND + 0 + + + 1 + 20 + + + + wxALL|wxALIGN_BOTTOM + 3 + + + + CANCEL + + Abort animation + + OnButtonCancel + + + + + wxALL|wxALIGN_BOTTOM + 3 + + + + OK + + Run Animation + + OnButtonOK + + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/choiceKeyFrameDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/choiceKeyFrameDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/choiceKeyFrameDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/choiceKeyFrameDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,109 @@ + + + + + + enum\n{\nID_TEXT_FRAME,\nID_COMBO_CHOICE\n}; + + Key Frame + + wxVERTICAL + + wxALL|wxEXPAND + 10 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 20 + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 5 + + + ID_TEXT_FRAME + + OnFrameText + + + + + + + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 10 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + 1 + + + + + wxLEFT + 5 + + + + -1 + ID_COMBO_CHOICE + + + + OnChoiceCombo + + + + + + + wxALL|wxEXPAND + 5 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxRIGHT + 5 + + + CANCEL + + wxID_CANCEL + + + + wxLEFT + 5 + + + OK + + wxID_OK + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/colourChooserDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/colourChooserDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/colourChooserDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/colourChooserDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,329 @@ + + + + + + enum{\nID_COMBO_TRANSITION,\nID_TEXT_FINAL_VALUE,\nID_TEXT_FRAME_START,\nID_TEXT_INITIAL_VALUE,\n}; + + Key Frame : Colour + + wxVERTICAL + + 0 + + + 5 + 20 + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + 0 + + + 20 + 10 + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 10 + 20 + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 14 + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 5 + + + + -1 + ID_COMBO_TRANSITION + + Step + Ramp + + + OnComboTransition + + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 4 + + + ID_TEXT_FRAME_START + + OnTextStartFrame + + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 12 + + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 4 + + + ID_TEXT_FRAME_START + + OnTextEndFrame + + + + + + + 0 + + + 10 + 20 + + + + + + wxLEFT|wxRIGHT|wxEXPAND + 5 + + + + 1 + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 20 + 20 + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 3 + + + + + Colour at the start of the transtition + + OnBtnStartColour + + + + + 0 + + + 20 + 20 + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 9 + + + + 1 + + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 3 + + + + + Colour at end of transition + + OnBtnEndColour + + + + + 0 + + + 20 + 20 + + + + + + 0 + + + 20 + 20 + + + + + + 0 + + + 20 + 10 + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxALL + 4 + + + CANCEL + wxID_CANCEL + + OnButtonCancel + + + + + wxALL + 4 + + + OK + wxID_OK + + OnButtonOK + + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/realKeyFrameDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/realKeyFrameDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/realKeyFrameDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/realKeyFrameDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,291 @@ + + + + + + enum{\nID_COMBO_TRANSITION,\nID_TEXT_FINAL_VALUE,\nID_TEXT_FRAME_START,\nID_TEXT_INITIAL_VALUE,\n}; + + Key Frame :Number + + wxVERTICAL + + 0 + + + 5 + 20 + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + 0 + + + 20 + 10 + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 10 + 20 + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 14 + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 5 + + + + -1 + ID_COMBO_TRANSITION + + Step + Ramp + + + OnComboTransition + + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 4 + + + ID_TEXT_FRAME_START + + OnTextStartFrame + + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 12 + + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 4 + + + ID_TEXT_FRAME_START + + OnTextEndFrame + + + + + + + 0 + + + 10 + 20 + + + + + + wxLEFT|wxRIGHT|wxEXPAND + 5 + + + + 1 + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 20 + 20 + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 4 + + + ID_TEXT_INITIAL_VALUE + + OnTextInitialValue + + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_CENTER_VERTICAL + 9 + + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 4 + + + ID_TEXT_FINAL_VALUE + + OnTextFinalValue + + + + + + + 0 + + + 20 + 20 + + + + + + 0 + + + 20 + 10 + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxALL + 4 + + + CANCEL + + OnButtonCancel + + + + + wxALL + 4 + + + OK + + OnButtonOK + + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/stringKeyFrameDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/stringKeyFrameDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/animateSubDialogs/stringKeyFrameDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/animateSubDialogs/stringKeyFrameDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,217 @@ + + + + + + enum\n{\nID_TEXT_START_FRAME,\nID_RADIO_FROM_FILE,\nID_TEXT_FROM_FILE,\nID_RADIO_FROM_TABLE,\nID_GRID_STRINGS\n}; + + String Keyframes + Frame at which to start string sequence + 595, 412 + + wxVERTICAL + + wxALL|wxEXPAND + 6 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + wxLEFT|wxALIGN_CENTER_VERTICAL + 6 + + + Frame offset for data start + ID_TEXT_START_FRAME + + OnTextStart + + + + + 0 + + + 20 + 20 + + + + + + wxALL|wxEXPAND + 6 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + + ID_RADIO_FROM_FILE + + OnFileRadio + + + + + wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL + 6 + + + File to use as string data source, one value per row + ID_TEXT_FROM_FILE + + OnTextFilename + + + + + wxLEFT|wxRIGHT + 6 + + + + OPEN + + Select file to use as data source + wxID_OPEN + + OnBtnChooseFile + + + + + + + wxLEFT + 6 + + + + Use table below for data source + ID_RADIO_FROM_TABLE + + OnTableRadio + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxALL|wxEXPAND + 5 + + + ID_GRID_STRINGS + 1 + 1 + 1 + 0 + 1 + 1 + 1 + wxGrid.wxGridSelectCells + + Frame + Value + + + OnGridCellChange + OnGridEditorShown + + + + + wxRIGHT|wxEXPAND + 5 + + + wxVERTICAL + + wxBOTTOM + 5 + + + ADD + + Add new data rows to table + wxID_ADD + + OnBtnAdd + + + + + 0 + + + REMOVE + + Remove selected strings from table + wxID_REMOVE + + OnBtnRemove + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxALL + 5 + + + CANCEL + + Abort value selection and return to previous window + wxID_CANCEL + + + + wxALL + 5 + + + OK + + Accept data values + wxID_OK + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/autosaveDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/autosaveDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/autosaveDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/autosaveDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,75 @@ + + + + + + enum\n{\nID_LIST_STATES=wxID_ANY+1,\nID_REMOVE_ALL + + Restore state? + + wxVERTICAL + + wxLEFT|wxRIGHT|wxTOP|wxALIGN_CENTER_HORIZONTAL + 6 + + + + 1 + + + + + wxALL|wxEXPAND + 8 + + + 0 + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxLEFT|wxBOTTOM + 8 + + + + + + + 0 + + + 20 + 20 + + + + wxLEFT|wxRIGHT|wxBOTTOM + 8 + + + CANCEL + + + + + wxRIGHT|wxBOTTOM + 8 + + + OK + + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/errorDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/errorDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/errorDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/errorDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,111 @@ + + + + + + + Filter Errors + 551, 414 + + wxVERTICAL + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 6 + + + + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 10 + 10 + + + + wxTOP|wxEXPAND + 5 + + + wxHORIZONTAL + + 0 + + + 1 + + + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + + + wxTOP|wxEXPAND + 6 + + + wxHORIZONTAL + + 0 + + + 1 + + + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + + + 0 + + + 20 + 20 + + + + + + + + wxALL|wxALIGN_RIGHT + 5 + + + OK + + wxID_OK + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/mainWindow.wxg 3depict-0.0.13/src/gui/glade-skeleton/mainWindow.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/mainWindow.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/mainWindow.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,868 @@ + + + + + + enum {\nID_COMBO_SETTINGS = wxID_ANY+1,\nID_FILE_EXIT,\nID_FILE_OPEN,\nID_FILE_SAVE,\nID_FILE_SAVEAS,\nID_HELP_ABOUT,\nID_HELP_HELP,\nID_NOTEBOOK_CONTROL,\nID_NOTE_CAMERA,\nID_NOTE_DATA,\nID_NOTE_PERFORMANCE,\nID_NOTE_TOOLS,\nID_NOTE_VISUALISATION,\nID_PANEL_DATA,\nID_PANEL_VIEW,\nID_SPLIT_LEFTRIGHT,\nID_SPLIT_TOP_BOTTOM,\nID_NOTE_SPECTRA,\nID_NOTE_RAW,\n}; + + Quick 3D + 1 + + + + + + ID_FILE_OPEN + Open + Open state file + OnFileOpen + + + + ID_FILE_SAVE + Save + Save state to file + OnFileSave + + + + ID_FILE_SAVEAS + MenuSaveAs + Save current state to new file + OnFileSaveAs + + + + --- + --- + + + + + Export Current Plot + OnFileExportPlot + + + + Export Current 3D View + OnFileExportImage + + + + Export Ion Data + OnFileExportIons + + + + Export Range Data + OnFileExportRange + + + + + --- + --- + + + + ID_FILE_EXIT + Exit + Exit Program + OnFileExit + + + + + + + + + --- + --- + + + + ID_VIEW_CONTROL_PANE + MenuControlPane + Enable or disable the left control pane + 1 + OnViewControlPane + + + + ID_VIEW_RAW_DATA_PANE + MenuRawDataPane + Enable or disable the raw data pane (bottom of right panel) + 1 + OnViewRawDataPane + + + + ID_VIEW_SPECTRA + MenuViewSPectra + 1 + + + + --- + --- + + + + + + + + + ID_HELP_HELP + MenuHelp + Show help files and documentation + OnHelpHelp + + + + --- + --- + + + + ID_HELP_ABOUT + MenuAbout + Information about this program + OnHelpAbout + + + + + + wxHORIZONTAL + + wxEXPAND + 0 + + + + wxSPLIT_VERTICAL + ID_SPLIT_LEFTRIGHT + panelView + panelLeft + + + + wxVERTICAL + + wxLEFT|wxBOTTOM|wxEXPAND + 2 + + + + + Data + Cam + Post + Tools + + ID_NOTEBOOK_CONTROL + + + 10, 10 + 1 + ID_NOTE_DATA + + wxVERTICAL + + 0 + + + 1 + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND + 3 + + + + 0 + ID_COMBO_SETTINGS + + + + OnComboSettings + OnComboSettingsText + OnComboSettingsEnter + + + + + wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 0 + + + + + + + + + wxEXPAND + 0 + + + + 1 + + + + 0 + + + 1 + + + + + wxEXPAND + 0 + + + + wxSPLIT_HORIZONTAL + filterPropertyPane + filterTreePane + + + + wxHORIZONTAL + + wxEXPAND + 0 + + + wxVERTICAL + + wxLEFT|wxRIGHT|wxEXPAND + 4 + + + + -1 + List of available filters + ID_FILTER_NAMES + + Range File + Downsampling + Mass Spectrum + Clipping + Compos. Profiles + Bounding Box + Ion Colour + Ion Transform + + + OnFilterNameCombo + OnFilterNameComboText + OnFilterNameComoEnter + + + + + wxLEFT|wxBOTTOM|wxEXPAND + 3 + + + + Tree of data filters + ID_TREE_FILTERS + + OnTreeBeginDrag + OnTreeEndDrag + OnTreeDeleteItem + OnTreeSelectionChange + OnTreeKeyDown + OnTreeItemTooltip + + + + + wxTOP + 8 + + + 1 + + + + + wxBOTTOM|wxEXPAND + 5 + + + + + + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 1 + + Enable/Disable automatic updates of data when filter change takes effect + ID_CHECK_AUTOUPDATE + + + + 0 + + + 10 + 10 + + + + wxALL + 2 + + + REFRESH + + + + + wxEXPAND + 0 + + + + + + + + + + + + + wxVERTICAL + + 0 + + + 1 + + + + + wxLEFT|wxEXPAND + 4 + + + ID_GRID_FILTER_PROPERTY + 1 + 1 + 1 + 3 + 1 + 0 + 1 + wxGrid.wxGridSelectCells + + Property + Value + + + OnGridFilterPropertyChange + + + + + + + + + + + + 10, 10 + 1 + ID_NOTE_CAMERA + + wxVERTICAL + + 0 + + + 1 + + + + + wxTOP|wxBOTTOM|wxEXPAND + 4 + + + wxHORIZONTAL + + 0 + + + -1 + ID_COMBO_CAMERA + + + + OnEventComboBox + OnEventText + OnEventTextEnter + + + + + wxLEFT|wxRIGHT + 2 + + + REMOVE + + + OnButtonRemoveCam + + + + + + + wxEXPAND + 0 + + + + 1 + + + + wxEXPAND + 0 + + + ID_GRID_CAMERA_PROPERTIES + Camera data information + 1 + 1 + 1 + 4 + 1 + 0 + 1 + wxGrid.wxGridSelectRows + + Property + Value + + + + + + + + + wxVERTICAL + + wxALL + 5 + + + + Enable/disable visual effects on final 3D output + + OnCheckPostProcess + + + + + wxEXPAND + 0 + + + + + Crop + Stereo + + + + + wxVERTICAL + + wxALL + 6 + + + + Enable cropping post-process effect + ID_EFFECT_CROP_ENABLE + + OnFxCropCheck + + + + + wxLEFT + 15 + + + + + + + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 5 + + + wxHORIZONTAL + + wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 0 + + + wxVERTICAL + + wxRIGHT|wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL + 5 + + + + 0 + ID_EFFECT_CROP_AXISONE_COMBO + + x-y + x-z + y-x + y-z + z-x + z-y + + + OnFxCropAxisOne + + + + + wxRIGHT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxSHAPED + 5 + + + + #54fff4 + ID_EFFECT_CROP_PANELONE_COMBO + + + + + + wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 0 + + + wxVERTICAL + + wxLEFT|wxBOTTOM|wxEXPAND + 5 + + + + 0 + ID_EFFECT_CROP_AXISTWO_COMBO + + x-y + x-z + y-x + y-z + z-x + z-y + + + OnFxCropAxisTwo + + + + + wxLEFT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxSHAPED + 5 + + + + #ff4fe2 + ID_EFFECT_CROP_PANELTWO_COMBO + + + + + + + + wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 5 + + + 2 + 0,1,2 + 3 + 0,1 + 2 + 2 + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + 0 + + + ID_EFFECT_CROP_TEXT_DX + + + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + 0 + + + ID_EFFECT_CROP_TEXT_DY + + + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + 0 + + + ID_EFFECT_CROP_TEXT_DZ + + + + + + + + + + wxVERTICAL + + wxLEFT|wxTOP + 6 + + + + Colour based 3D effect enable/disable + + OnFxStereoEnable + + + + + 0 + + + 20 + 20 + + + + wxBOTTOM|wxEXPAND + 15 + + + wxHORIZONTAL + + wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + + 1 + + + + + wxLEFT + 5 + + + + 0 + Glasses colour mode + + Red-Blue + Red-Green + Red-Cyan + Half Colour + Mixed Colour + + + OnFxStereoCombo + + + + + 0 + + + 1 + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxLEFT|wxTOP + 5 + + + 1 + + + + + wxLEFT|wxRIGHT|wxTOP|wxEXPAND + 5 + + + + Level of separation between left and right images, which sets 3D depth to visual distortion tradeoff + + OnFxStereoBaseline + + + + + + + wxLEFT + 5 + + + + Reverse output 3D channels (to negate a flip in 3D lens layout) + + + + + + + + + + + + wxVERTICAL + + wxLEFT|wxTOP|wxBOTTOM + 5 + + + + + + + wxLEFT|wxTOP|wxBOTTOM + 6 + + + + + + + wxLEFT|wxTOP|wxBOTTOM + 5 + + + + + + + wxLEFT|wxTOP|wxBOTTOM + 5 + + + + + + + wxTOP|wxEXPAND + 5 + + + wxHORIZONTAL + + wxRIGHT|wxALIGN_RIGHT + 5 + + + 1 + + + + + 5 + + + 0, 100 + 50 + + + + + + + + + + + + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/preferencesDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/preferencesDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/preferencesDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/preferencesDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,400 @@ + + + + + + + Preferences + 642, 487 + + wxVERTICAL + + wxEXPAND + 0 + + + + + Pref + Startup + Camera + + + + + wxHORIZONTAL + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + 1 + + + + + wxEXPAND + 0 + + + + 0 + ID_LIST_FILTERS + + + + OnListClick + + + + + + + 0 + + + 20 + 20 + + + + wxEXPAND + 0 + + + wxVERTICAL + + wxEXPAND + 0 + + + 10 + ID_GRID_PROPERTIES + + + + wxGrid.wxGridSelectCells + 1 + 1 + 1 + 0 + 1 + + OnFilterCellClick + OnFilterCellChange + + 1 + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + 0 + + + + + + + 0 + + + + + + + 0 + + + 20 + 20 + + + + + + + + + + + + wxVERTICAL + + wxALL|wxEXPAND + 5 + + + wxVERTICAL + + + 0 + + + + 0 + Set the method of panel layout when starting the program + ID_START_COMBO_PANEL + + Always show + Remember + Specify + + + OnStartupPanelCombo + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 20 + + + + wxEXPAND + 0 + + + wxVERTICAL + + 0 + + + + ID_START_CHECK_CONTROL + + OnStartupCheckControl + + + + + 0 + + + + ID_START_CHECK_RAWDATA + + OnStartupCheckRawData + + + + + 0 + + + + ID_START_CHECK_PLOTLIST + + OnStartupCheckPlotList + + + + + + + + + + + wxALL|wxEXPAND + 5 + + + wxVERTICAL + + + 0 + + + + Lets the program check the internet to see if updates to the program version are available, then bugs you about it now and again. + + + + + + + + + + wxVERTICAL + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + + + 0 + + + 20 + 20 + + + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + Camera tanslation, orbit and swivel rates. + 1, 100 + 1 + + + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + + + 0 + + + 20 + 20 + + + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL + 0 + + + + Camera zooming rate. + 1, 100 + 1 + + + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxEXPAND + 0 + + + 20 + 20 + + + + wxTOP + 8 + + + OK + + + + + wxLEFT|wxTOP|wxBOTTOM + 8 + + + CANCEL + + + + + 0 + + + 20 + 10 + + + + + + + diff -Nru 3depict-0.0.12/src/gui/glade-skeleton/resDialog.wxg 3depict-0.0.13/src/gui/glade-skeleton/resDialog.wxg --- 3depict-0.0.12/src/gui/glade-skeleton/resDialog.wxg 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/glade-skeleton/resDialog.wxg 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,208 @@ + + + + + + enum\n{\n ID_RESET=wxID_ANY+1,\n ID_SPIN_WIDTH,\n ID_SPIN_HEIGHT,\n ID_LOCK_ASPECT\n}; + + Resolution Selection + + wxVERTICAL + + wxEXPAND + 0 + + + wxHORIZONTAL + + 0 + + + 20 + 10 + + + + wxLEFT|wxEXPAND + 8 + + + wxVERTICAL + + 0 + + + 20 + 20 + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + + + wxALL|wxALIGN_CENTER_VERTICAL + 8 + + + ID_SPIN_WIDTH + + OnSpinWidth + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + wxALIGN_CENTER_VERTICAL + 0 + + + 1 + + + + + wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL + 5 + + + ID_SPIN_HEIGHT + + OnSpinHeight + + + + + + + wxALIGN_CENTER_VERTICAL + 3 + + + + ID_LOCK_ASPECT + + OnCheckLockAspect + + + + + 0 + + + 20 + 20 + + + + + + 0 + + + 10 + 10 + + + + wxEXPAND + 0 + + + + 1 + + + + wxALL|wxEXPAND + 5 + + + + + + + + + wxEXPAND + 0 + + + + 1 + + + + wxTOP|wxBOTTOM|wxEXPAND + 5 + + + wxHORIZONTAL + + wxALL + 5 + + + + ID_RESET + + OnBtnRefresh + + + + + 0 + + + 20 + 20 + + + + wxALL + 5 + + + OK + + + OnBtnOK + + + + + wxALL + 5 + + + CANCEL + + + OnBtnCancel + + + + + + + + diff -Nru 3depict-0.0.12/src/gui/mainFrame.cpp 3depict-0.0.13/src/gui/mainFrame.cpp --- 3depict-0.0.12/src/gui/mainFrame.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/mainFrame.cpp 2013-04-10 20:52:37.000000000 +0000 @@ -0,0 +1,5522 @@ +/* + * 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 . +*/ + +#include "mainFrame.h" + +#ifdef __APPLE__ +//FIXME: workaround for UI layout under apple platform +// wxMac appears to have problems with nested panels. +#define APPLE_EFFECTS_WORKAROUND 1 +#endif + +enum +{ + WINDOW_LOCK_REFRESH, + WINDOW_LOCK_PROPEDIT, + WINDOW_LOCK_NONE +}; + + +//OS specific stuff +#ifdef __APPLE__ +#include "CoreFoundation/CoreFoundation.h" +#endif + +#include "mainFrame.h" + +//wxWidgets stuff +#include +#include +#include +#include +#include +#include +#include +#include + +#if wxCHECK_VERSION(2, 9, 0) + #include // Needed for wxLaunchDefaultApplication +#else + #include //Needed for GetOpenCommand +#endif + +//Custom program dialog windows +#include "gui/dialogs/StashDialog.h" //Stash editor +#include "gui/dialogs/resolutionDialog.h" // resolution selection dialog +#include "gui/dialogs/ExportRngDialog.h" // Range export dialog +#include "gui/dialogs/ExportPos.h" // Ion export dialog +#include "gui/dialogs/prefDialog.h" // Preferences dialog +#include "gui/dialogs/autosaveDialog.h" // startup autosave dialog for multiple load options +#include "gui/dialogs/filterErrorDialog.h" // Dialog for displaying details for filter analysis error messages +#include "gui/dialogs/animateFilterDialog.h" // Dialog for performing property sweeps on filters + +#include "common/stringFuncs.h" + +//Program Icon +#include "art.h" + +//Filter imports +#include "backend/filters/rangeFile.h" +#include "backend/filters/dataLoad.h" + + +using std::pair; +using std::max; + +//milliseconds before clearing status bar (by invoking a status timer event) +const unsigned int STATUS_TIMER_DELAY=10000; +//Milliseconds between querying viscontrol for needing update +const unsigned int UPDATE_TIMER_DELAY=50; +//Milliseconds between progress bar updates +const unsigned int PROGRESS_TIMER_DELAY=100; +//Seconds between autosaves +const unsigned int AUTOSAVE_DELAY=180; + +//Default window size +const unsigned int DEFAULT_WIN_WIDTH=1024; +const unsigned int DEFAULT_WIN_HEIGHT=800; + +//minimum startup window size +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; + +//The conversion factor from the baseline shift slider to camera units +const float BASELINE_SHIFT_FACTOR=0.0002f; + + +const char *cameraIntroString=NTRANS("New camera name..."); +const char *stashIntroString=NTRANS("New stash name...."); + +//Name of autosave state file. MUST end in .xml middle +const char *AUTOSAVE_PREFIX= "autosave."; +const char *AUTOSAVE_SUFFIX=".xml"; + + +//This is the dropdown matching list. This must match +//the order for comboFilters_choices, as declared in +//MainFrame's constructor + +//--- These settings must be modified concomitantly. +const unsigned int FILTER_DROP_COUNT=14; + +const char * comboFilters_choices[FILTER_DROP_COUNT] = +{ + NTRANS("Annotation"), + NTRANS("Bounding Box"), + NTRANS("Clipping"), + NTRANS("Cluster Analysis"), + NTRANS("Compos. Profiles"), + NTRANS("Downsampling"), + NTRANS("Extern. Prog."), + NTRANS("Ion Colour"), + NTRANS("Ion Info"), + NTRANS("Ion Transform"), + NTRANS("Spectrum"), + NTRANS("Range File"), + NTRANS("Spat. Analysis"), + NTRANS("Voxelisation") +}; + +//Mapping between filter ID and combo position +const unsigned int comboFiltersTypeMapping[FILTER_DROP_COUNT] = { + FILTER_TYPE_ANNOTATION, + FILTER_TYPE_BOUNDBOX, + FILTER_TYPE_IONCLIP, + FILTER_TYPE_CLUSTER_ANALYSIS, + FILTER_TYPE_COMPOSITION, + FILTER_TYPE_IONDOWNSAMPLE, + FILTER_TYPE_EXTERNALPROC, + FILTER_TYPE_IONCOLOURFILTER, + FILTER_TYPE_IONINFO, + FILTER_TYPE_TRANSFORM, + FILTER_TYPE_SPECTRUMPLOT, + FILTER_TYPE_RANGEFILE, + FILTER_TYPE_SPATIAL_ANALYSIS, + FILTER_TYPE_VOXELS + }; +//---- + +//Constant identifiers for binding events in wxwidgets "event table" +enum { + + //File menu + ID_MAIN_WINDOW= wxID_ANY+1, + + ID_FILE_EXIT, + ID_FILE_OPEN, + ID_FILE_MERGE, + ID_FILE_SAVE, + ID_FILE_SAVEAS, + ID_FILE_EXPORT_PLOT, + ID_FILE_EXPORT_IMAGE, + ID_FILE_EXPORT_IONS, + ID_FILE_EXPORT_RANGE, + ID_FILE_EXPORT_ANIMATION, + ID_FILE_EXPORT_FILTER_ANIMATION, + ID_FILE_EXPORT_PACKAGE, + + //Edit menu + ID_EDIT_UNDO, + ID_EDIT_REDO, + ID_EDIT_PREFERENCES, + + //Help menu + ID_HELP_ABOUT, + ID_HELP_HELP, + ID_HELP_CONTACT, + + //View menu + ID_VIEW_BACKGROUND, + ID_VIEW_CONTROL_PANE, + ID_VIEW_RAW_DATA_PANE, + ID_VIEW_SPECTRA, + ID_VIEW_PLOT_LEGEND, + ID_VIEW_WORLDAXIS, + ID_VIEW_FULLSCREEN, + //Left hand note pane + ID_NOTEBOOK_CONTROL, + ID_NOTE_CAMERA, + ID_NOTE_DATA, + ID_NOTE_PERFORMANCE, + ID_NOTE_TOOLS, + ID_NOTE_VISUALISATION, + //Lower pane + ID_PANEL_DATA, + ID_PANEL_VIEW, + ID_NOTE_SPECTRA, + ID_NOTE_RAW, + ID_GRID_RAW_DATA, + ID_BUTTON_GRIDCOPY, + ID_LIST_PLOTS, + + //Splitter IDs + ID_SPLIT_LEFTRIGHT, + ID_SPLIT_FILTERPROP, + ID_SPLIT_TOP_BOTTOM, + ID_SPLIT_SPECTRA, + ID_RAWDATAPANE_SPLIT, + ID_CONTROLPANE_SPLIT, + + //Camera panel + ID_COMBO_CAMERA, + ID_GRID_CAMERA_PROPERTY, + + //Filter panel + ID_COMBO_FILTER, + ID_COMBO_STASH, + ID_BTN_STASH_MANAGE, + ID_CHECK_AUTOUPDATE, + ID_FILTER_NAMES, + ID_GRID_FILTER_PROPERTY, + ID_LIST_FILTER, + ID_TREE_FILTERS, + ID_BUTTON_REFRESH, + ID_BTN_EXPAND, + ID_BTN_COLLAPSE, + ID_BTN_FILTERTREE_ERRS, + + //Effects panel + ID_EFFECT_ENABLE, + ID_EFFECT_CROP_ENABLE, + ID_EFFECT_CROP_AXISONE_COMBO, + ID_EFFECT_CROP_PANELONE, + ID_EFFECT_CROP_PANELTWO, + ID_EFFECT_CROP_AXISTWO_COMBO, + ID_EFFECT_CROP_CHECK_COORDS, + ID_EFFECT_CROP_TEXT_DX, + ID_EFFECT_CROP_TEXT_DY, + ID_EFFECT_CROP_TEXT_DZ, + ID_EFFECT_STEREO_ENABLE, + ID_EFFECT_STEREO_COMBO, + ID_EFFECT_STEREO_BASELINE_SLIDER, + ID_EFFECT_STEREO_LENSFLIP, + + //Options panel + ID_CHECK_ALPHA, + ID_CHECK_LIGHTING, + ID_CHECK_CACHING, + ID_CHECK_WEAKRANDOM, + ID_SPIN_CACHEPERCENT, + + //Misc + ID_PROGRESS_ABORT, + ID_STATUS_TIMER, + ID_PROGRESS_TIMER, + ID_UPDATE_TIMER, + ID_AUTOSAVE_TIMER, + + +}; + + +void setWxTreeImages(wxTreeCtrl *t, const map &artFilters) +{ +#if defined(__WIN32) || defined(__WIN64) + const int winTreeIconSize=9; + wxImageList *imList = new wxImageList(winTreeIconSize,winTreeIconSize); +#else + wxImageList *imList = new wxImageList; +#endif + //map to map wxArtIDs to position in the image list + map artMap; + + size_t offset=0; + //Construct an image list for the tree + for(map::const_iterator it=artFilters.begin();it!=artFilters.end();++it) + { + #if defined(__WIN32) || defined(__WIN64) + + imList->Add(wxBitmap(wxBitmap(wxArtProvider::GetBitmap(it->second)). + ConvertToImage().Rescale(winTreeIconSize, winTreeIconSize))); + #else + imList->Add(wxArtProvider::GetBitmap(it->second)); + #endif + + artMap[it->second] = offset; + offset++; + } + + //Assign the image list - note wx will delete the image list here - we don't need to. + t->AssignImageList(imList); + + //Now do a DFS run through the tree, checking to see if any of the elements need + // a particular image + std::stack items; + if (t->GetRootItem().IsOk()) + items.push(t->GetRootItem()); + + while (!items.empty()) + { + wxTreeItemId next = items.top(); + items.pop(); + + //Get the filter pointer + //-- + size_t tItemVal; + wxTreeItemData *tData; + + tData=t->GetItemData(next); + tItemVal=((wxTreeUint *)tData)->value; + //-- + + + map::const_iterator it; + it = artFilters.find(tItemVal); + + if (next != t->GetRootItem() && it!=artFilters.end()) + t->SetItemImage(next,artMap[it->second]); + else + { + t->SetItemImage(next,-1); + } + + wxTreeItemIdValue cookie; + wxTreeItemId nextChild = t->GetFirstChild(next, cookie); + while (nextChild.IsOk()) + { + items.push(nextChild); + nextChild = t->GetNextSibling(nextChild); + } + } + + return; +} + +void clearWxTreeImages(wxTreeCtrl *t) +{ + t->AssignImageList(NULL); +} + +MainWindowFrame::MainWindowFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): + wxFrame(parent, id, title, pos, size, style) +{ + initedOK=false; + programmaticEvent=false; + fullscreenState=0; + verCheckThread=0; + lastMessageType=MESSAGE_NONE; + //Set up the program icon handler + wxArtProvider::Push(new MyArtProvider); + SetIcon(wxArtProvider::GetIcon(wxT("MY_ART_ID_ICON"))); + + //Set up the drag and drop handler + dropTarget = new FileDropTarget(this); + SetDropTarget(dropTarget); + + //Set up the recently used files menu + // Note that this cannot exceed 9. Items show up, but do not trigger events. + // This is bug 12141 in wxWidgets : http://trac.wxwidgets.org/ticket/12141 + ASSERT(configFile.getMaxHistory() <=9); + recentHistory= new wxFileHistory(configFile.getMaxHistory()); + + + programmaticEvent=false; + currentlyUpdatingScene=false; + statusTimer = new wxTimer(this,ID_STATUS_TIMER); + progressTimer = new wxTimer(this,ID_PROGRESS_TIMER); + updateTimer= new wxTimer(this,ID_UPDATE_TIMER); + autoSaveTimer= new wxTimer(this,ID_AUTOSAVE_TIMER); + requireFirstUpdate=true; + + + //Tell the vis controller which window is to remain + //semi-active during calls to wxSafeYield from callback system + visControl.setYieldWindow(this); + //Set up keyboard shortcuts "accelerators" + wxAcceleratorEntry entries[1]; + entries[0].Set(0,WXK_ESCAPE,ID_PROGRESS_ABORT); + wxAcceleratorTable accel(1, entries); + SetAcceleratorTable(accel); + + // begin wxGlade: MainWindowFrame::MainWindowFrame + splitLeftRight = new wxSplitterWindow(this, ID_SPLIT_LEFTRIGHT, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); + panelRight = new wxPanel(splitLeftRight, wxID_ANY); + splitTopBottom = new wxSplitterWindow(panelRight, ID_SPLIT_TOP_BOTTOM, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); + noteDataView = new wxNotebook(splitTopBottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT); + noteDataViewConsole = new wxPanel(noteDataView, wxID_ANY); + noteRaw = new wxPanel(noteDataView, ID_NOTE_RAW); + splitterSpectra = new wxSplitterWindow(noteDataView, ID_SPLIT_SPECTRA, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); + window_2_pane_2 = new wxPanel(splitterSpectra, wxID_ANY); + 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 + //on a broken and working Gl install. booyah. + glPanelOK=panelTop->m_glWidget; + #elif defined(__WIN32) || defined(__WIN64) || defined(__APPLE__) + //I hope this works. I'm not 100% sure -- I can't seem to reliably break my GL under windows. + glPanelOK=panelTop->GetContext(); + #else + //lets just hope it worked. + glPanelOK=true; + #endif +#endif + + if(!glPanelOK) + { + wxErrMsg(this,TRANS("OpenGL Failed"), +TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please check your video drivers.") ); + + cerr << TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please check your video drivers.") << endl; + return; + } + + panelLeft = new wxPanel(splitLeftRight, wxID_ANY); + notebookControl = new wxNotebook(panelLeft, ID_NOTEBOOK_CONTROL, wxDefaultPosition, wxDefaultSize, wxNB_RIGHT); + noteTools = new wxPanel(notebookControl, ID_NOTE_PERFORMANCE, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + notePost = new wxPanel(notebookControl, wxID_ANY); + noteEffects = new wxNotebook(notePost, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT); + noteFxPanelStereo = new wxPanel(noteEffects, wxID_ANY); + noteFxPanelCrop = new wxPanel(noteEffects, wxID_ANY); + noteCamera = new wxScrolledWindow(notebookControl, ID_NOTE_CAMERA, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + noteData = new wxPanel(notebookControl, ID_NOTE_DATA, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + filterSplitter = new wxSplitterWindow(noteData,ID_SPLIT_FILTERPROP , wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER); + filterPropertyPane = new wxPanel(filterSplitter, wxID_ANY); + //topPanelSizer_staticbox = new wxStaticBox(panelTop, -1, wxT("")); + filterTreePane = new wxPanel(filterSplitter, wxID_ANY); + MainFrame_Menu = new wxMenuBar(); + + fileMenu = new wxMenu(); + fileMenu->Append(ID_FILE_OPEN, wxTRANS("&Open...\tCtrl+O"), wxTRANS("Open state file"), wxITEM_NORMAL); + fileMenu->Append(ID_FILE_MERGE, wxTRANS("&Merge...\tCtrl+Shift+O"), wxTRANS("Merge other file"), wxITEM_NORMAL); + + recentFilesMenu=new wxMenu(); + recentHistory->UseMenu(recentFilesMenu); + fileMenu->AppendSubMenu(recentFilesMenu,wxTRANS("&Recent")); + fileSave = fileMenu->Append(ID_FILE_SAVE, wxTRANS("&Save\tCtrl+S"), wxTRANS("Save state to file"), wxITEM_NORMAL); + fileSave->Enable(false); + fileMenu->Append(ID_FILE_SAVEAS, wxTRANS("Save &As...\tCtrl+Shift+S"), wxTRANS("Save current state to new file"), wxITEM_NORMAL); + fileMenu->AppendSeparator(); + fileExport = new wxMenu(); + fileExport->Append(ID_FILE_EXPORT_PLOT, wxTRANS("&Plot...\tCtrl+P"), wxTRANS("Export Current Plot"), wxITEM_NORMAL); + fileExport->Append(ID_FILE_EXPORT_IMAGE, wxTRANS("&Image...\tCtrl+I"), wxTRANS("Export Current 3D View"), wxITEM_NORMAL); + fileExport->Append(ID_FILE_EXPORT_IONS, wxTRANS("Ion&s...\tCtrl+N"), wxTRANS("Export Ion Data"), wxITEM_NORMAL); + fileExport->Append(ID_FILE_EXPORT_RANGE, wxTRANS("Ran&ges...\tCtrl+G"), wxTRANS("Export Range Data"), wxITEM_NORMAL); + fileExport->Append(ID_FILE_EXPORT_FILTER_ANIMATION, wxTRANS("&Animate Filters...\tCtrl+A"), wxTRANS("Export Animated Filter"), wxITEM_NORMAL); + fileExport->Append(ID_FILE_EXPORT_ANIMATION, wxTRANS("Ani&mate Camera...\tCtrl+M"), wxTRANS("Export Animated Camera"), wxITEM_NORMAL); + fileExport->Append(ID_FILE_EXPORT_PACKAGE, wxTRANS("Pac&kage...\tCtrl+K"), wxTRANS("Export analysis package"), wxITEM_NORMAL); + + fileMenu->AppendSubMenu(fileExport,wxTRANS("&Export")); + fileMenu->AppendSeparator(); +#ifdef __APPLE__ + fileMenu->Append(ID_FILE_EXIT, wxTRANS("&Quit\tCtrl+Q"), wxTRANS("Exit Program"), wxITEM_NORMAL); +#else + fileMenu->Append(ID_FILE_EXIT, wxTRANS("E&xit"), wxTRANS("Exit Program"), wxITEM_NORMAL); +#endif + MainFrame_Menu->Append(fileMenu, wxTRANS("&File")); + + wxMenu* wxglade_tmp_menu_1 = new wxMenu(); + wxglade_tmp_menu_1->Append(ID_VIEW_BACKGROUND, + wxTRANS("&Background Colour...\tCtrl+B"),wxTRANS("Change background colour")); + wxglade_tmp_menu_1->AppendSeparator(); //Separator +#ifndef __APPLE__ + checkMenuControlPane= wxglade_tmp_menu_1->Append(ID_VIEW_CONTROL_PANE, + wxTRANS("&Control Pane\tF3"), wxTRANS("Toggle left control pane"), wxITEM_CHECK); +#else + checkMenuControlPane= wxglade_tmp_menu_1->Append(ID_VIEW_CONTROL_PANE, + wxTRANS("&Control Pane\tAlt+C"), wxTRANS("Toggle left control pane"), wxITEM_CHECK); + +#endif + checkMenuControlPane->Check(); +#ifndef __APPLE__ + checkMenuRawDataPane= wxglade_tmp_menu_1->Append(ID_VIEW_RAW_DATA_PANE, + wxTRANS("&Raw Data Pane\tF4"), wxTRANS("Toggle raw data pane (bottom)"), wxITEM_CHECK); +#else + checkMenuRawDataPane= wxglade_tmp_menu_1->Append(ID_VIEW_RAW_DATA_PANE, + wxTRANS("&Raw Data Pane\tAlt+R"), wxTRANS("Toggle raw data pane (bottom)"), wxITEM_CHECK); +#endif + checkMenuRawDataPane->Check(); +#ifndef __APPLE__ + checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, wxTRANS("&Plot List\tF5"),wxTRANS("Toggle plot list"), wxITEM_CHECK); +#else + checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, wxTRANS("&Plot List\tAlt+P"),wxTRANS("Toggle plot list"), wxITEM_CHECK); +#endif + checkMenuSpectraList->Check(); + + wxglade_tmp_menu_1->AppendSeparator(); //Separator + wxMenu* viewPlot= new wxMenu(); + checkViewLegend=viewPlot->Append(ID_VIEW_PLOT_LEGEND,wxTRANS("&Legend\tCtrl+L"),wxTRANS("Toggle Legend display"),wxITEM_CHECK); + checkViewLegend->Check(); + wxglade_tmp_menu_1->AppendSubMenu(viewPlot,wxTRANS("P&lot...")); + checkViewWorldAxis=wxglade_tmp_menu_1->Append(ID_VIEW_WORLDAXIS,wxTRANS("&Axis\tCtrl+Shift+I"),wxTRANS("Toggle World Axis display"),wxITEM_CHECK); + checkViewWorldAxis->Check(); + + wxglade_tmp_menu_1->AppendSeparator(); //Separator +#ifndef __APPLE__ + menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, wxTRANS("&Fullscreen mode\tF11"),wxTRANS("Next fullscreen mode: with toolbars")); +#else + menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, wxTRANS("&Fullscreen mode\tCtrl+Shift+F"),wxTRANS("Next fullscreen mode: with toolbars")); +#endif + + + wxMenu *Edit = new wxMenu(); + editUndoMenuItem = Edit->Append(ID_EDIT_UNDO,wxTRANS("&Undo\tCtrl+Z")); + editUndoMenuItem->Enable(false); + editRedoMenuItem = Edit->Append(ID_EDIT_REDO,wxTRANS("&Redo\tCtrl+Y")); + editRedoMenuItem->Enable(false); + Edit->AppendSeparator(); + Edit->Append(ID_EDIT_PREFERENCES,wxTRANS("&Preferences")); + + MainFrame_Menu->Append(Edit, wxTRANS("&Edit")); + + + MainFrame_Menu->Append(wxglade_tmp_menu_1, wxTRANS("&View")); + wxMenu* Help = new wxMenu(); + Help->Append(ID_HELP_HELP, wxTRANS("&Help...\tCtrl+H"), wxTRANS("Show help files and documentation"), wxITEM_NORMAL); + Help->Append(ID_HELP_CONTACT, wxTRANS("&Contact..."), wxTRANS("Open contact page"), wxITEM_NORMAL); + Help->AppendSeparator(); + Help->Append(ID_HELP_ABOUT, wxTRANS("&About..."), wxTRANS("Information about this program"), wxITEM_NORMAL); + MainFrame_Menu->Append(Help, wxTRANS("&Help")); + SetMenuBar(MainFrame_Menu); + lblSettings = new wxStaticText(noteData, wxID_ANY, wxTRANS("Stashed Filters")); + + + comboStash = new wxComboBox(noteData, ID_COMBO_STASH, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER|SAFE_CB_SORT); + btnStashManage = new wxButton(noteData, ID_BTN_STASH_MANAGE, wxT("..."),wxDefaultPosition,wxSize(28,28)); + filteringLabel = new wxStaticText(noteData, wxID_ANY, wxTRANS("Data Filtering")); + + + //Workaround for wx bug http://trac.wxwidgets.org/ticket/4398 + //Combo box wont sort even when asked under wxGTK<3.0 + // use sortedArrayString, rather than normal arraystring + wxSortedArrayString filterNames; + for(unsigned int ui=0;uicomboFilters_choices offset. + filterMap[TRANS(str)] = ui; + //Add to filter name wxArray + wxString wxStrTrans = wxTRANS(str); + filterNames.Add(wxStrTrans); + } + + + + comboFilters = new wxComboBox(filterTreePane, ID_COMBO_FILTER, wxT(""), wxDefaultPosition, wxDefaultSize, filterNames, wxCB_DROPDOWN|wxCB_READONLY|SAFE_CB_SORT); + + + treeFilters = new wxTreeCtrl(filterTreePane, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_EDIT_LABELS); + lastRefreshLabel = new wxStaticText(filterTreePane, wxID_ANY, wxTRANS("Last Outputs")); + listLastRefresh = new wxListCtrl(filterTreePane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER); + checkAutoUpdate = new wxCheckBox(filterTreePane, ID_CHECK_AUTOUPDATE, wxTRANS("Auto Refresh")); + refreshButton = new wxButton(filterTreePane, wxID_REFRESH, wxEmptyString); + btnFilterTreeExpand= new wxButton(filterTreePane, ID_BTN_EXPAND, wxT("▼"),wxDefaultPosition,wxSize(30,30)); + btnFilterTreeCollapse = new wxButton(filterTreePane, ID_BTN_COLLAPSE, wxT("▲"),wxDefaultPosition,wxSize(30,30)); + btnFilterTreeErrs = new wxBitmapButton(filterTreePane,ID_BTN_FILTERTREE_ERRS,wxArtProvider::GetBitmap(wxART_INFORMATION),wxDefaultPosition,wxSize(40,40)); + + propGridLabel = new wxStaticText(filterPropertyPane, wxID_ANY, wxTRANS("Filter settings")); + gridFilterPropGroup = new wxPropertyGrid(filterPropertyPane, ID_GRID_FILTER_PROPERTY); + labelCameraName = new wxStaticText(noteCamera, wxID_ANY, wxTRANS("Camera Name")); + comboCamera = new wxComboBox(noteCamera, ID_COMBO_CAMERA, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER ); + buttonRemoveCam = new wxButton(noteCamera, wxID_REMOVE, wxEmptyString); + cameraNamePropertySepStaticLine = new wxStaticLine(noteCamera, wxID_ANY); + gridCameraProperties = new wxPropertyGrid(noteCamera, ID_GRID_CAMERA_PROPERTY); +#ifndef APPLE_EFFECTS_WORKAROUND + checkPostProcessing = new wxCheckBox(notePost, ID_EFFECT_ENABLE, wxTRANS("3D Post-processing")); +#endif + checkFxCrop = new wxCheckBox(noteFxPanelCrop, ID_EFFECT_CROP_ENABLE, wxTRANS("Enable Cropping")); + const wxString comboFxCropAxisOne_choices[] = { + wxTRANS("x-y"), + wxTRANS("x-z"), + wxTRANS("y-x"), + wxTRANS("y-z"), + wxTRANS("z-x"), + wxTRANS("z-y") + }; + comboFxCropAxisOne = new wxComboBox(noteFxPanelCrop, ID_EFFECT_CROP_AXISONE_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 6, comboFxCropAxisOne_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY); + panelFxCropOne = new CropPanel(noteFxPanelCrop, ID_EFFECT_CROP_AXISONE_COMBO, + wxDefaultPosition,wxDefaultSize,wxEXPAND); + const wxString comboFxCropAxisTwo_choices[] = { + wxTRANS("x-y"), + wxTRANS("x-z"), + wxTRANS("y-x"), + wxTRANS("y-z"), + wxTRANS("z-x"), + wxTRANS("z-y") + }; + comboFxCropAxisTwo = new wxComboBox(noteFxPanelCrop, ID_EFFECT_CROP_AXISTWO_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 6, comboFxCropAxisTwo_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY); + panelFxCropTwo = new CropPanel(noteFxPanelCrop, ID_EFFECT_CROP_AXISTWO_COMBO,wxDefaultPosition,wxDefaultSize,wxEXPAND); + checkFxCropCameraFrame = new wxCheckBox(noteFxPanelCrop,ID_EFFECT_CROP_CHECK_COORDS,wxTRANS("Use camera coordinates")); + labelFxCropDx = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dX")); + textFxCropDx = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DX, wxEmptyString); + labelFxCropDy = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dY")); + textFxCropDy = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DY, wxEmptyString); + labelFxCropDz = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dZ")); + textFxCropDz = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DZ, wxEmptyString); + checkFxEnableStereo = new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_ENABLE, wxTRANS("Enable Anaglyphic Stereo")); + checkFxStereoLensFlip= new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_LENSFLIP, wxTRANS("Flip Channels")); + lblFxStereoMode = new wxStaticText(noteFxPanelStereo, wxID_ANY, wxTRANS("Anaglyph Mode"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); + const wxString comboFxStereoMode_choices[] = { + wxTRANS("Red-Blue"), + wxTRANS("Red-Green"), + wxTRANS("Red-Cyan"), + wxTRANS("Green-Magenta"), + }; + comboFxStereoMode = new wxComboBox(noteFxPanelStereo, ID_EFFECT_STEREO_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 4, comboFxStereoMode_choices, wxCB_DROPDOWN|wxCB_SIMPLE|wxCB_READONLY); + 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); + 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); + checkWeakRandom = new wxCheckBox(noteTools, ID_CHECK_WEAKRANDOM, wxTRANS("Fast and weak randomisation.")); + checkWeakRandom->SetValue(true); + 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); + spinCachePercent = new wxSpinCtrl(noteTools, ID_SPIN_CACHEPERCENT, wxT("50"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100); + panelView = new wxPanel(panelTop, ID_PANEL_VIEW); + panelSpectra = new MathGLPane(splitterSpectra, wxID_ANY); + plotListLabel = new wxStaticText(window_2_pane_2, wxID_ANY, wxTRANS("Plot List")); + plotList = new wxListBox(window_2_pane_2, ID_LIST_PLOTS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE|wxLB_NEEDED_SB|wxLB_SORT); + gridRawData = new CopyGrid(noteRaw, ID_GRID_RAW_DATA); + btnRawDataSave = new wxButton(noteRaw, wxID_SAVE, wxEmptyString); + btnRawDataClip = new wxButton(noteRaw, wxID_COPY, wxEmptyString); + textConsoleOut = new wxTextCtrl(noteDataViewConsole, + wxID_ANY, wxEmptyString,wxDefaultPosition, + wxDefaultSize,wxTE_MULTILINE|wxTE_READONLY); + MainFrame_statusbar = CreateStatusBar(3, 0); + + set_properties(); + do_layout(); + + //Disable post-processing +#ifndef APPLE_EFFECTS_WORKAROUND + checkPostProcessing->SetValue(false); + noteFxPanelCrop->Enable(false); + noteFxPanelStereo->Enable(false); +#else + //Disable Fx panel stereo controls explicitly + comboFxStereoMode->Enable(false); + sliderFxStereoBaseline->Enable(false); + checkFxStereoLensFlip->Enable(false); + + //Disable Crop controls explicitly + checkFxCropCameraFrame->Enable(false); + comboFxCropAxisOne->Enable(false); + panelFxCropOne->Enable(false); + comboFxCropAxisTwo->Enable(false); + panelFxCropTwo->Enable(false); + textFxCropDx->Enable(false); + textFxCropDy->Enable(false); + textFxCropDz->Enable(false); + labelFxCropDx->Enable(false); + labelFxCropDy->Enable(false); + labelFxCropDz->Enable(false); + +#endif + + //Link the crop panels in the post section appropriately + panelFxCropOne->link(panelFxCropTwo,CROP_LINK_BOTH); + panelFxCropTwo->link(panelFxCropOne,CROP_LINK_BOTH); + + + + //Manually tuned splitter parameters. + filterSplitter->SetMinimumPaneSize(80); + filterSplitter->SetSashGravity(0.8); + splitLeftRight->SetSashGravity(0.15); + splitTopBottom->SetSashGravity(0.85); + splitterSpectra->SetSashGravity(0.82); + + //Last Refresh box + listLastRefresh->InsertColumn(0,wxTRANS("Type")); + listLastRefresh->InsertColumn(1,wxTRANS("Num")); + + //Inform top panel about timer and timeouts + panelTop->setParentStatus(MainFrame_statusbar,statusTimer,STATUS_TIMER_DELAY); + + panelTop->clearCameraUpdates(); + + // end wxGlade + + if(configFile.read() == CONFIG_ERR_BADFILE) + { + textConsoleOut->AppendText(wxTRANS("Warning: Your configuration file appears to be invalid:\n")); + wxString wxS = wxTRANS("\tConfig Load: "); + wxS+= wxStr( configFile.getErrMessage()); + textConsoleOut->AppendText(wxS); + } + else + restoreConfigDefaults(); + + //Try to set the window size to a nice size + SetSize(getNiceWindowSize()); + + + //Attempt to load the auto-save file, if it exists + //----------------- + checkReloadAutosave(); + //----------------- + + + initedOK=true; + + + updateTimer->Start(UPDATE_TIMER_DELAY,wxTIMER_CONTINUOUS); + autoSaveTimer->Start(AUTOSAVE_DELAY*1000,wxTIMER_CONTINUOUS); + +#ifndef DISABLE_ONLINE_UPDATE + wxDateTime datetime = wxDateTime::Today(); + + //Annoy the user, on average, every (% blah) days. + const int CHECK_FREQUENCY=7; + + //Generate a pseudorandom number of fixed sequence + LinearFeedbackShiftReg lfsr; + //Set the period to 2^9 (power of 2 > weeksinyear*daysinweek) + lfsr.setMaskPeriod(9); + lfsr.setState(109); //Use a fixed random seed, to ensure that users will be in-sync for checking + + unsigned int offset = datetime.GetWeekOfYear()*7 + datetime.GetWeekDay(); + while(offset--) + lfsr.clock(); //Discard a whole bunch of entires + + //Everyone will get the same pseudorandom number on the same day. + size_t pseudorandomVal=lfsr.clock(); + ASSERT(pseudorandomVal); //shouldn't be zero, or LFSR is in bad state + + if( configFile.getAllowOnlineVersionCheck() && + !(pseudorandomVal %CHECK_FREQUENCY)) + { + + verCheckThread=new VersionCheckThread(this); + verCheckThread->Create(); + verCheckThread->Run(); + } +#endif +} + +MainWindowFrame::~MainWindowFrame() +{ + + //Delete and stop all the timers. + delete statusTimer; + delete progressTimer; + delete updateTimer; + delete autoSaveTimer; + + //delete the file history pointer + delete recentHistory; + + + //wxwidgets can crash if objects are ->Connect-ed in + // wxWindowBase::DestroyChildren(), so Disconnect before destructing +#if wxCHECK_VERSION(2, 9, 0) + comboCamera->Unbind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboCameraSetFocus, this); + comboStash->Unbind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboStashSetFocus, this); + noteDataView->Unbind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MainWindowFrame::OnNoteDataView, this); +#else + noteDataView->Disconnect(); + comboStash->Disconnect(); + comboCamera->Disconnect(); +#endif +} + + +BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame) + EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_FILTER_PROPERTY,MainWindowFrame::OnFilterGridCellEditorShow) + EVT_GRID_CMD_EDITOR_HIDDEN(ID_GRID_FILTER_PROPERTY,MainWindowFrame::OnFilterGridCellEditorHide) + EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_CAMERA_PROPERTY,MainWindowFrame::OnCameraGridCellEditorShow) + EVT_GRID_CMD_EDITOR_HIDDEN(ID_GRID_CAMERA_PROPERTY,MainWindowFrame::OnCameraGridCellEditorHide) + EVT_TIMER(ID_STATUS_TIMER,MainWindowFrame::OnStatusBarTimer) + EVT_TIMER(ID_PROGRESS_TIMER,MainWindowFrame::OnProgressTimer) + EVT_TIMER(ID_UPDATE_TIMER,MainWindowFrame::OnUpdateTimer) + EVT_TIMER(ID_AUTOSAVE_TIMER,MainWindowFrame::OnAutosaveTimer) + EVT_SPLITTER_UNSPLIT(ID_SPLIT_TOP_BOTTOM, MainWindowFrame::OnRawDataUnsplit) + EVT_SPLITTER_UNSPLIT(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlUnsplit) + EVT_SPLITTER_UNSPLIT(ID_SPLIT_SPECTRA, MainWindowFrame::OnSpectraUnsplit) + EVT_SPLITTER_DCLICK(ID_SPLIT_FILTERPROP, MainWindowFrame::OnFilterPropDoubleClick) + EVT_SPLITTER_DCLICK(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlUnsplit) + EVT_SPLITTER_SASH_POS_CHANGED(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlSplitMove) + EVT_SPLITTER_SASH_POS_CHANGED(ID_SPLIT_TOP_BOTTOM, MainWindowFrame::OnTopBottomSplitMove) + // begin wxGlade: MainWindowFrame::event_table + EVT_MENU(ID_FILE_OPEN, MainWindowFrame::OnFileOpen) + EVT_MENU(ID_FILE_MERGE, MainWindowFrame::OnFileMerge) + EVT_MENU(ID_FILE_SAVE, MainWindowFrame::OnFileSave) + EVT_MENU(ID_FILE_SAVEAS, MainWindowFrame::OnFileSaveAs) + EVT_MENU(ID_FILE_EXPORT_PLOT, MainWindowFrame::OnFileExportPlot) + EVT_MENU(ID_FILE_EXPORT_IMAGE, MainWindowFrame::OnFileExportImage) + EVT_MENU(ID_FILE_EXPORT_IONS, MainWindowFrame::OnFileExportIons) + EVT_MENU(ID_FILE_EXPORT_RANGE, MainWindowFrame::OnFileExportRange) + EVT_MENU(ID_FILE_EXPORT_ANIMATION, MainWindowFrame::OnFileExportVideo) + EVT_MENU(ID_FILE_EXPORT_FILTER_ANIMATION, MainWindowFrame::OnFileExportFilterVideo) + EVT_MENU(ID_FILE_EXPORT_PACKAGE, MainWindowFrame::OnFileExportPackage) + EVT_MENU(ID_FILE_EXIT, MainWindowFrame::OnFileExit) + + EVT_MENU(ID_EDIT_UNDO, MainWindowFrame::OnEditUndo) + EVT_MENU(ID_EDIT_REDO, MainWindowFrame::OnEditRedo) + EVT_MENU(ID_EDIT_PREFERENCES, MainWindowFrame::OnEditPreferences) + + EVT_MENU(ID_VIEW_BACKGROUND, MainWindowFrame::OnViewBackground) + EVT_MENU(ID_VIEW_CONTROL_PANE, MainWindowFrame::OnViewControlPane) + EVT_MENU(ID_VIEW_RAW_DATA_PANE, MainWindowFrame::OnViewRawDataPane) + EVT_MENU(ID_VIEW_SPECTRA, MainWindowFrame::OnViewSpectraList) + EVT_MENU(ID_VIEW_PLOT_LEGEND, MainWindowFrame::OnViewPlotLegend) + EVT_MENU(ID_VIEW_WORLDAXIS, MainWindowFrame::OnViewWorldAxis) + EVT_MENU(ID_VIEW_FULLSCREEN, MainWindowFrame::OnViewFullscreen) + + EVT_MENU(ID_HELP_HELP, MainWindowFrame::OnHelpHelp) + EVT_MENU(ID_HELP_CONTACT, MainWindowFrame::OnHelpContact) + EVT_MENU(ID_HELP_ABOUT, MainWindowFrame::OnHelpAbout) + EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, MainWindowFrame::OnRecentFile) + + EVT_BUTTON(wxID_REFRESH,MainWindowFrame::OnButtonRefresh) + EVT_BUTTON(wxID_COPY,MainWindowFrame::OnButtonGridCopy) + EVT_BUTTON(wxID_SAVE,MainWindowFrame::OnButtonGridSave) + EVT_TEXT(ID_COMBO_STASH, MainWindowFrame::OnComboStashText) + EVT_TEXT_ENTER(ID_COMBO_STASH, MainWindowFrame::OnComboStashEnter) + EVT_COMBOBOX(ID_COMBO_STASH, MainWindowFrame::OnComboStash) + EVT_TREE_END_DRAG(ID_TREE_FILTERS, MainWindowFrame::OnTreeEndDrag) + EVT_TREE_KEY_DOWN(ID_TREE_FILTERS, MainWindowFrame::OnTreeKeyDown) + EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, MainWindowFrame::OnTreeSelectionChange) + EVT_TREE_DELETE_ITEM(ID_TREE_FILTERS, MainWindowFrame::OnTreeDeleteItem) + EVT_TREE_BEGIN_DRAG(ID_TREE_FILTERS, MainWindowFrame::OnTreeBeginDrag) + EVT_BUTTON(ID_BTN_EXPAND, MainWindowFrame::OnBtnExpandTree) + EVT_BUTTON(ID_BTN_COLLAPSE, MainWindowFrame::OnBtnCollapseTree) + EVT_BUTTON(ID_BTN_FILTERTREE_ERRS, MainWindowFrame::OnBtnFilterTreeErrs) + EVT_GRID_CMD_CELL_CHANGE(ID_GRID_FILTER_PROPERTY, MainWindowFrame::OnGridFilterPropertyChange) + EVT_GRID_CMD_CELL_CHANGE(ID_GRID_CAMERA_PROPERTY, MainWindowFrame::OnGridCameraPropertyChange) + EVT_TEXT(ID_COMBO_CAMERA, MainWindowFrame::OnComboCameraText) + EVT_TEXT_ENTER(ID_COMBO_CAMERA, MainWindowFrame::OnComboCameraEnter) + EVT_CHECKBOX(ID_CHECK_ALPHA, MainWindowFrame::OnCheckAlpha) + EVT_CHECKBOX(ID_CHECK_LIGHTING, MainWindowFrame::OnCheckLighting) + EVT_CHECKBOX(ID_CHECK_CACHING, MainWindowFrame::OnCheckCacheEnable) + EVT_CHECKBOX(ID_CHECK_WEAKRANDOM, MainWindowFrame::OnCheckWeakRandom) + EVT_SPINCTRL(ID_SPIN_CACHEPERCENT, MainWindowFrame::OnCacheRamUsageSpin) + EVT_COMBOBOX(ID_COMBO_CAMERA, MainWindowFrame::OnComboCamera) + EVT_COMBOBOX(ID_COMBO_FILTER, MainWindowFrame::OnComboFilter) + EVT_TEXT_ENTER(ID_COMBO_FILTER, MainWindowFrame::OnComboFilterEnter) + EVT_BUTTON(ID_BTN_STASH_MANAGE, MainWindowFrame::OnButtonStashDialog) + EVT_BUTTON(wxID_REMOVE, MainWindowFrame::OnButtonRemoveCam) + EVT_LISTBOX(ID_LIST_PLOTS, MainWindowFrame::OnSpectraListbox) + EVT_CLOSE(MainWindowFrame::OnClose) + EVT_TREE_END_LABEL_EDIT(ID_TREE_FILTERS,MainWindowFrame::OnTreeEndLabelEdit) + EVT_TREE_BEGIN_LABEL_EDIT(ID_TREE_FILTERS,MainWindowFrame::OnTreeBeginLabelEdit) + + //Post-processing stuff + EVT_CHECKBOX(ID_EFFECT_ENABLE, MainWindowFrame::OnCheckPostProcess) + EVT_CHECKBOX(ID_EFFECT_CROP_ENABLE, MainWindowFrame::OnFxCropCheck) + EVT_CHECKBOX(ID_EFFECT_CROP_CHECK_COORDS, MainWindowFrame::OnFxCropCamFrameCheck) + EVT_COMBOBOX(ID_EFFECT_CROP_AXISONE_COMBO, MainWindowFrame::OnFxCropAxisOne) + EVT_COMBOBOX(ID_EFFECT_CROP_AXISTWO_COMBO, MainWindowFrame::OnFxCropAxisTwo) + EVT_CHECKBOX(ID_EFFECT_STEREO_ENABLE, MainWindowFrame::OnFxStereoEnable) + 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_COMMAND(wxID_ANY, RemoteUpdateAvailEvent, MainWindowFrame::OnCheckUpdatesThread) + // end wxGlade +END_EVENT_TABLE(); + + +bool MainWindowFrame::getTreeFilterId(const wxTreeItemId &tId, size_t &filterId) const +{ + if(!tId.IsOk()) + return false; + + //Disallow obtaining the filterID for the root item + if(tId == treeFilters->GetRootItem()) + return false; + + wxTreeItemData *tData=treeFilters->GetItemData(tId); + filterId = ((wxTreeUint *)tData)->value; + + return true; +} + + +void MainWindowFrame::OnFileOpen(wxCommandEvent &event) +{ + //Do not allow any action if a scene update is in progress + 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); + + //Show the file dialog + if( (wxF->ShowModal() == wxID_CANCEL)) + return; + + textConsoleOut->Clear(); + //Get vis controller to update tree control to match internal + // structure. Retain tree selection & visibility if we currently + // have a valid selection + size_t filterId; + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + visControl.setWxTreeFilterViewPersistence(filterId); + + //Load the file + if(!loadFile(wxF->GetPath())) + { + visControl.clearTreeFilterViewPersistence(); + return; + } + + + std::string tmp; + tmp = stlStr(wxF->GetPath()); + configFile.addRecentFile(tmp); + //Update the "recent files" menu + recentHistory->AddFileToHistory(wxF->GetPath()); + + //If we are using the default camera, + //move it to make sure that it is visible + if(visControl.numCams() == 1) + visControl.ensureSceneVisible(3); + + statusMessage(TRANS("Loaded file."),MESSAGE_INFO); + + panelTop->Refresh(); + + wxF->Destroy(); +} + +void MainWindowFrame::OnFileMerge(wxCommandEvent &event) +{ + //Do not allow any action if a scene update is in progress + if(currentlyUpdatingScene || visControl.isRefreshing()) + return; + + //Load a file, either a state file, or a new pos file, or text file + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Select Data or State File..."), wxT(""), + wxT(""),wxTRANS("3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|XML State File (*.xml)|*.xml|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST); + + //Show the file dialog + if( (wxF->ShowModal() == wxID_CANCEL)) + return; + + textConsoleOut->Clear(); + //Load the file + if(!loadFile(wxF->GetPath(),true)) + return; + + statusMessage(TRANS("Merged file."),MESSAGE_INFO); + + panelTop->Refresh(); + + wxF->Destroy(); +} + +void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y) +{ + //We can't alter the filter state if we are refreshing + if(visControl.isRefreshing()) + return ; + + textConsoleOut->Clear(); + wxMouseState wxm = wxGetMouseState(); + + //Try opening the files as range (if ext. agrees) + // or as + bool loaded =false; + for(unsigned int ui=0;uiGetCount()) + { + //Check the extension to see if it should be a range file + wxFileName fileName; + fileName.Assign(files[ui]); + ext=stlStr(fileName.GetExt()); + + for(size_t uj=0;ujGetSelection(),filterId)) + return; + + RangeFile rng; + string s; + s=stlStr(files[ui]); + if(rng.openGuessFormat(s.c_str())) + { + rangeOK=true; + + + //Load rangefile & construct filter + RangeFileFilter *f; + f=(RangeFileFilter *)configFile.getDefaultFilter(FILTER_TYPE_RANGEFILE); + //Copy across the range data + f->setRangeData(rng); + f->setRangeFilename(s.c_str()); + + //Get the parent filter pointer + visControl.addFilter(f,false,filterId); + + } + else + { + //OK, we need to let the user know something went wrong. + //Less annoying than a dialog, but the statusbar is going + //to be useless, as it will be overwritten during the subsequent + //refresh (when we treat this as a pos file). + //FIXME: Something needs to go here... A queue for messages? + } + } + } + //--- + + //If it is a pos file, just handle it by trying to load + if(!rangeOK) + { + + //If command down, load first file using this, + //then merge the rest + if(!loaded) + { + if(loadFile(files[ui],!wxm.CmdDown())) + loaded=true; + } + else + loadFile(files[ui],true); + } + } + + + if(!wxm.CmdDown() && files.Count()) + { +#ifdef __APPLE__ + statusMessage(TRANS("Tip: You can use ⌘ (command) to merge"),MESSAGE_HINT); +#else + statusMessage(TRANS("Tip: You can use ctrl to merge"),MESSAGE_HINT); +#endif + } + + if(files.Count()) + { + //If we are using the default camera, + //move it to make sure that it is visible + if(visControl.numCams() == 1) + visControl.ensureSceneVisible(3); + } +} + +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); + + //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")) + { + std::stringstream ss; + + //Load the file as if it were an XML file + if(!visControl.loadState(dataFile.c_str(),ss,merge)) + { + std::string str; + str=ss.str(); + textConsoleOut->AppendText(wxStr(str)); + //Note that the parent window must be NULL + // if the parent window is not visible (eg autosave startup) + wxWindow *parentWin=NULL; + if(this->IsShown()) + parentWin=this; + + wxErrMsg(parentWin,TRANS("Load error"), + TRANS("Error loading state file.\nSee console for more info.")); + 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()) + { + wxMessageDialog *wxD =new wxMessageDialog(this, + wxTRANS("This state file contains filters that can be unsafe to run\nDo you wish to remove these before continuing?.") + ,wxTRANS("Security warning"),wxYES_NO|wxICON_WARNING|wxYES_DEFAULT ); + + wxD->SetAffirmativeId(wxID_YES); + wxD->SetEscapeId(wxID_NO); + + if(wxD->ShowModal()!= wxID_NO) + visControl.stripHazardousContents(); + + } + + //Update the background colour + if(panelTop->isInited()) + panelTop->updateClearColour(); + + checkViewWorldAxis->Check(visControl.getAxisVisible()); + + //Update the camera dropdown + vector > camData; + visControl.getCamData(camData); + + comboCamera->Clear(); + unsigned int uniqueID; + //Skip the first element, as it is a hidden camera. + for(unsigned int ui=1;uiAppend(wxStr(camData[ui].second), + (wxClientData *)new wxListUint(camData[ui].first)); + //If this is the active cam (1) set the selection and (2) remember + //the ID + if(camData[ui].first == 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) + { + //Use the remembered ID to update the grid. + visControl.updateCamPropertyGrid(gridCameraProperties,uniqueID); + } + else + { + //Reset the camera property fields & combo box + gridCameraProperties->clear(); + comboCamera->SetValue(wxCStr(TRANS(cameraIntroString))); + } + + //reset the stash combo box + comboStash->SetValue(wxCStr(TRANS(stashIntroString))); + + + //Check to see if we have any effects that we need to enable + vector effs; + panelTop->currentScene.getEffects(effs); + if(!effs.empty()) + { + //OK, we have some effects; we will need to update the UI + updateFxUI(effs); + } + + + + currentFile =fileStr; + fileSave->Enable(true); + + + + //Update the stash combo box + comboStash->Clear(); + + std::vector > stashList; + visControl.getStashes(stashList); + for(unsigned int ui=0;uiAppend(wxStr(stashList[ui].first),(wxClientData *)u); + ASSERT(comboStash->GetClientObject(comboStash->GetCount()-1)); + } + + gridFilterPropGroup->clear(); + + } + else + { + + FilterTree fTree; + + Filter *posFilter,*downSampleFilter; + 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") ) + fileMode=DATALOAD_TEXT_FILE; + else + fileMode=DATALOAD_FLOAT_FILE; + + ((DataLoadFilter*)posFilter)->setFileMode(fileMode); + ((DataLoadFilter*)posFilter)->setFilename(dataFile); + + //Remember the filter that we wish to keep visible after altering + // tree control. + // adding filters will invalidate IDs, so this needs to be set now + size_t filterId; + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + visControl.setWxTreeFilterViewPersistence(filterId); + + //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); + doSceneUpdate(); + + return true; +} + +void MainWindowFrame::OnRecentFile(wxCommandEvent &event) +{ + + if(currentlyUpdatingScene || visControl.isRefreshing()) + return; + + wxString f(recentHistory->GetHistoryFile(event.GetId() - wxID_FILE1)); + + if (!f.empty()) + { + textConsoleOut->Clear(); + + //Remember the filter that we wish to keep visible after altering + // tree control. + // adding filters will invalidate IDs, so this needs to be set now + size_t filterId; + 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)) + { + if(loadOK) + statusMessage(TRANS("Loaded file."),MESSAGE_INFO); + panelTop->Refresh(); + } + + if(!loadOK) + { + //Didn't load? We don't want it. + visControl.clearTreeFilterViewPersistence(); + recentHistory->RemoveFileFromHistory(event.GetId()-wxID_FILE1); + configFile.removeRecentFile(stlStr(f)); + } + } +} + +void MainWindowFrame::OnFileSave(wxCommandEvent &event) +{ + if(!currentFile.length()) + return; + + //If the file does not exist, use saveas instead + if(!wxFileExists(currentFile)) + { + OnFileSaveAs(event); + + return; + } + + + std::map dummyMap; + std::string dataFile = stlStr(currentFile); + + //Try to save the viscontrol state + if(!visControl.saveState(dataFile.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); + + } + +} + +void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event) +{ + + if(!panelSpectra->getNumVisible()) + { + wxErrMsg(this,TRANS("Unable to save"), + TRANS("No plot available. Please create a plot before exporting.")); + return; + } + + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save plot..."), wxT(""), + wxT(""),wxTRANS("By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*.svg|PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE); + + if( (wxF->ShowModal() == wxID_CANCEL)) + return; + + std::string dataFile = stlStr(wxF->GetPath()); + + //Split the filename into chunks: path, volume, name and extension + //the format of this is OS dependant, but wxWidgets can deal with this. + std::string strExt; + { + wxFileName fname; + wxString volume,path,name,ext; + bool hasExt; + fname.SplitPath(wxF->GetPath(),&volume, + &path,&name,&ext, &hasExt); + + + strExt=stlStr(ext); + strExt = lowercase(strExt); + wxF->Destroy(); + } + + unsigned int errCode; + + enum + { + EXT_SVG, + EXT_PNG, + EXT_NONE + }; + const char *extensions[] = {"png","svg",""}; + const char *descriptions[] = {"PNG File", "Scalable Vector Graphic",""}; + + size_t extId = EXT_NONE; + for(size_t ui=0;uiShowModal() == wxID_CANCEL) + { + delete wxD; + return; + } + + strExt=extensions[wxD->GetSelection()]; + + //Update the filename extension to use + dataFile+="."; + dataFile+=strExt; + } + + + //Try to save the file (if we recognise the extension) + if(strExt == "svg") + errCode=panelSpectra->saveSVG(dataFile); + else if (strExt == "png") + { + //Show a resolution chooser dialog + ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution")); + + int plotW,plotH; + panelSpectra->GetClientSize(&plotW,&plotH); + d.setRes(plotW,plotH,true); + if(d.ShowModal() == wxID_CANCEL) + return; + + + errCode=panelSpectra->savePNG(dataFile,d.getWidth(),d.getHeight()); + + } + else + { + ASSERT(false); + wxErrMsg(this,TRANS("Unable to save"), + TRANS("Unknown file extension. Please use \"svg\" or \"png\"")); + return; + } + + //Did we save OK? If not, let the user know + if(errCode) + { + wxErrMsg(this,TRANS("Save error"),panelSpectra->getErrString(errCode)); + } + else + { + dataFile=std::string(TRANS("Saved plot: ")) + dataFile; + statusMessage(dataFile.c_str(),MESSAGE_INFO); + } +} + +void MainWindowFrame::OnFileExportImage(wxCommandEvent &event) +{ + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save Image..."), wxT(""), + wxT(""),wxTRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE); + + if( (wxF->ShowModal() == wxID_CANCEL)) + return; + + std::string dataFile = stlStr(wxF->GetPath()); + + //Show a resolution chooser dialog + ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution")); + + //Use the current res as the dialog default + int w,h; + panelTop->GetClientSize(&w,&h); + d.setRes(w,h,true); + + //Show dialog, skip save if user cancels dialog + if(d.ShowModal() == wxID_CANCEL) + return; + + //TODO: Fix this limitation! + if((d.getWidth() < w && d.getHeight() > h) || + (d.getWidth() > w && d.getHeight() < h)) + { + wxErrMsg(this,TRANS("Program limitation"), + TRANS("Limitation on the screenshot dimension; please ensure that both width and height exceed the initial values,\n or that they are both smaller than the initial values.\n If this bothers you, please submit a bug.")); + return; + } + + + bool saveOK=panelTop->saveImage(d.getWidth(),d.getHeight(),dataFile.c_str()); + + if(!saveOK) + { + wxErrMsg(this,TRANS("Save error"), + TRANS("Unable to save. Check output destination can be written to.")); + } + else + { + dataFile=std::string(TRANS("Saved 3D View :")) + dataFile; + statusMessage(dataFile.c_str(),MESSAGE_INFO); + } + +} + + +void MainWindowFrame::OnFileExportVideo(wxCommandEvent &event) +{ + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save Image..."), wxT(""), + wxT(""),wxTRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE); + + if( (wxF->ShowModal() == wxID_CANCEL)) + return; + + + //Show a resolution chooser dialog + ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution")); + + //Use the current res as the dialog default + int w,h; + panelTop->GetClientSize(&w,&h); + d.setRes(w,h,true); + + //Show dialog, skip save if user cancels dialo + if(d.ShowModal() == wxID_CANCEL) + { + wxF->Destroy(); + return; + } + + if((d.getWidth() < w && d.getHeight() > h) || + (d.getWidth() > w && d.getHeight() < h) ) + { + wxErrMsg(this, TRANS("Program limitation"), + TRANS("Limitation on the screenshot dimension; please ensure that both width and height exceed the initial values,\n or that they are smaller than the initial values.\n If this bothers, please submit a bug.")); + return; + } + + + wxFileName fname; + wxString volume,path,name,ext; + bool hasExt; + fname.SplitPath(wxF->GetPath(),&volume, + &path,&name,&ext, &hasExt); + + if(!hasExt) + ext=wxT("png"); + + ///TODO: This is nasty and hackish. We should present a nice, + //well laid out dialog for frame count (show angular increment) + wxTextEntryDialog *teD = new wxTextEntryDialog(this,wxTRANS("Number of frames"),wxTRANS("Frame count"), + wxT("180"),(long int)wxOK|wxCANCEL); + + unsigned int numFrames=0; + std::string strTmp; + do + { + if(teD->ShowModal() == wxID_CANCEL) + { + wxF->Destroy(); + teD->Destroy(); + return; + } + + + strTmp = stlStr(teD->GetValue()); + }while(stream_cast(numFrames,strTmp)); + + teD->Destroy(); + + + bool saveOK=panelTop->saveImageSequence(d.getWidth(),d.getHeight(), + numFrames,path,name,ext); + + + if(!saveOK) + { + wxErrMsg(this,TRANS("Save error"),TRANS("Unable to save. Check output destination can be written to.")); + } + else + { + std::string dataFile = stlStr(wxF->GetPath()); + dataFile=std::string(TRANS("Saved 3D View :")) + dataFile; + statusMessage(dataFile.c_str(),MESSAGE_INFO); + } + wxF->Destroy(); + + + //Force a paint update for the scene, to ensure aspect ratio information is preserved + wxPaintEvent ptEvent; + wxPostEvent(panelTop,event); +} + + +void MainWindowFrame::setLockUI(bool locking=true, + unsigned int lockMode=WINDOW_LOCK_REFRESH) +{ + switch(lockMode) + { + case WINDOW_LOCK_REFRESH: + { + comboFilters->Enable(!locking); + refreshButton->Enable(!locking && visControl.numFilters());; + btnFilterTreeErrs->Enable(!locking); + + + editUndoMenuItem->Enable(!locking && visControl.getUndoSize()); + editRedoMenuItem->Enable(!locking && visControl.getRedoSize()); + fileMenu->Enable(ID_FILE_OPEN,!locking); + fileMenu->Enable(ID_FILE_MERGE,!locking); + + gridFilterPropGroup->Enable(!locking); + comboStash->Enable(!locking); + + //Locking of the tools pane + checkWeakRandom->Enable(!locking); + checkCaching->Enable(!locking); + spinCachePercent->Enable(!locking); + + fileMenu->Enable(ID_FILE_OPEN,!locking); + fileMenu->Enable(ID_FILE_MERGE,!locking); + fileMenu->Enable(ID_FILE_SAVE,!locking); + fileMenu->Enable(ID_FILE_SAVEAS,!locking); + + for(size_t ui=0;uiGetMenuItemCount();ui++) + { + wxMenuItem *m; + m=recentFilesMenu->FindItemByPosition(ui); + m->Enable(!locking); + + } + + fileExport->Enable(ID_FILE_EXPORT_ANIMATION,!locking); + fileExport->Enable(ID_FILE_EXPORT_FILTER_ANIMATION,!locking); + fileExport->Enable(ID_FILE_EXPORT_PACKAGE,!locking); + + panelSpectra->limitInteraction(locking); + break; + } + case WINDOW_LOCK_PROPEDIT: + { + comboFilters->Enable(!locking); + refreshButton->Enable(!locking); + btnFilterTreeErrs->Enable(!locking); + + comboStash->Enable(!locking); + treeFilters->Enable(!locking); + + editUndoMenuItem->Enable(!locking && visControl.getUndoSize()); + editRedoMenuItem->Enable(!locking && visControl.getRedoSize()); + + + fileMenu->Enable(ID_FILE_OPEN,!locking); + fileMenu->Enable(ID_FILE_MERGE,!locking); + fileMenu->Enable(ID_FILE_SAVE,!locking); + fileMenu->Enable(ID_FILE_SAVEAS,!locking); + + for(size_t ui=0;uiGetMenuItemCount();ui++) + { + wxMenuItem *m; + m=recentFilesMenu->FindItemByPosition(ui); + m->Enable(!locking); + + } + + fileExport->Enable(ID_FILE_EXPORT_ANIMATION,!locking); + fileExport->Enable(ID_FILE_EXPORT_FILTER_ANIMATION,!locking); + fileExport->Enable(ID_FILE_EXPORT_PACKAGE,!locking); + + //Locking of the tools pane + checkWeakRandom->Enable(!locking); + checkCaching->Enable(!locking); + spinCachePercent->Enable(!locking); + + //Lock panel spectra, so we cannot alter things like ranges + panelSpectra->limitInteraction(locking); + break; + } + default: + ASSERT(false); + } +} + +void MainWindowFrame::OnFileExportFilterVideo(wxCommandEvent &event) +{ + + //Don't let the user run the animation dialog if they have + // no filters open + if(!visControl.numFilters()) + { + statusMessage(TRANS("Cannot animate with no filters.")); + return; + } + + + ExportAnimationDialog *exportDialog = + new ExportAnimationDialog(this, wxID_ANY, wxEmptyString); + + int w, h; + panelTop->GetClientSize(&w,&h); + FilterTree origTree; + + //Steal the filter tree, and give the pointer to the export dialog + // viscontrol now has an empty tree, so watch out. + visControl.swapFilterTree(origTree); + exportDialog->setTree(origTree); + exportDialog->prepare(); + visControl.swapFilterTree(origTree); + + //Animate dialog + if( (exportDialog->ShowModal() == wxID_CANCEL)) + { + exportDialog->Destroy(); + return; + } + + + setLockUI(); + panelTop->Enable(false); + + size_t numFrames; + numFrames=exportDialog->getNumFrames(); + + + currentlyUpdatingScene=true; + //Modify the tree. + for(size_t ui=0;ui<=numFrames;ui++) + { + bool needsUp; + //steal tree from viscontrol + visControl.swapFilterTree(origTree); + + //Modify the tree, as needed + if(!exportDialog->getModifiedTree(ui,origTree,needsUp)) + { + std::string s; + stream_cast(ui,s); + s = TRANS("Filter property change failed") + s; + wxMessageDialog *wxMesD =new wxMessageDialog(this,wxStr(s), + wxTRANS("Filter change error"),wxOK|wxICON_ERROR); + wxMesD->ShowModal(); + + wxMesD->Destroy(); + setLockUI(false); + panelTop->Enable(true); + return; + } + + //restore tree to viscontrol + visControl.swapFilterTree(origTree); + + if(needsUp || !exportDialog->wantsOnlyChanges()) + { + typedef std::vector STREAMOUT; + std::list outData; + std::list outStreams; + + //First try to refresh the tree + if(visControl.refreshFilterTree(outData)) + { + std::string errMesg,tmpStr; + stream_cast(tmpStr,ui); + errMesg=TRANS("Refresh failed on frame :") + tmpStr; + + wxErrMsg(this,TRANS("Refresh failed"),errMesg); + + currentlyUpdatingScene=false; + setLockUI(false); + panelTop->Enable(true); + return; + } + + + //Now update the scene, if needed + for(list::iterator it=outData.begin(); + it!=outData.end();++it) + outStreams.push_back(it->second); + + + try + { + if(exportDialog->wantsImages()) + { + //update the output streams, but do not release + // the contents. + if(visControl.doUpdateScene(outStreams,false)) + { + pair errMsg; + string tmpStr; + stream_cast(tmpStr,ui); + errMsg.first=TRANS("Scene generation failed"); + errMsg.second = TRANS("Unable to generate scene for frame "); + errMsg.second+=tmpStr; + throw errMsg; + } + else + { + if(!panelTop->saveImage(exportDialog->getImageWidth(), + exportDialog->getImageHeight(), + exportDialog->getFilename(ui,FILENAME_IMAGE).c_str(),true,false)) + { + pair errMsg; + string tmpStr; + stream_cast(tmpStr,ui); + errMsg.first=TRANS("Unable to save"); + errMsg.second = TRANS("Image save failed for frame "); + errMsg.second+=tmpStr; + throw errMsg; + } + } + } + + if(exportDialog->wantsIons()) + { + //merge all the output streams into one + vector mergedStreams; + for(list::iterator it=outStreams.begin(); + it!=outStreams.end();++it) + { + size_t origSize; + origSize=mergedStreams.size(); + mergedStreams.resize( origSize+ it->size()); + std::copy(it->begin(),it->end(),mergedStreams.begin() +origSize); + } + + if(visControl.exportIonStreams(mergedStreams,exportDialog->getFilename(ui,FILENAME_IONS))) + { + pair errMsg; + string tmpStr; + stream_cast(tmpStr,ui); + errMsg.first=TRANS("Ion save failed"); + errMsg.second = TRANS("Unable to save ions for frame "); + errMsg.second+=tmpStr; + throw errMsg; + } + } + + if(exportDialog->wantsPlots()) + { + + size_t plotNumber=0; + //Save each plot by name, where possible + for(list::iterator it=outStreams.begin(); it!=outStreams.end();++it) + { + for(size_t uj=0;ujsize();uj++) + { + //Skip non plot output + if((*it)[uj]->getStreamType() != STREAM_TYPE_PLOT ) + continue; + + //Save the plot output + std::string filename; + const PlotStreamData* p = (const PlotStreamData*)(*it)[uj]; + filename = exportDialog->getFilename(ui,FILENAME_PLOT,plotNumber); + + plotNumber++; + + if(!p->save(filename.c_str())) + { + pair errMsg; + string tmpStr; + stream_cast(tmpStr,ui); + errMsg.first=TRANS("Plot save failed"); + errMsg.second = TRANS("Unable to save plot or frame "); + errMsg.second+=tmpStr; + throw errMsg; + + } + + } + + } + } + + if(exportDialog->wantsRanges()) + { + size_t rangeNum=0; + + //TODO: Integrate enums for rangefiles? + map rangeEnumMap; + rangeEnumMap[RANGE_OAKRIDGE] = RANGE_FORMAT_ORNL; + rangeEnumMap[RANGE_AMETEK_RRNG] = RANGE_FORMAT_RRNG; + rangeEnumMap[RANGE_AMETEK_ENV] = RANGE_FORMAT_ENV; + //Save each range + for(list::iterator it=outStreams.begin(); it!=outStreams.end();++it) + { + for(size_t uj=0;ujsize();uj++) + { + //Skip non plot output + if((*it)[uj]->getStreamType() != STREAM_TYPE_RANGE) + continue; + + //Save the plot output + std::string filename; + const RangeStreamData* p = (const RangeStreamData*)(*it)[uj]; + filename = exportDialog->getFilename(ui,FILENAME_RANGE,rangeNum); + + size_t format; + format=rangeEnumMap.at(exportDialog->getRangeFormat()); + + if(!p->save(filename.c_str(),format)) + { pair errMsg; + string tmpStr; + stream_cast(tmpStr,ui); + errMsg.first=TRANS("Range save failed"); + errMsg.second = TRANS("Unable to save range for frame "); + + throw errMsg; + } + + } + } + } + + + if(exportDialog->wantsVoxels()) + { + size_t offset=0; + for(list::iterator it=outStreams.begin(); it!=outStreams.end();++it) + { + for(size_t uj=0;ujsize();uj++) + { + if( ((*it)[uj])->getStreamType() != STREAM_TYPE_VOXEL) + continue; + + const VoxelStreamData *v; + v=(const VoxelStreamData*)(*it)[uj]; + + std::string filename = exportDialog->getFilename(ui,FILENAME_VOXEL,offset); + if(v->data.writeFile(filename.c_str())) + { + pair errMsg; + string tmpStr; + stream_cast(tmpStr,ui); + errMsg.first=TRANS("Voxel save failed"); + errMsg.second = TRANS("Unable to save voxels for frame "); + errMsg.second+=tmpStr; + throw errMsg; + } + + offset++; + } + } + } + } + catch(std::pair errMsg) + { + //Display an error dialog to the user + wxErrMsg(this,errMsg.first,errMsg.second); + + //clean up data + visControl.safeDeleteFilterList(outData); + exportDialog->Destroy(); + currentlyUpdatingScene=false; + setLockUI(false); + panelTop->Enable(true); + + return; + } + + //Clean up date from this run, releasing stream pointers. + visControl.safeDeleteFilterList(outData); + outStreams.clear(); + } + + } + + currentlyUpdatingScene=false; + exportDialog->Destroy(); + setLockUI(false); + panelTop->Enable(true); + + //Re-run the scene update for the original case, + // this allows for things like the selection bindings to be reinitialised. + doSceneUpdate(); +} + +void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event) +{ + if(!treeFilters->GetCount()) + { + statusMessage(TRANS("No filters means no data to export"),MESSAGE_ERROR); + return; + + } + + //This could be nicer, or reordered + wxTextEntryDialog *wxT = new wxTextEntryDialog(this,wxTRANS("Package name"), + wxTRANS("Package directory name"),wxT(""),wxOK|wxCANCEL); + + wxT->SetValue(wxTRANS("AnalysisPackage")); + + if(wxT->ShowModal() == wxID_CANCEL) + { + wxT->Destroy(); + return; + } + + + //Pop up a directory dialog, to choose the base path for the new folder + wxDirDialog *wxD = new wxDirDialog(this); + + wxMessageDialog *wxMesD =new wxMessageDialog(this,wxTRANS("Package folder already exists, won't overwrite.") + ,wxTRANS("Not available"),wxOK|wxICON_ERROR); + + unsigned int res; + res = wxD->ShowModal(); + while(res != wxID_CANCEL) + { + //Dir cannot exist yet, as we want to make it. + if(wxDirExists(wxD->GetPath() + wxT->GetValue())) + { + wxMesD->ShowModal(); + res=wxD->ShowModal(); + } + else + break; + } + wxMesD->Destroy(); + + //User aborted directory choice. + if(res==wxID_CANCEL) + { + wxD->Destroy(); + wxT->Destroy(); + return; + } + + wxString folder; + folder=wxD->GetPath() + wxFileName::GetPathSeparator() + wxT->GetValue() + + wxFileName::GetPathSeparator(); + //Check to see that the folder actually exists + if(!wxMkdir(folder)) + { + wxMessageDialog *wxMesD =new wxMessageDialog(this,wxTRANS("Package folder creation failed\ncheck writing to this location is possible.") + ,wxTRANS("Folder creation failed"),wxOK|wxICON_ERROR); + + wxMesD->ShowModal(); + wxMesD->Destroy(); + + return; + } + + + //OK, so the folder exists, lets make the XML state file + std::string dataFile = string(stlStr(folder)) + "state.xml"; + + std::map fileMapping; + //Try to save the viscontrol state + if(!visControl.saveState(dataFile.c_str(),fileMapping,true)) + { + wxErrMsg(this,TRANS("Save error"), + TRANS("Unable to save. Check output destination can be written to.")); + } + else + { + //Copy the files in the mapping + wxProgressDialog *wxP = new wxProgressDialog(wxTRANS("Copying"), + wxTRANS("Copying referenced files"),fileMapping.size()); + + wxP->Show(); + for(map::iterator it=fileMapping.begin(); + it!=fileMapping.end();++it) + { + if(!wxCopyFile(wxStr(it->second),folder+wxStr(it->first))) + { + wxErrMsg(this,TRANS("Save error"),TRANS("Error copying file")); + wxP->Destroy(); + return; + } + wxP->Update(); + } + + wxP->Destroy(); + + + wxString s; + s=wxString(wxTRANS("Saved package: ")) + folder; + statusMessage(stlStr(s).c_str(),MESSAGE_INFO); + } + + wxD->Destroy(); +} + +void MainWindowFrame::OnFileExportIons(wxCommandEvent &event) +{ + if(!treeFilters->GetCount()) + { + statusMessage(TRANS("No filters means no data to export"),MESSAGE_ERROR); + return; + + } + + //Steal the filter tree (including caches) from viscontrol + FilterTree f; + visControl.switchoutFilterTree(f); + + //Load up the export dialog + ExportPosDialog *exportDialog=new ExportPosDialog(this,wxID_ANY,wxTRANS("Export")); + exportDialog->initialiseData(f); + + //create a file chooser for later. + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save pos..."), wxT(""), + wxT(""),wxTRANS("POS Data (*.pos)|*.pos|All Files (*)|*"),wxFD_SAVE); + + //If the user cancels the file chooser, + //drop them back into the export dialog. + do + { + //Show, then check for user cancelling export dialog + if(exportDialog->ShowModal() == wxID_CANCEL) + { + //Take control of the filter tree back from the export dialog, + // and return it to visControl + exportDialog->swapFilterTree(f); + visControl.swapFilterTree(f); + exportDialog->Destroy(); + + //Need this to reset the ID values + visControl.updateWxTreeCtrl(treeFilters); + return; + } + + } + while( (wxF->ShowModal() == wxID_CANCEL)); //Check for user abort in file chooser + + + + //Check file already exists (no overwrite without asking) + if(wxFileExists(wxF->GetPath())) + { + wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("File already exists, overwrite?") + ,wxTRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION); + if(wxD->ShowModal() == wxID_CANCEL) + { + wxD->Destroy(); + + //Take control of the filter tree back from the export dialog, + // and return it to visControl + exportDialog->swapFilterTree(f); + visControl.swapFilterTree(f); + + //Need this to reset the ID values + visControl.updateWxTreeCtrl(treeFilters); + exportDialog->Destroy(); + return; + } + } + + std::string dataFile = stlStr(wxF->GetPath()); + + //Retrieve the ion streams that we need to save + vector exportVec; + exportDialog->getExportVec(exportVec); + + + //write the ion streams to disk + if(visControl.exportIonStreams(exportVec,dataFile)) + { + wxErrMsg(this,TRANS("Save error"), + TRANS("Unable to save. Check output destination can be written to.")); + } + else + { + dataFile=std::string(TRANS("Saved ions: ")) + dataFile; + statusMessage(dataFile.c_str(),MESSAGE_INFO); + } + + //Take control of the filter tree back from the export dialog, + // and return it to visControl + exportDialog->swapFilterTree(f); + visControl.swapFilterTree(f); + + //Call ->Destroy to invoke destructor, which will safely delete the + //filterstream pointers it generated + exportDialog->Destroy(); + //Need this to reset the ID values + visControl.updateWxTreeCtrl(treeFilters); +} + +void MainWindowFrame::OnFileExportRange(wxCommandEvent &event) +{ + + if(!treeFilters->GetCount()) + { + statusMessage(TRANS("No filters means no data to export"), + MESSAGE_ERROR); + return; + } + ExportRngDialog *rngDialog = new ExportRngDialog(this,wxID_ANY,wxTRANS("Export Ranges"), + wxDefaultPosition,wxSize(600,400)); + + vector rangeData; + //Retrieve all the range filters in the viscontrol + visControl.getFiltersByType(rangeData,FILTER_TYPE_RANGEFILE); + //pass this to the range dialog + rngDialog->addRangeData(rangeData); + + if(rngDialog->ShowModal() == wxID_CANCEL) + { + rngDialog->Destroy(); + return; + } + + + +} + + +void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event) +{ + //Show a file save dialog + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save state..."), wxT(""), + wxT(""),wxTRANS("XML state file (*.xml)|*.xml|All Files (*)|*"),wxFD_SAVE); + + //Show, then check for user cancelling dialog + if( (wxF->ShowModal() == wxID_CANCEL)) + return; + + std::string dataFile = stlStr(wxF->GetPath()); + + wxFileName fname; + wxString volume,path,name,ext; + bool hasExt; + fname.SplitPath(wxF->GetPath(),&volume, + &path,&name,&ext, &hasExt); + + //Check file already exists (no overwrite without asking) + if(wxFileExists(wxF->GetPath())) + { + wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("File already exists, overwrite?") + ,wxTRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION); + if(wxD->ShowModal() == wxID_CANCEL) + { + wxD->Destroy(); + return; + } + } + if(hasExt) + { + //Force the string to end in ".xml" + std::string strExt; + strExt=stlStr(ext); + strExt = lowercase(strExt); + if(strExt != "xml") + dataFile+=".xml"; + } + else + dataFile+=".xml"; + + + bool oldRelPath=visControl.usingRelPaths(); + //Check to see if we have are using relative paths, + //and if so, do any of our filters + if(visControl.usingRelPaths() && visControl.hasStateOverrides()) + { + wxMessageDialog *wxD =new wxMessageDialog(this,wxTRANS("Files have been referred to using relative paths. Keep relative paths?") + ,wxTRANS("Overwrite?"),wxYES|wxNO|wxICON_QUESTION); + + wxD->SetEscapeId(wxID_NO); + wxD->SetAffirmativeId(wxID_YES); + //Just for the moment, set relative paths to false, if the user asks. + //we will restore this later + if(wxD->ShowModal() == wxID_NO) + { + oldRelPath=true; + visControl.setUseRelPaths(false); + } + + } + + + std::map dummyMap; + //Try to save the viscontrol state + if(!visControl.saveState(dataFile.c_str(),dummyMap)) + { + wxErrMsg(this,TRANS("Save error"), + TRANS("Unable to save. Check output destination can be written to.")); + } + else + { + currentFile = wxF->GetPath(); + fileSave->Enable(true); + + //Update the recent files, and the menu. + configFile.addRecentFile(dataFile); + recentHistory->AddFileToHistory(wxStr(dataFile)); + + dataFile=std::string(TRANS("Saved state: ")) + dataFile; + statusMessage(dataFile.c_str(),MESSAGE_INFO); + } + + //Restore the relative path behaviour + visControl.setUseRelPaths(oldRelPath); +} + + +void MainWindowFrame::OnFileExit(wxCommandEvent &event) +{ + //Close query is handled by OnClose() + Close(); +} + +void MainWindowFrame::OnEditUndo(wxCommandEvent &event) +{ + visControl.popUndoStack(); + + //Get vis controller to update tree control to match internal + // structure. Retain tree selection & visibility if we currently + // have a valid selection + size_t filterId; + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + visControl.setWxTreeFilterViewPersistence(filterId); + + //Update tree control + visControl.updateWxTreeCtrl(treeFilters); + + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + //Update property grid + visControl.updateFilterPropGrid(gridFilterPropGroup,filterId); + } + else + { + gridFilterPropGroup->clear(); + updateLastRefreshBox(); + } + + + + doSceneUpdate(); +} + +void MainWindowFrame::OnEditRedo(wxCommandEvent &event) +{ + visControl.popRedoStack(); + + size_t filterId; + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + visControl.setWxTreeFilterViewPersistence(filterId); + + //Update tree control + visControl.updateWxTreeCtrl(treeFilters); + + //If we can still get the ID, lets use it + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + //Update property grid + visControl.updateFilterPropGrid(gridFilterPropGroup, filterId); + } + else + { + gridFilterPropGroup->clear(); + updateLastRefreshBox(); + } + + + + doSceneUpdate(); +} + +void MainWindowFrame::OnEditPreferences(wxCommandEvent &event) +{ + //Create a new preference dialog + PrefDialog *p = new PrefDialog(this); + + vector filterDefaults; + + //obtain direct copies of the cloned Filter pointers + configFile.getFilterDefaults(filterDefaults); + p->setFilterDefaults(filterDefaults); + + //Get the default mouse parameters + unsigned int mouseZoomRate,mouseMoveRate; + mouseZoomRate=configFile.getMouseZoomRate(); + mouseMoveRate=configFile.getMouseMoveRate(); + + + unsigned int panelMode; + + //Set Panel startup flags + bool rawStartup,controlStartup,plotStartup; + controlStartup=configFile.getPanelEnabled(CONFIG_STARTUPPANEL_CONTROL); + rawStartup=configFile.getPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA); + plotStartup=configFile.getPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST); + + panelMode=configFile.getStartupPanelMode(); + + p->setPanelDefaults(panelMode,controlStartup,rawStartup,plotStartup); + +#ifndef DISABLE_ONLINE_UPDATE + p->setAllowOnlineUpdate(configFile.getAllowOnlineVersionCheck()); +#endif + + + p->setMouseZoomRate(mouseZoomRate); + p->setMouseMoveRate(mouseMoveRate); + + //Initialise panel + p->initialise(); + //show panel + if(p->ShowModal() !=wxID_OK) + { + p->cleanup(); + p->Destroy(); + return; + } + + filterDefaults.clear(); + + //obtain cloned copies of the pointers + p->getFilterDefaults(filterDefaults); + + mouseZoomRate=p->getMouseZoomRate(); + mouseMoveRate=p->getMouseMoveRate(); + + panelTop->setMouseZoomFactor((float)mouseZoomRate/100.0f); + panelTop->setMouseMoveFactor((float)mouseMoveRate/100.0f); + + configFile.setMouseZoomRate(mouseZoomRate); + configFile.setMouseMoveRate(mouseMoveRate); + + //Note that this transfers control of pointer to the config file + configFile.setFilterDefaults(filterDefaults); + + //Retrieve pane settings, and pass to config manager + p->getPanelDefaults(panelMode,controlStartup,rawStartup,plotStartup); + + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,controlStartup,true); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,rawStartup,true); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,plotStartup,true); + + configFile.setStartupPanelMode(panelMode); + +#ifndef DISABLE_ONLINE_UPDATE + configFile.setAllowOnline(p->getAllowOnlineUpdate()); + configFile.setAllowOnlineVersionCheck(p->getAllowOnlineUpdate()); +#endif + p->cleanup(); + p->Destroy(); +} + +void MainWindowFrame::OnViewBackground(wxCommandEvent &event) +{ + + //retrieve the current colour from the openGL panel + float r,g,b; + panelTop->getGlClearColour(r,g,b); + //Show a wxColour choose dialog. + wxColourData d; + d.SetColour(wxColour((unsigned char)(r*255),(unsigned char)(g*255), + (unsigned char)(b*255),(unsigned char)(255))); + wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); + + if( colDg->ShowModal() == wxID_OK) + { + wxColour c; + //Change the colour + c=colDg->GetColourData().GetColour(); + + //Scale colour ranges to 0-> 1 and set in the gl pane + panelTop->setGlClearColour(c.Red()/255.0f,c.Green()/255.0f,c.Blue()/255.0f); + } +} + +void MainWindowFrame::OnViewControlPane(wxCommandEvent &event) +{ + if(event.IsChecked()) + { + if(!splitLeftRight->IsSplit()) + { + const float SPLIT_FACTOR=0.3; + int x,y; + GetClientSize(&x,&y); + splitLeftRight->SplitVertically(panelLeft, + panelRight,(int)(SPLIT_FACTOR*x)); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,true); + + } + } + else + { + if(splitLeftRight->IsSplit()) + { + splitLeftRight->Unsplit(panelLeft); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,false); + } + } +} + + +void MainWindowFrame::OnViewRawDataPane(wxCommandEvent &event) +{ + if(event.IsChecked()) + { + if(!splitTopBottom->IsSplit()) + { + const float SPLIT_FACTOR=0.3; + + int x,y; + GetClientSize(&x,&y); + splitTopBottom->SplitHorizontally(panelTop, + noteDataView,(int)(SPLIT_FACTOR*x)); + + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,true); + } + } + else + { + if(splitTopBottom->IsSplit()) + { + splitTopBottom->Unsplit(); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,false); + } + } +} + +void MainWindowFrame::OnViewSpectraList(wxCommandEvent &event) +{ + if(event.IsChecked()) + { + if(!splitterSpectra->IsSplit()) + { + const float SPLIT_FACTOR=0.6; + + int x,y; + splitterSpectra->GetClientSize(&x,&y); + splitterSpectra->SplitVertically(panelSpectra, + window_2_pane_2,(int)(SPLIT_FACTOR*x)); + + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,true); + } + } + else + { + if(splitterSpectra->IsSplit()) + { + splitterSpectra->Unsplit(); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,false); + } + } +} + +void MainWindowFrame::OnViewPlotLegend(wxCommandEvent &event) +{ + panelSpectra->setLegendVisible(event.IsChecked()); + panelSpectra->Refresh(); +} + +void MainWindowFrame::OnViewWorldAxis(wxCommandEvent &event) +{ + panelTop->currentScene.setWorldAxisVisible(event.IsChecked()); + panelTop->Refresh(); +} + +void MainWindowFrame::OnHelpHelp(wxCommandEvent &event) +{ + //First attempt to locate the local copy of the manual. + string s; + s=locateDataFile("3Depict-manual.pdf"); + + //Also Debian makes us use the lowercase "D", so check there too. + if(!s.size()) + s=locateDataFile("3depict-manual.pdf"); + + + //If we found it, use the default program associated with that data file + bool launchedOK=false; + if( wxFileExists(wxStr(s)) && s.size()) + { + //we found the manual. Launch the default handler. +#if wxCHECK_VERSION(2, 9, 0) + launchedOK=wxLaunchDefaultApplication(wxStr(s)); +#else + //its a bit more convoluted for earlier versions of wx. + //we have to try xdg-open or open for Linux and mac respectively + //for windows, we need to use the wxWidgets GetOpenCommand + + long appPID; + + #if defined(__linux__) + //Try xdg-open first + wxString str; + str= wxT("xdg-open "); + str+=wxStr(s); + appPID=wxExecute(str,wxEXEC_ASYNC); + launchedOK=(appPID!=0); + #elif defined(__APPLE__) + //Try open first + wxString str; + str= wxT("open "); + str+=wxStr(s); + appPID=wxExecute(str,wxEXEC_ASYNC); + launchedOK=(appPID!=0); + #endif + + //No luck still? Try wx's quirky GetOpenCommand + if(!launchedOK) + { + wxString command; + //Sigh. In version < 2.9; wx uses the mime-type + //manager to wrap up the construction + //of wxFileType object (private constructor). + //so we can't just *make* a wxFileType + //we have to derive one from a "mime-type manager". + //the only way to do this is from the file extension + //or by passing the mime-string. + wxMimeTypesManager m; + wxFileType *t; + + t=m.GetFileTypeFromExtension(wxT("pdf")); + command=t->GetOpenCommand(wxStr(s)); + appPID=wxExecute(command,wxEXEC_ASYNC); + launchedOK=(appPID!=0); + } +#endif + } + + //Still no go? Give up and launch a browser. + if(!launchedOK) + { + std::string helpFileLocation("http://threedepict.sourceforge.net/documentation.html"); + wxLaunchDefaultBrowser(wxStr(helpFileLocation),wxBROWSER_NEW_WINDOW); + + statusMessage(TRANS("Manual not found locally. Launching web browser"),MESSAGE_INFO); + } +} + +void MainWindowFrame::OnHelpContact(wxCommandEvent &event) +{ + std::string contactFileLocation("http://threedepict.sourceforge.net/contact.html"); + wxLaunchDefaultBrowser(wxStr(contactFileLocation),wxBROWSER_NEW_WINDOW); + + statusMessage(TRANS("Opening contact page in external web browser"),MESSAGE_INFO); +} + +void MainWindowFrame::OnButtonStashDialog(wxCommandEvent &event) +{ + std::vector > stashVec; + visControl.getStashes(stashVec); + + ASSERT(comboStash->GetCount() == stashVec.size()) + + if(stashVec.empty()) + { + statusMessage(TRANS("No filter stashes to edit."),MESSAGE_ERROR); + return; + } + + StashDialog *s = new StashDialog(this,wxID_ANY,wxTRANS("Filter Stashes")); + s->setVisController(&visControl); + s->ready(); + s->ShowModal(); + + s->Destroy(); + + //Stash list may have changed. Force update + stashVec.clear(); + visControl.getStashes(stashVec); + + comboStash->Clear(); + for(unsigned int ui=0;uiAppend(wxStr(stashVec[ui].first),(wxClientData *)u); + ASSERT(comboStash->GetClientObject(comboStash->GetCount()-1)); + } + + +} + + +void MainWindowFrame::OnHelpAbout(wxCommandEvent &event) +{ + wxAboutDialogInfo info; + info.SetName(wxCStr(PROGRAM_NAME)); + info.SetVersion(wxCStr(PROGRAM_VERSION)); + info.SetDescription(wxTRANS("Quick and dirty analysis for point data.")); + info.SetWebSite(wxT("https://sourceforge.net/apps/phpbb/threedepict/")); + + info.AddDeveloper(wxT("D. Haley")); + info.AddDeveloper(wxT("A. Ceguerra")); + //GNU GPL v3 + info.SetCopyright(_T("Copyright (C) 2013 3Depict team\n This software is licenced under the GPL Version 3.0 or later\n This program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions; Please see the file COPYING in the program directory for details")); + + info.AddArtist(_T("Thanks go to all who have developed the libraries that I use, which make this program possible.\n This includes the wxWidgets team, Alexy Balakin (MathGL), the FTGL and freetype people, the GNU Scientific Library contributors, the tree.h guy (Kasper Peeters) and more.")); + + info.AddArtist(wxString(wxTRANS("Compiled with wx Version: " )) + + wxString(wxSTRINGIZE_T(wxVERSION_STRING))); + + wxArrayString s; + s.Add(_T("Deutsch (German) : Erich (de)")); + info.SetTranslators(s); + + wxAboutBox(info); +} + + +void MainWindowFrame::OnComboStashText(wxCommandEvent &event) +{ + std::string s; + s=stlStr(comboStash->GetValue()); + if(!s.size()) + return; + + int n = comboStash->FindString(comboStash->GetValue()); + + if ( n== wxNOT_FOUND ) + statusMessage(TRANS("Press enter to store new stash"),MESSAGE_HINT); + else + { + //The combo generates an ontext event when a string + //is selected (yeah, I know, weird..) Block this case. + if(comboStash->GetSelection() != n) + statusMessage(TRANS("Press enter to restore stash"),MESSAGE_HINT); + } +} + +void MainWindowFrame::OnComboStashEnter(wxCommandEvent &event) +{ + //The user has pressed enter, in the combo box. If there is an existing stash of this name, + //use it. Otherwise store the current tree control as part of the new stash + std::string userText; + + userText=stlStr(comboStash->GetValue()); + + //Forbid names with no text content + userText=stripWhite(userText); + if(!userText.size()) + return; + + std::vector > stashList; + visControl.getStashes(stashList); + + unsigned int stashPos = (unsigned int ) -1; + for(unsigned int ui=0;uiGetSelection(),filterId)) + { + statusMessage(TRANS("Unable to create stash, selection invalid"),MESSAGE_ERROR); + return; + } + + unsigned int n =visControl.stashFilters(filterId,userText.c_str()); + n=comboStash->Append(wxStr(userText),(wxClientData *)new wxListUint(n)); + ASSERT(comboStash->GetClientObject(n)); + + statusMessage(TRANS("Created new filter tree stash"),MESSAGE_INFO); + + } + else + { + //Found it. Restore the existing stash + //Find the stash associated with this item + int index; + index= comboStash->FindString(comboStash->GetValue()); + ASSERT(index != wxNOT_FOUND); + wxListUint *l; + l =(wxListUint*)comboStash->GetClientObject(index); + //Get the parent filter from the tree selection + size_t filterId; + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + const Filter *parentFilter= + (const Filter *)visControl.getFilterById(filterId); + + visControl.addStashedToFilters(parentFilter,l->value); + + visControl.updateWxTreeCtrl(treeFilters, + parentFilter); + + statusMessage("",MESSAGE_NONE); + if(checkAutoUpdate->GetValue()) + doSceneUpdate(); + + } + + //clear the text in the combo box + comboStash->SetValue(wxT("")); + } + + //clear the text in the combo box + comboStash->SetValue(wxT("")); +} + + +void MainWindowFrame::OnComboStash(wxCommandEvent &event) +{ + //Find the stash associated with this item + wxListUint *l; + l =(wxListUint*)comboStash->GetClientObject(comboStash->GetSelection()); + + size_t filterId; + //Get the parent filter from the tree selection + if(getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + //Get the parent filter pointer + const Filter *parentFilter= + (const Filter *)visControl.getFilterById(filterId); + + visControl.addStashedToFilters(parentFilter,l->value); + + visControl.updateWxTreeCtrl(treeFilters, + parentFilter); + + if(checkAutoUpdate->GetValue()) + doSceneUpdate(); + + + } + + //clear the text in the combo box + comboStash->SetValue(wxT("")); +} + + + +void MainWindowFrame::OnTreeEndDrag(wxTreeEvent &event) +{ + + if(visControl.isRefreshing() ) + { + event.Veto(); + return; + } + + //Should be enforced by ::Allow() in start drag. + ASSERT(filterTreeDragSource && filterTreeDragSource->IsOk()); + //Allow tree to be manhandled, so you can move filters around + wxTreeItemId newParent = event.GetItem(); + + bool needRefresh=false; + size_t sId; + if(!getTreeFilterId(*filterTreeDragSource,sId)) + return; + + wxMouseState wxm = wxGetMouseState(); + + //if we have a parent node to reparent this to + if(newParent.IsOk()) + { + size_t pId; + if(!getTreeFilterId(newParent,pId)) + return; + + //Copy elements from a to b, if a and b are not the same + if(pId != sId) + { + visControl.setWxTreeFilterViewPersistence(sId); + visControl.setWxTreeFilterViewPersistence(pId); + //If command button down (ctrl or clover on mac), + //then copy, otherwise move + if(wxm.CmdDown()) + needRefresh=visControl.copyFilter(sId,pId); + else + needRefresh=visControl.reparentFilter(sId,pId); + } + } + else + { + //Only filters that are a data source are allowed to be in the base. + if( visControl.filterIsPureDataSource(sId)) + { + if(wxm.CmdDown()) + needRefresh=visControl.copyFilter(sId,0); + else + needRefresh=visControl.reparentFilter(sId,0); + } + else + statusMessage(TRANS("Filter type not a data source - can't be at tree base"),MESSAGE_ERROR); + } + + if(needRefresh ) + { + //Refresh the treecontrol + visControl.updateWxTreeCtrl(treeFilters); + + //We have finished the drag + statusMessage("",MESSAGE_NONE); + if(checkAutoUpdate->GetValue()) + doSceneUpdate(); + } + delete filterTreeDragSource; + filterTreeDragSource=0; +} + + +void MainWindowFrame::OnTreeSelectionChange(wxTreeEvent &event) +{ + if(currentlyUpdatingScene) + { + event.Veto(); + return; + } + + size_t filterId; + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + gridFilterPropGroup->clear(); + return; + } + + visControl.updateFilterPropGrid(gridFilterPropGroup, filterId); + + updateLastRefreshBox(); + + + treeFilters->Fit(); + panelTop->Refresh(); + +} + + +void MainWindowFrame::updateLastRefreshBox() +{ + size_t filterId; + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + return; + //retrieve the current active filter + const Filter *f= visControl.getFilterById(filterId); + + //Prevent update flicker by disabling interaction + listLastRefresh->Freeze(); + + listLastRefresh->DeleteAllItems(); + for(unsigned int ui=0;uigetNumOutput(ui); + if(numOut) + { + long index; + stream_cast(n,numOut); + index=listLastRefresh->InsertItem(0,wxCStr(TRANS(STREAM_NAMES[ui]))); + listLastRefresh->SetItem(index,1,wxStr(n)); + } + } + listLastRefresh->Thaw(); +} + +void MainWindowFrame::OnTreeDeleteItem(wxTreeEvent &event) +{ + if(visControl.isRefreshing() ) + { + event.Veto(); + return; + } + //This event is only generated programatically, + //Currently it *purposely* does nothing in the + //not updating case +} + +void MainWindowFrame::OnTreeBeginLabelEdit(wxTreeEvent &event) +{ + if(visControl.isRefreshing() ) + { + event.Veto(); + return; + } +} + +void MainWindowFrame::OnTreeEndLabelEdit(wxTreeEvent &event) +{ + if(event.IsEditCancelled()) + { + treeFilters->Fit(); + return; + } + + + //There is a case where the tree doesn't quite clear + //when there is an editor involved. + if(visControl.numFilters()) + { + std::string s; + s=stlStr(event.GetLabel()); + if(s.size()) + { + size_t filterId; + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + return; + + //If the string has been changed, then we need to update + if(visControl.setFilterString(filterId,s)) + { + //We need to reupdate the scene, in order to re-fill the + //spectra list box + doSceneUpdate(); + } + } + else + { + event.Veto(); // Disallow blank strings. + } + } + + treeFilters->Fit(); +} + +void MainWindowFrame::OnTreeBeginDrag(wxTreeEvent &event) +{ + if(visControl.isRefreshing() ) + { + event.Veto(); + return; + } + + //No dragging if editing, or if no filters + if(treeFilters->GetEditControl() || event.GetItem() == treeFilters->GetRootItem()) + { + event.Veto(); + return; + } + + //Record the drag source + wxTreeItemId t = event.GetItem(); + + if(t.IsOk()) + { + filterTreeDragSource = new wxTreeItemId; + *filterTreeDragSource =t; + event.Allow(); + +#ifdef __APPLE__ + statusMessage(TRANS("Moving - Hold ⌘ (command) to copy"),MESSAGE_HINT); +#else + statusMessage(TRANS("Moving - Hold control to copy"),MESSAGE_HINT); +#endif + } + +} + +void MainWindowFrame::OnBtnExpandTree(wxCommandEvent &event) +{ + treeFilters->ExpandAll(); +} + + +void MainWindowFrame::OnBtnCollapseTree(wxCommandEvent &event) +{ + treeFilters->CollapseAll(); +} + +void MainWindowFrame::OnBtnFilterTreeErrs(wxCommandEvent &event) +{ + + //Grab the error strings + vector res; + visControl.getAnalysisResults(res); + + ASSERT(res.size()); + + vector errStrings; + + for(unsigned int ui=0;uigetUserString() + "\n"; + } + + errStrings.push_back(s); + s.clear(); + + } + res.clear(); + + FilterErrorDialog *f= new FilterErrorDialog(this); + f->SetText(errStrings); + + f->ShowModal(); + + delete f; + +} + +void MainWindowFrame::OnTreeKeyDown(wxTreeEvent &event) +{ + if(currentlyUpdatingScene) + { + event.Veto(); + return; + } + const wxKeyEvent k = event.GetKeyEvent(); + switch(k.GetKeyCode()) + { + case WXK_BACK: + case WXK_DELETE: + { + wxTreeItemId id; + + if(!treeFilters->GetCount()) + return; + + id=treeFilters->GetSelection(); + + if(!id.IsOk() || id == treeFilters->GetRootItem()) + return; + + + //TODO: Refactor out wxTreeItem... code, into separate routine + // that only spits out viscontrol Ids + //Rebuild the tree control, ensuring that the parent is visible, + //if it has a parent (recall root node of wx control is hidden) + + //Get the parent & its data + wxTreeItemId parent = treeFilters->GetItemParent(id); + wxTreeItemData *parentData=treeFilters->GetItemData(parent); + + //Ask viscontrol to ensure that the parent stays persistently + // visible when next rebuilding the tree control + visControl.setWxTreeFilterViewPersistence( + ((wxTreeUint*)parentData)->value); + + //Tree data contains unique identifier for vis control to do matching + wxTreeItemData *tData=treeFilters->GetItemData(id); + //Remove the item from the Tree + visControl.removeFilterSubtree(((wxTreeUint *)tData)->value); + //Clear property grid + gridFilterPropGroup->clear(); + if(parent !=treeFilters->GetRootItem()) + { + ASSERT(parent.IsOk()); // should be - base node should always exist. + + //Ensure that the parent stays visible + visControl.setWxTreeFilterViewPersistence( + ((wxTreeUint*)parentData)->value); + visControl.updateWxTreeCtrl(treeFilters); + + + //OK, so those old Id s are no longer valid, + //as we just rebuilt the tree. We need new ones + //Parent is now selected + parent=treeFilters->GetSelection(); + parentData=treeFilters->GetItemData(parent); + + + //Update the filter property grid with the parent's data + visControl.updateFilterPropGrid(gridFilterPropGroup, + ((wxTreeUint *)parentData)->value); + } + else + { + if(parent.IsOk()) + visControl.updateWxTreeCtrl(treeFilters); + } + + //Force a scene update, independent of if autoUpdate is enabled. + doSceneUpdate(); + + break; + } + default: + event.Skip(); + } +} + +void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event) +{ + + if(programmaticEvent || currentlyUpdatingScene || visControl.isRefreshing()) + { + event.Veto(); + return; + } + + programmaticEvent=true; + //Should only be in the second col + ASSERT(event.GetCol()==1); + + std::string value; + value = stlStr(gridFilterPropGroup->GetCellValue( + event.GetRow(),1)); + + size_t filterId; + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + programmaticEvent=false; + return; + } + + + bool needUpdate; + int row=event.GetRow(); + if(!visControl.setFilterProperty(filterId, + gridFilterPropGroup->getKeyFromRow(row),value,needUpdate)) + { + event.Veto(); + programmaticEvent=false; + return; + } + + + if(needUpdate && checkAutoUpdate->GetValue()) + doSceneUpdate(); + else + clearWxTreeImages(treeFilters); + + visControl.updateFilterPropGrid(gridFilterPropGroup,filterId); + + Layout(); + programmaticEvent=false; +} + +void MainWindowFrame::OnGridCameraPropertyChange(wxGridEvent &event) +{ + + if(programmaticEvent) + { + event.Veto(); + return; + } + + programmaticEvent=true; + //Should only be in the second col + ASSERT(event.GetCol()==1); + + std::string value; + value = stlStr(gridCameraProperties->GetCellValue( + event.GetRow(),1)); + + //Get the camera ID value (long song and dance that it is) + wxListUint *l; + int n = comboCamera->FindString(comboCamera->GetValue()); + if(n == wxNOT_FOUND) + { + programmaticEvent=false; + return; + } + l =(wxListUint*) comboCamera->GetClientObject(n); + + ASSERT(l); + + size_t cameraId; + cameraId = l->value; + + int row=event.GetRow(); + if(visControl.setCamProperties(cameraId,gridCameraProperties->getKeyFromRow(row),value)) + visControl.updateCamPropertyGrid(gridCameraProperties,cameraId); + else + event.Veto(); + + panelTop->Refresh(true); + programmaticEvent=false; + + +} + +void MainWindowFrame::OnCameraGridCellEditorHide(wxGridEvent &e) +{ + //Unlock the camera combo, now that we have finished editing + comboCamera->Enable(true); +} + +void MainWindowFrame::OnComboCameraText(wxCommandEvent &event) +{ + std::string s; + s=stlStr(comboCamera->GetValue()); + if(!s.size()) + return; + + int n = comboCamera->FindString(comboCamera->GetValue()); + + if ( n== wxNOT_FOUND ) + statusMessage(TRANS("Press enter to store new camera"),MESSAGE_HINT); + else + statusMessage(TRANS("Press enter to restore camera"),MESSAGE_HINT); +} + +void MainWindowFrame::OnComboCameraEnter(wxCommandEvent &event) +{ + std::string camName; + camName=stlStr(comboCamera->GetValue()); + + //Disallow cameras with no name + if (!camName.size()) + return; + + //Search for the camera's position in the combo box + int n = comboCamera->FindString(comboCamera->GetValue()); + + //If we have found the camera... + if ( n!= wxNOT_FOUND ) + { + //Select the combo box item + comboCamera->Select(n); + //Set this camera as thew new camera + wxListUint *l; + l =(wxListUint*) comboCamera->GetClientObject(comboCamera->GetSelection()); + visControl.setCam(l->value); + + std::string s = std::string(TRANS("Restored camera: ") ) +stlStr(comboCamera->GetValue()); + + statusMessage(s.c_str(),MESSAGE_INFO); + + //refresh the camera property grid + visControl.updateCamPropertyGrid(gridCameraProperties ,l->value); + + //force redraw in 3D pane + panelTop->Refresh(false); + return ; + } + + //Create a new camera for the scene. + unsigned int u=visControl.addCam(camName); + + //Do not delete as this will be deleted by wx. + comboCamera->Append(comboCamera->GetValue(),(wxClientData *)new wxListUint(u)); + + std::string s = std::string(TRANS("Stored camera: " )) +stlStr(comboCamera->GetValue()); + statusMessage(s.c_str(),MESSAGE_INFO); + + visControl.setCam(u); + visControl.updateCamPropertyGrid(gridCameraProperties,u); + panelTop->Refresh(false); +} + +void MainWindowFrame::OnComboCamera(wxCommandEvent &event) +{ + //Set the active camera + wxListUint *l; + l =(wxListUint*) comboCamera->GetClientObject(comboCamera->GetSelection()); + visControl.setCam(l->value); + + + + visControl.updateCamPropertyGrid(gridCameraProperties,l->value); + + std::string s = std::string(TRANS("Restored camera: ") ) +stlStr(comboCamera->GetValue()); + statusMessage(s.c_str(),MESSAGE_INFO); + + panelTop->Refresh(false); + return ; +} + +void MainWindowFrame::OnComboCameraSetFocus(wxFocusEvent &event) +{ + + if(!haveSetComboCamText) + { + //Even if we have + int pos; + pos = comboCamera->FindString(comboCamera->GetValue()); + + //clear the text if it is the introduction string, or something + // we don't have in the camera + if(pos == wxNOT_FOUND) + comboCamera->SetValue(wxT("")); + + haveSetComboCamText=true; + event.Skip(); + return; + } + + event.Skip(); +} + +void MainWindowFrame::OnComboStashSetFocus(wxFocusEvent &event) +{ + if(!haveSetComboStashText) + { + comboStash->SetValue(wxT("")); + haveSetComboStashText=true; + event.Skip(); + return; + } + event.Skip(); +} + +void MainWindowFrame::OnComboFilterEnter(wxCommandEvent &event) +{ + if(currentlyUpdatingScene || visControl.isRefreshing()) + return; + + OnComboFilter(event); +} + +void MainWindowFrame::OnComboFilter(wxCommandEvent &event) +{ + if(currentlyUpdatingScene) + return; + + size_t filterId; + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + if(treeFilters->GetCount()) + statusMessage(TRANS("Select an item from the filter tree before choosing a new filter")); + else + statusMessage(TRANS("Load data source (file->open) before choosing a new filter")); + return; + } + + //Perform the appropriate action for the particular filter, + //or use the default action for every other filter + bool haveErr=false; + + + //Convert the string into a filter ID based upon our mapping + wxString s; + s=comboFilters->GetString(event.GetSelection()); + size_t filterType; + filterType=filterMap[stlStr(s)]; + + ASSERT(stlStr(s) == TRANS(comboFilters_choices[filterType])); + switch(comboFiltersTypeMapping[filterType]) + { + case FILTER_TYPE_RANGEFILE: + { + ///Prompt user for file + wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Select RNG File..."),wxT(""),wxT(""), + wxTRANS("Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST); + + + if( (wxF->ShowModal() == wxID_CANCEL)) + { + haveErr=true; + break; + } + + //Load rangefile & construct filter + Filter*f=configFile.getDefaultFilter(FILTER_TYPE_RANGEFILE); + std::string dataFile = stlStr(wxF->GetPath()); + RangeFileFilter *r = (RangeFileFilter*)f; + r->setRangeFilename(dataFile); + + + + if(!r->updateRng()) + { + std::string errString; + errString = TRANS("Failed reading range file."); + errString += "\n"; + errString+=r->getRange().getErrString(); + + wxErrMsg(this,TRANS("Error loading file"),errString); + + delete f; + haveErr=true; + break; + } + + visControl.addFilter(f,false,filterId); + + //Rebuild tree control + visControl.updateWxTreeCtrl(treeFilters,f); + break; + } + default: + { + Filter *t; + + ASSERT(filterType < FILTER_TYPE_ENUM_END); + //Generate the appropriate filter + t=configFile.getDefaultFilter(comboFiltersTypeMapping[filterType]); + //Add the filter to viscontrol + visControl.addFilter(t,false,filterId); + + //Rebuild tree control + visControl.updateWxTreeCtrl(treeFilters,t); + } + + } + + if(haveErr) + { + //Clear the combo box + comboFilters->SetValue(wxT("")); + return; + } + + + if(checkAutoUpdate->GetValue()) + doSceneUpdate(); + + comboFilters->SetValue(wxT("")); +} + +bool MainWindowFrame::doSceneUpdate() +{ + //Update scene + ASSERT(!currentlyUpdatingScene); + + //Suspend the update timer, and start the progress timer + updateTimer->Stop(); + progressTimer->Start(PROGRESS_TIMER_DELAY); + currentlyUpdatingScene=true; + haveAborted=false; + + + statusMessage("",MESSAGE_NONE); + noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons.")); + + //Disable tree filters,refresh button and undo + setLockUI(true); + + panelSpectra->Refresh(); + + if(!requireFirstUpdate) + textConsoleOut->Clear(); + + //Set focus on the main frame itself, so that we can catch escape key presses + SetFocus(); + + unsigned int errCode=visControl.refreshFilterTree(); + + progressTimer->Stop(); + updateTimer->Start(UPDATE_TIMER_DELAY); + + //If there was an error, then + //display it + if(errCode) + { + ProgressData p; + p=visControl.getProgress(); + + statusTimer->Start(STATUS_TIMER_DELAY,wxTIMER_ONE_SHOT); + std::string errString; + if(p.curFilter) + errString = p.curFilter->getErrString(errCode); + else + errString = TRANS("Refresh Aborted."); + + statusMessage(errString.c_str(),MESSAGE_ERROR); + } + + //Call the progress one more time, in order to ensure that user sees "100%" + if(!errCode) + updateProgressStatus(); + + currentlyUpdatingScene=false; + visControl.resetProgress(); + + //Restore the UI elements to their interactive state + setLockUI(false); + + panelTop->Refresh(false); + panelSpectra->Refresh(false); + + updateLastRefreshBox(); + + + //Add (or hide) a little "Star" to inform the user there is some info available + if(textConsoleOut->IsEmpty() || noteDataView->GetSelection()==NOTE_CONSOLE_PAGE_OFFSET) + noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons.")); + else + { +#if defined(__WIN32) || defined(__WIN64) + noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("*Cons.")); +#else + noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("§Cons.")); +#endif + } + + + setFilterTreeAnalysisImages(); + + visControl.updateRawGrid(); + + //Return a value dependant upon whether we successfully loaded + //the data or not + return errCode == 0; +} + +void MainWindowFrame::setFilterTreeAnalysisImages() +{ + vector lastErrs; + visControl.getAnalysisResults(lastErrs); + + //Show the error button if required + btnFilterTreeErrs->Show(!lastErrs.empty()); + + if(lastErrs.empty()) + { + treeFilters->AssignImageList(NULL); + return; + } + + //Maps filters to their maximal severity level + map severityMapping; + + for(size_t ui=0;ui::iterator it; + it = severityMapping.find(filt); + + + //If doesn't exist, put one in. If it does exist, keep only max. severity msg + if(it == severityMapping.end()) + severityMapping[filt] = lastErrs[ui].severity; + else + it->second = std::max(lastErrs[ui].severity,severityMapping[filt]); + } + } + + //Map filters into icons + map iconSettings; + { + //Maps particular severity values into icons + map severityIconMapping; + severityIconMapping[ANALYSE_SEVERITY_ERROR] = wxART_ERROR; + severityIconMapping[ANALYSE_SEVERITY_WARNING] =wxART_WARNING; + + for(map::const_iterator it=severityMapping.begin();it!=severityMapping.end(); ++it) + iconSettings[visControl.getIdByFilter(it->first)] = severityIconMapping[it->second]; + } + + //apply the filter->icon mapping + setWxTreeImages(treeFilters,iconSettings); + +#if defined(__WIN32) || defined(__WIN64) + //HACK: Under MSW, force button to correct positioning, by forcing a relayout + treeFilters->GetParent()->Layout(); +#endif +} + +void MainWindowFrame::OnStatusBarTimer(wxTimerEvent &event) +{ + for(unsigned int ui=0; ui<3; ui++) + { + MainFrame_statusbar->SetBackgroundColour(wxNullColour); + MainFrame_statusbar->SetStatusText(wxT(""),ui); + } + + + //Stop the status timer, just in case + statusTimer->Stop(); +} + +void MainWindowFrame::OnProgressTimer(wxTimerEvent &event) +{ + updateProgressStatus(); +} + +void MainWindowFrame::OnAutosaveTimer(wxTimerEvent &event) +{ + //Save a state file to the configuration dir + //with the title "autosave.xml" + // + + wxString filePath = wxStr(configFile.getConfigDir()); + + unsigned int pid; + pid = wxGetProcessId(); + + std::string pidStr; + stream_cast(pidStr,pid); + + filePath+=wxFileName::GetPathSeparator()+ wxCStr(AUTOSAVE_PREFIX) + wxStr(pidStr) + + wxCStr(AUTOSAVE_SUFFIX); + //Save to the autosave file + std::string s; + s= stlStr(filePath); + std::map dummyMap; + if(visControl.saveState(s.c_str(),dummyMap)) + statusMessage(TRANS("Autosave complete."),MESSAGE_INFO); + else + { + //The save failed, but may have left an incomplete file lying around + if(wxFileExists(filePath)) + wxRemoveFile(filePath); + } + + +} + +void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event) +{ + programmaticEvent=true; + + //TODO: HACK AROUND: force tree filter to relayout under wxGTK and Mac + #ifndef __WXMSW__ + //Note: Calling this under windows causes the dropdown box that hovers over the top of this to + //be closed, rendering the dropdown useless. That took ages to work out. + treeFilters->GetParent()->Layout(); + #endif + + if(requireFirstUpdate) + { + //If we are using the default camera, + //move it to make sure that it is visible + if(visControl.numCams() == 1) + visControl.ensureSceneVisible(3); + + panelTop->Refresh(); + requireFirstUpdate=false; + } + + + //see if we need to update the post effects due to user interaction + //with the crop panels + if(panelFxCropOne->hasUpdate() || panelFxCropTwo->hasUpdate()) + { + updatePostEffects(); + panelFxCropOne->clearUpdate(); + panelFxCropOne->clearUpdate(); + } + + //Check viscontrol to see if it needs an update, such as + //when the user interacts with an object when it is not + //in the process of refreshing. + //Don't attempt to update if already updating, or last + //update aborted + bool visUpdates=visControl.hasUpdates(); + bool plotUpdates=panelSpectra->hasUpdates(); + + //I can has updates? + if((visUpdates || plotUpdates) && !visControl.isRefreshing()) + { + //FIXME: This is a massive hack. Use proper feedback to determine + //the correct thing to update, rather than nuking everything + //from orbit + if(plotUpdates) + visControl.clearCacheByType(FILTER_TYPE_RANGEFILE); + + doSceneUpdate(); + } + + //Check the openGL pane to see if the camera property grid needs refreshing + if(panelTop->hasCameraUpdates()) + { + //Use the current combobox value to determine which camera is the + //current camera in the property grid + + + int n = comboCamera->FindString(comboCamera->GetValue()); + + if(n != wxNOT_FOUND) + { + wxListUint *l; + l =(wxListUint*) comboCamera->GetClientObject(n); + + visControl.updateCamPropertyGrid(gridCameraProperties,l->value); + } + + panelTop->clearCameraUpdates(); + } + + if(plotUpdates) + panelSpectra->clearUpdates(); + + if(visUpdates) + { + size_t filterId; + + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + { + programmaticEvent=false; + return; + } + + visControl.updateFilterPropGrid(gridFilterPropGroup,filterId); + + } + + programmaticEvent=false; +} + +void MainWindowFrame::statusMessage(const char *message, unsigned int type) +{ + bool sendMessage=true; + switch(type) + { + case MESSAGE_ERROR: + MainFrame_statusbar->SetBackgroundColour(*wxGREEN); + break; + case MESSAGE_INFO: + MainFrame_statusbar->SetBackgroundColour(*wxCYAN); + break; + case MESSAGE_HINT: + break; + //Pseudo-messages + case MESSAGE_NONE: + // No actions needed, just supply the message + ASSERT( string(message)== string("")); + MainFrame_statusbar->SetBackgroundColour(wxNullColour); + break; + case MESSAGE_NONE_BUT_HINT: + ASSERT( string(message)== string("")); + //we need to clear any messages other than "hintMessage" + sendMessage=(lastMessageType==MESSAGE_HINT); + break; + default: + ASSERT(false); + } + + lastMessageType=type; + + if(sendMessage) + { + MainFrame_statusbar->SetStatusText(wxCStr(message),0); + for(size_t ui=1;ui<3; ui++) + { + MainFrame_statusbar->SetStatusText(wxT(""),ui); + } + } + statusTimer->Start(STATUS_TIMER_DELAY,wxTIMER_ONE_SHOT); +} + +void MainWindowFrame::updateProgressStatus() +{ + + std::string progressString,filterProg; + + + if(!visControl.numFilters()) + return; + + if(haveAborted) + { + progressString=TRANS("Aborted."); + } + else + { + ProgressData p; + p=visControl.getProgress(); + ASSERT(p.totalProgress <= visControl.numFilters()); + + if(p.filterProgress > 100) + p.filterProgress=100; + + //Create a string from the total and percentile progresses + std::string totalProg,totalCount,step,maxStep; + stream_cast(totalProg,p.totalProgress); + stream_cast(filterProg,p.filterProgress); + stream_cast(totalCount,p.totalNumFilters); + + + stream_cast(step,p.step); + stream_cast(maxStep,p.maxStep); + + ASSERT(p.step <=p.maxStep); + + if(p.curFilter) + { + if(!p.maxStep) + progressString = totalProg+TRANS(" of ") + totalCount + + " (" + p.curFilter->typeString() +")"; + else + { + progressString = totalProg+TRANS(" of ") + totalCount + + " (" + p.curFilter->typeString() + ", " + + step + "/" + maxStep + ": " + + p.stepName+")"; + } + } + else + { + //If we have no filter, then we must be done if the totalProgress is + //equal to the total count. + if(totalProg == totalCount) + progressString = TRANS("Updated."); + else + progressString = totalProg + TRANS(" of ") + totalCount; + } + + if( p.filterProgress != 100) + filterProg+=TRANS("\% Done (Esc aborts)"); + else + filterProg+=TRANS("\% Done"); + + } + + MainFrame_statusbar->SetBackgroundColour(wxNullColour); + MainFrame_statusbar->SetStatusText(wxT(""),0); + MainFrame_statusbar->SetStatusText(wxStr(progressString),1); + MainFrame_statusbar->SetStatusText(wxStr(filterProg),2); +} + +void MainWindowFrame::updatePostEffects() +{ + panelTop->currentScene.clearEffects(); + + //Do we need post-processing? +#ifndef APPLE_EFFECTS_WORKAROUND + if(!checkPostProcessing->IsChecked()) + return; +#endif + if( checkFxCrop->IsChecked()) + { + + wxString ws; + string s; + ws=comboFxCropAxisOne->GetValue(); + s =stlStr(ws); + + //String encodes permutation (eg "x-y"). + unsigned int axisPerm[4]; + axisPerm[0] =(unsigned int)(s[0] -'x')*2; + axisPerm[1] = (unsigned int)(s[0] -'x')*2+1; + axisPerm[2] =(unsigned int)(s[2] -'x')*2; + axisPerm[3] = (unsigned int)(s[2] -'x')*2+1; + + //Get the crop data, and generate an effect + BoxCropEffect *b = new BoxCropEffect; + + //Assume, that unless otherwise specified + //the default crop value is zero + float array[6]; + float tmpArray[4]; + for(unsigned int ui=0;ui<6;ui++) + array[ui]=0; + + //Permute the indices for the crop fractions, then assign + panelFxCropOne->getCropValues(tmpArray); + for(unsigned int ui=0;ui<4;ui++) + array[axisPerm[ui]] = tmpArray[ui]; + + + ws=comboFxCropAxisTwo->GetValue(); + s =stlStr(ws); + + axisPerm[0] =(unsigned int)(s[0] -'x')*2; + axisPerm[1] = (unsigned int)(s[0] -'x')*2+1; + axisPerm[2] =(unsigned int)(s[2] -'x')*2; + axisPerm[3] = (unsigned int)(s[2] -'x')*2+1; + panelFxCropTwo->getCropValues(tmpArray); + + for(unsigned int ui=0;ui<4;ui++) + array[axisPerm[ui]] = tmpArray[ui]; + + b->setFractions(array); + + //Should we be using the camera frame? + b->useCamCoords(checkFxCropCameraFrame->IsChecked()); + + //Send the effect to the scene + if(b->willDoSomething()) + { + panelTop->currentScene.addEffect(b); + panelTop->currentScene.setEffects(true); + + + //Update the dx,dy and dz boxes + BoundCube bcTmp; + bcTmp=panelTop->currentScene.getBound(); + + b->getCroppedBounds(bcTmp); + + if(!checkFxCropCameraFrame->IsChecked()) + { + float delta; + delta=bcTmp.getBound(0,1)-bcTmp.getBound(0,0); + stream_cast(s,delta); + textFxCropDx->SetValue(wxStr(s)); + + delta=bcTmp.getBound(1,1)-bcTmp.getBound(1,0); + stream_cast(s,delta); + textFxCropDy->SetValue(wxStr(s)); + + delta=bcTmp.getBound(2,1)-bcTmp.getBound(2,0); + stream_cast(s,delta); + textFxCropDz->SetValue(wxStr(s)); + } + else + { + textFxCropDx->SetValue(wxT("")); + textFxCropDy->SetValue(wxT("")); + textFxCropDz->SetValue(wxT("")); + } + + //well, we dealt with this update. + panelFxCropOne->clearUpdate(); + panelFxCropTwo->clearUpdate(); + } + else + { + textFxCropDx->SetValue(wxT("")); + textFxCropDy->SetValue(wxT("")); + textFxCropDz->SetValue(wxT("")); + delete b; + + //we should let this return true, + //so that an update takes hold + } + + } + + + if(checkFxEnableStereo->IsChecked()) + { + AnaglyphEffect *anaglyph = new AnaglyphEffect; + + unsigned int sel; + sel=comboFxStereoMode->GetSelection(); + anaglyph->setMode(sel); + int v=sliderFxStereoBaseline->GetValue(); + + float shift=((float)v)*BASELINE_SHIFT_FACTOR; + + anaglyph->setBaseShift(shift); + anaglyph->setFlip(checkFxStereoLensFlip->IsChecked()); + panelTop->currentScene.addEffect(anaglyph); + } + + panelTop->Refresh(); +} + +void MainWindowFrame::updateFxUI(const vector &effs) +{ + //Here we pull information out from the effects and then + //update the ui controls accordingly + + Freeze(); + + for(unsigned int ui=0;uigetType()) + { + case EFFECT_BOX_CROP: + { + const BoxCropEffect *e=(const BoxCropEffect*)effs[ui]; + + //Enable the checkbox + checkFxCrop->SetValue(true); + //set the combos back to x-y y-z + comboFxCropAxisOne->SetSelection(0); + comboFxCropAxisTwo->SetSelection(1); + + //Temporarily de-link the panels + panelFxCropOne->link(0,CROP_LINK_NONE); + panelFxCropTwo->link(0,CROP_LINK_NONE); + + //Set the crop values + for(unsigned int ui=0;ui<6;ui++) + { + if(ui<4) + panelFxCropOne->setCropValue(ui, + e->getCropValue(ui)); + else if(ui > 2) + panelFxCropTwo->setCropValue(ui-2, + e->getCropValue(ui)); + } + + //Ensure that the values that went in were valid + panelFxCropOne->makeCropValuesValid(); + panelFxCropTwo->makeCropValuesValid(); + + + //Restore the panel linkage + panelFxCropOne->link(panelFxCropTwo,CROP_LINK_BOTH); + panelFxCropTwo->link(panelFxCropOne,CROP_LINK_BOTH); + + + break; + } + case EFFECT_ANAGLYPH: + { + const AnaglyphEffect *e=(const AnaglyphEffect*)effs[ui]; + //Set the slider from the base-shift value + float shift; + shift=e->getBaseShift(); + sliderFxStereoBaseline->SetValue( + (unsigned int)(shift/BASELINE_SHIFT_FACTOR)); + + + //Set the stereo drop down colour + unsigned int mode; + mode = e->getMode(); + ASSERT(mode < comboFxStereoMode->GetCount()); + + comboFxStereoMode->SetSelection(mode); + //Enable the stereo mode + checkFxEnableStereo->SetValue(true); + break; + } + default: + ASSERT(false); + } + + } + + //Re-enable the effects UI as needed + if(!effs.empty()) + { +#ifndef APPLE_EFFECTS_WORKAROUND + checkPostProcessing->SetValue(true); + noteFxPanelCrop->Enable(); + noteFxPanelStereo->Enable(); +#endif + visControl.setEffects(true); + } + + + Thaw(); +} + +void MainWindowFrame::OnProgressAbort(wxCommandEvent &event) +{ + if(!haveAborted) + visControl.abort(); + haveAborted=true; +} + +void MainWindowFrame::OnViewFullscreen(wxCommandEvent &event) +{ + if(programmaticEvent) + return; + + programmaticEvent=true; + + //Toggle fullscreen, leave the menubar & statusbar visible + +#ifdef __APPLE__ + switch(fullscreenState) + { + case 0: + ShowFullScreen(true,wxFULLSCREEN_NOTOOLBAR); + menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: none")); + break; + case 1: + menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: complete")); + ShowFullScreen(false); + break; + case 2: + menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: none")); + ShowFullScreen(true); + break; + case 3: + menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: with toolbars")); + ShowFullScreen(false); + break; + + default: + ASSERT(false); + + } + fullscreenState++; + fullscreenState%=4; +#elif __LINUX__ + + switch(fullscreenState) + { + case 0: + ShowFullScreen(true,wxFULLSCREEN_NOTOOLBAR); + statusMessage(TRANS("Next Mode: No fullscreen"),MESSAGE_HINT); + break; + case 1: + ShowFullScreen(false); + statusMessage(TRANS("Next Mode: fullscreen w/o toolbar"),MESSAGE_HINT); + break; + case 2: + ShowFullScreen(true); + statusMessage(TRANS("Next Mode: fullscreen with toolbar"),MESSAGE_HINT); + break; + default: + ASSERT(false); + } + fullscreenState++; + fullscreenState%=3; +#else + + switch(fullscreenState) + { + case 0: + ShowFullScreen(true); + break; + case 1: + ShowFullScreen(false); + break; + default: + ASSERT(false); + } + fullscreenState++; + fullscreenState%=2; +#endif + programmaticEvent=false; +} + +void MainWindowFrame::OnButtonRefresh(wxCommandEvent &event) +{ + if(currentlyUpdatingScene || visControl.isRefreshing()) + return; + + //dirty hack to get keyboard state. + wxMouseState wxm = wxGetMouseState(); + if(wxm.ShiftDown()) + { + visControl.purgeFilterCache(); + statusMessage("",MESSAGE_NONE); + } + else + { + if(checkCaching->IsChecked()) + statusMessage(TRANS("Tip: You can shift-click to force full refresh, if required"),MESSAGE_HINT); + } + doSceneUpdate(); +} + +void MainWindowFrame::OnRawDataUnsplit(wxSplitterEvent &event) +{ + checkMenuRawDataPane->Check(false); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA,false); +} + +void MainWindowFrame::OnFilterPropDoubleClick(wxSplitterEvent &event) +{ + //Disallow unsplitting of filter property panel + event.Veto(); +} + +void MainWindowFrame::OnControlSplitMove(wxSplitterEvent &event) +{ + wxGridEvent gridEvent(ID_GRID_RAW_DATA,wxEVT_GRID_LABEL_LEFT_DCLICK,NULL); + wxPostEvent(gridFilterPropGroup,gridEvent); +} + +void MainWindowFrame::OnTopBottomSplitMove(wxSplitterEvent &event) +{ + Refresh(); + panelTop->Refresh(); +} + +void MainWindowFrame::OnControlUnsplit(wxSplitterEvent &event) +{ + //Make sure that the LHS panel is removed, rather than the default (right) + splitLeftRight->Unsplit(panelLeft); + + checkMenuControlPane->Check(false); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_CONTROL,false); +} + +void MainWindowFrame::OnSpectraUnsplit(wxSplitterEvent &event) +{ + checkMenuSpectraList->Check(false); + configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,false); +} + +//This function modifies the properties before showing the cell content editor. +//This is needed only for certain data types (colours, bools) other data types are edited +//using the default editor and modified using ::OnGridFilterPropertyChange +void MainWindowFrame::OnFilterGridCellEditorShow(wxGridEvent &event) +{ + + if(programmaticEvent ) + { + event.Skip(); + return; + } + + + //Find where the event occurred (cell & property) + const GRID_PROPERTY *item; + + unsigned int key; + key=gridFilterPropGroup->getKeyFromRow(event.GetRow()); + + item=gridFilterPropGroup->getProperty(key); + + //Remove any icons that show filter errors or warning state + clearWxTreeImages(treeFilters); + + bool needUpdate=false; + + //If this occurs at run-time, then just abort, otherwise throw error + ASSERT(treeFilters->GetSelection() != treeFilters->GetRootItem()); + if(treeFilters->GetSelection() == treeFilters->GetRootItem()) + return; + + //Get the filter ID value + size_t filterId; + if(!getTreeFilterId(treeFilters->GetSelection(),filterId)) + return; + + switch(item->type) + { + case PROPERTY_TYPE_BOOL: + { + std::string s; + //Toggle the property in the grid + if(item->data == "0") + s= "1"; + else + s="0"; + visControl.setFilterProperty(filterId,key,s,needUpdate); + + event.Veto(); + break; + } + case PROPERTY_TYPE_COLOUR: + { + //Show a wxColour choose dialog. + wxColourData d; + + unsigned char r,g,b,a; + parseColString(item->data,r,g,b,a); + + d.SetColour(wxColour(r,g,b,a)); + wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); + + + if( colDg->ShowModal() == wxID_OK) + { + wxColour c; + //Change the colour + c=colDg->GetColourData().GetColour(); + + std::string s; + genColString(c.Red(),c.Green(),c.Blue(),s); + + //Pass the new colour to the viscontrol system, which updates + //the filters + visControl.setFilterProperty(filterId,key,s,needUpdate); + } + + //Set the filter property + //Disallow direct editing of the grid cell + event.Veto(); + + break; + } + default: + { + //we will handle this after the user has edited the cell contents + //but we must lock controls that can alter the active filter, and thereby changing the + // filter grid in the meantime + setLockUI(true,WINDOW_LOCK_PROPEDIT); + break; + } + } + + if(needUpdate) + { + visControl.updateFilterPropGrid(gridFilterPropGroup,filterId); + + if(checkAutoUpdate->GetValue()) + doSceneUpdate(); + else + clearWxTreeImages(treeFilters); + } +} + +void MainWindowFrame::OnFilterGridCellEditorHide(wxGridEvent &event) +{ + //re-enable the controls that were locked during OnFilterGridCellEditorShow + setLockUI(false,WINDOW_LOCK_PROPEDIT); +} + +void MainWindowFrame::OnCameraGridCellEditorShow(wxGridEvent &event) +{ + if(programmaticEvent) + { + event.Skip(); + return; + } + //Find where the event occurred (cell & property) + const GRID_PROPERTY *item; + + unsigned int key; + key=gridCameraProperties->getKeyFromRow(event.GetRow()); + + item=gridCameraProperties->getProperty(key); + + //Get the camera ID + wxListUint *l; + int n = comboCamera->FindString(comboCamera->GetValue()); + if( n == wxNOT_FOUND) + return; + + l =(wxListUint*) comboCamera->GetClientObject(n); + if(!l) + return; + + size_t camUniqueID=l->value; + + + switch(item->type) + { + case PROPERTY_TYPE_BOOL: + { + std::string s; + //Toggle the property in the grid + if(item->data == "0") + s= "1"; + else + s="0"; + visControl.setCamProperties(camUniqueID,key,s); + + //For some reason this does not redraw neatly. Force a redraw + visControl.updateCamPropertyGrid(gridCameraProperties,camUniqueID); + + event.Veto(); + break; + } + case PROPERTY_TYPE_COLOUR: + { + //Show a wxColour choose dialog. + wxColourData d; + + unsigned char r,g,b,a; + parseColString(item->data,r,g,b,a); + + d.SetColour(wxColour(r,g,b,a)); + wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d); + + + if( colDg->ShowModal() == wxID_OK) + { + wxColour c; + //Change the colour + c=colDg->GetColourData().GetColour(); + + std::string s; + genColString(c.Red(),c.Green(),c.Blue(),s); + + //Pass the new colour to the viscontrol system, which updates + //the filters + visControl.setCamProperties(camUniqueID,key,s); + } + + //Set the filter property + //Disallow direct editing of the grid cell + event.Veto(); + + break; + } + default: + //we will handle this after the user has edited the cell contents + //Lock the camera combo, so the user can't alter the camera data while we are using the editor + comboCamera->Enable(false); + break; + } + + panelTop->Refresh(false); + +} + +void MainWindowFrame::OnButtonGridCopy(wxCommandEvent &event) +{ + gridRawData->copyData(); +} + +void MainWindowFrame::OnButtonGridSave(wxCommandEvent &event) +{ + if(!gridRawData->GetRows()||!gridRawData->GetCols()) + { + statusMessage(TRANS("No data to save"),MESSAGE_ERROR); + return; + } + gridRawData->saveData(); +} + +void MainWindowFrame::OnCheckAlpha(wxCommandEvent &event) +{ + panelTop->currentScene.setAlpha(event.IsChecked()); + + panelTop->Refresh(); +} + +void MainWindowFrame::OnCheckLighting(wxCommandEvent &event) +{ + panelTop->currentScene.setLighting(event.IsChecked()); + + panelTop->Refresh(); +} + +void MainWindowFrame::OnCheckCacheEnable(wxCommandEvent &event) +{ + if(event.IsChecked()) + visControl.setCachePercent((unsigned int)spinCachePercent->GetValue()); + else + { + visControl.setCachePercent(0); + visControl.purgeFilterCache(); + + doSceneUpdate(); + } +} + +void MainWindowFrame::OnCheckWeakRandom(wxCommandEvent &event) +{ + visControl.setStrongRandom(!event.IsChecked()); + + doSceneUpdate(); +} + +void MainWindowFrame::OnCacheRamUsageSpin(wxSpinEvent &event) +{ + ASSERT(event.GetPosition() >= 0 &&event.GetPosition()<=100); + + visControl.setCachePercent(event.GetPosition()); + +} +void MainWindowFrame::OnButtonRemoveCam(wxCommandEvent &event) +{ + + std::string camName; + + + camName=stlStr(comboCamera->GetValue()); + + if (!camName.size()) + return; + + int n = comboCamera->FindString(comboCamera->GetValue()); + + if ( n!= wxNOT_FOUND ) + { + wxListUint *l; + l =(wxListUint*) comboCamera->GetClientObject(n); + visControl.removeCam(l->value); + comboCamera->Delete(n); + + programmaticEvent=true; + comboCamera->SetValue(wxT("")); + gridCameraProperties->clear(); + programmaticEvent=false; + } +} + +void MainWindowFrame::OnSpectraListbox(wxCommandEvent &event) +{ + //This function gets called programatically by + //doSceneUpdate. Prevent interaction. + if(visControl.isRefreshing()) + return; + //Get the currently selected item + //Spin through the selected items + for(unsigned int ui=0;uiGetCount(); ui++) + { + wxListUint *l; + unsigned int plotID; + + //Retrieve the uniqueID + l=(wxListUint*)plotList->GetClientObject(ui); + plotID = l->value; + + panelSpectra->setPlotVisible(plotID,plotList->IsSelected(ui)); + + } + + panelSpectra->Refresh(); + //The raw grid contents may change due to the list selection + //change. Update the grid + visControl.updateRawGrid(); +} + +void MainWindowFrame::OnClose(wxCloseEvent &event) +{ + + if(visControl.isRefreshing()) + { + if(!haveAborted) + { + visControl.abort(); + haveAborted=true; + + statusMessage(TRANS("Aborting..."),MESSAGE_INFO); + return; + } + else + { + wxMessageDialog *wxD =new wxMessageDialog(this, + wxTRANS("Waiting for refresh to abort. Exiting could lead to the program backgrounding. Exit anyway? "), + wxTRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR); + + if(wxD->ShowModal() != wxID_OK) + { + event.Veto(); + wxD->Destroy(); + return; + } + wxD->Destroy(); + } + } + else + { + //If the program is being forced by the OS to shut down, don't ask the user for abort, + // as we can't abort it anyway. + if(event.CanVeto()) + { + if(visControl.numFilters() || visControl.numCams() > 1) + { + //Prompt for close + wxMessageDialog *wxD =new wxMessageDialog(this, + wxTRANS("Are you sure you wish to exit 3Depict?"),\ + wxTRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR); + if(wxD->ShowModal() != wxID_OK) + { + event.Veto(); + wxD->Destroy(); + return; + } + wxD->Destroy(); + + } + } + } + + + + //Remove the autosave file if it exists, as we are shutting down neatly. + + //Get self PID + std::string pidStr; + unsigned int pid; + pid=wxGetProcessId(); + stream_cast(pidStr,pid); + + wxString filePath =wxStr(configFile.getConfigDir()); + filePath+=wxCStr("/") + wxCStr(AUTOSAVE_PREFIX) + wxStr(pidStr)+ wxCStr(AUTOSAVE_SUFFIX); + + if(wxFileExists(filePath)) + wxRemoveFile(filePath); + + //Remember current window size for next time + wxSize winSize; + winSize=GetSize(); + configFile.setInitialAppSize(winSize.GetWidth(),winSize.GetHeight()); + + //Remember the sash positions for next time, as fractional values fo + // the window size, but only if split (as otherwise frac could exceed 1) + float frac; + if(splitLeftRight->IsSplit()) + { + frac =(float) splitLeftRight->GetSashPosition()/winSize.GetWidth(); + configFile.setLeftRightSashPos(frac); + } + if(splitTopBottom->IsSplit()) + { + frac = (float) splitTopBottom->GetSashPosition()/winSize.GetHeight(); + configFile.setTopBottomSashPos(frac); + } + if(filterSplitter->IsSplit()) + { + frac= (float)filterSplitter->GetSashPosition()/winSize.GetHeight(); + configFile.setFilterSashPos(frac); + } + if(splitterSpectra->IsSplit()) + { + frac = (float)splitterSpectra->GetSashPosition()/winSize.GetWidth(); + configFile.setPlotListSashPos(frac); + } + + winSize=noteDataView->GetSize(); + + //Try to save the configuration + configFile.write(); + + if(verCheckThread) + { + if(!verCheckThread->isComplete()) + { + //Kill it. + verCheckThread->Kill(); + } + else + verCheckThread->Wait(); + } + + + //Terminate the program + Destroy(); +} + + + +void MainWindowFrame::OnCheckPostProcess(wxCommandEvent &event) +{ +#ifdef APPLE_EFFECTS_WORKAROUND + //FIXME: I have disabled this under apple + ASSERT(false); +#endif + //Disable the entire UI panel + noteFxPanelCrop->Enable(event.IsChecked()); + noteFxPanelStereo->Enable(event.IsChecked()); + visControl.setEffects(event.IsChecked()); + updatePostEffects(); + + panelTop->Refresh(); +} + + +void MainWindowFrame::OnFxCropCheck(wxCommandEvent &event) +{ + //Disable/enable the other UI controls on the crop effects page + //Include the text labels to give them that "greyed-out" look + checkFxCropCameraFrame->Enable(event.IsChecked()); + comboFxCropAxisOne->Enable(event.IsChecked()); + panelFxCropOne->Enable(event.IsChecked()); + comboFxCropAxisTwo->Enable(event.IsChecked()); + panelFxCropTwo->Enable(event.IsChecked()); + textFxCropDx->Enable(event.IsChecked()); + textFxCropDy->Enable(event.IsChecked()); + textFxCropDz->Enable(event.IsChecked()); + labelFxCropDx->Enable(event.IsChecked()); + labelFxCropDy->Enable(event.IsChecked()); + labelFxCropDz->Enable(event.IsChecked()); + + updatePostEffects(); +} + + +void MainWindowFrame::OnFxCropCamFrameCheck(wxCommandEvent &event) +{ + updatePostEffects(); +} + + + +void MainWindowFrame::OnFxCropAxisOne(wxCommandEvent &event) +{ + linkCropWidgets(); + updatePostEffects(); +} + +void MainWindowFrame::OnFxCropAxisTwo(wxCommandEvent &event) +{ + linkCropWidgets(); + updatePostEffects(); +} + +void MainWindowFrame::linkCropWidgets() +{ + //Adjust the link mode as needed + //Lets cheat a little and parse the combo box contents + + unsigned int linkMode; + + string first[2],second[2]; + + wxString s; + string tmp; + + s=comboFxCropAxisOne->GetValue(); + tmp=stlStr(s); + first[0]=tmp[0]; + second[0]=tmp[2]; + + s=comboFxCropAxisTwo->GetValue(); + tmp=stlStr(s); + first[1]=tmp[0]; + second[1]=tmp[2]; + + + linkMode=0; + //First and second axis match? + if(first[0] == first[1] && second[0] == second[1]) + { + linkMode=CROP_LINK_BOTH; + } + else if(first[0] == second[1] && second[0] == first[1]) + linkMode=CROP_LINK_BOTH_FLIP; + else if(first[0] == first[1]) + linkMode=CROP_LINK_LR; + else if(second[0] == second[1]) + linkMode=CROP_LINK_TB; + else if(second[0] == first[1]) + { + panelFxCropOne->link(panelFxCropTwo,CROP_LINK_TB_FLIP); + panelFxCropTwo->link(panelFxCropOne,CROP_LINK_LR_FLIP); + } + else if(second[1]== first[0]) + { + panelFxCropOne->link(panelFxCropTwo,CROP_LINK_LR_FLIP); + panelFxCropTwo->link(panelFxCropOne,CROP_LINK_TB_FLIP); + } + else + { + //Pigeonhole principle says we can't get here. + ASSERT(false); + } + + + if(linkMode) + { + panelFxCropOne->link(panelFxCropTwo,linkMode); + panelFxCropTwo->link(panelFxCropOne,linkMode); + } + +} + + + + +void MainWindowFrame::OnFxStereoEnable(wxCommandEvent &event) +{ + comboFxStereoMode->Enable(event.IsChecked()); + sliderFxStereoBaseline->Enable(event.IsChecked()); + checkFxStereoLensFlip->Enable(event.IsChecked()); + + updatePostEffects(); +} + +void MainWindowFrame::OnFxStereoLensFlip(wxCommandEvent &event) +{ + updatePostEffects(); +} + + +void MainWindowFrame::OnFxStereoCombo(wxCommandEvent &event) +{ + updatePostEffects(); +} + + +void MainWindowFrame::OnFxStereoBaseline(wxScrollEvent &event) +{ + updatePostEffects(); +} + +void MainWindowFrame::restoreConfigDefaults() +{ + std::vector strVec; + + //Set the files that are listed in the recent files + //menu + configFile.getRecentFiles(strVec); + + for(unsigned int ui=0; uiAddFileToHistory(wxStr(strVec[ui])); + + //Set the mouse zoom speeds + float zoomRate,moveRate; + zoomRate=configFile.getMouseZoomRate(); + moveRate=configFile.getMouseMoveRate(); + + panelTop->setMouseZoomFactor((float)zoomRate/100.0f); + panelTop->setMouseMoveFactor((float)moveRate/100.0f); +} + +void MainWindowFrame::restoreConfigPanelDefaults() +{ + + //Set the panel defaults (hidden/shown) + // and their sizes + wxSize winSize; + winSize=getNiceWindowSize(); + float val,oldGravity; + if(!configFile.getPanelEnabled(CONFIG_STARTUPPANEL_CONTROL)) + { + splitLeftRight->Unsplit(panelLeft); + checkMenuControlPane->Check(false); + + val=configFile.getLeftRightSashPos(); + if(val > std::numeric_limits::epsilon()) + { + oldGravity=splitLeftRight->GetSashGravity(); + splitLeftRight->SetSashGravity(1.0); + splitLeftRight->SetSashPosition((int)(val*(float)winSize.GetWidth())); + splitLeftRight->SetSashGravity(oldGravity); + + } + } + + if(!configFile.getPanelEnabled(CONFIG_STARTUPPANEL_RAWDATA)) + { + splitTopBottom->Unsplit(); + checkMenuRawDataPane->Check(false); + } + else + { + val=configFile.getTopBottomSashPos(); + if(val > std::numeric_limits::epsilon()) + { + oldGravity=splitTopBottom->GetSashGravity(); + splitTopBottom->SetSashGravity(1.0); + splitTopBottom->SetSashPosition((int)(val*(float)winSize.GetHeight())); + splitTopBottom->SetSashGravity(oldGravity); + } + } + + //Set default or nice position for plotlist panel + if(!configFile.getPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST)) + { + splitterSpectra->Unsplit(); + checkMenuSpectraList->Check(false); + } + else + { + + winSize=noteDataView->GetSize(); + val=configFile.getPlotListSashPos(); + if(val > std::numeric_limits::epsilon()) + { + oldGravity=splitterSpectra->GetSashGravity(); + splitterSpectra->SetSashGravity(1.0); + splitterSpectra->SetSashPosition((int)(val*(float)winSize.GetWidth())); + splitterSpectra->SetSashGravity(oldGravity); + } + + } + + //set nice position for filter splitter (in left side of main window) + if(configFile.configLoadedOK()) + { + val=configFile.getFilterSashPos(); + winSize=filterPropertyPane->GetSize(); + if(val > std::numeric_limits::epsilon()) + { + oldGravity=filterSplitter->GetSashGravity(); + filterSplitter->SetSashGravity(1.0); + filterSplitter->SetSashPosition((int)(val*(float)winSize.GetHeight())); + filterSplitter->SetSashGravity(oldGravity); + } + } + +} + +// wxGlade: add MainWindowFrame event handlers + +void MainWindowFrame::SetCommandLineFiles(wxArrayString &files) +{ + textConsoleOut->Clear(); + //Load them up as data. + for(unsigned int ui=0;uiSetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons.")); + + //Keep processing + evt.Skip(); +} + +void MainWindowFrame::OnCheckUpdatesThread(wxCommandEvent &evt) +{ + //Check to see if we have a new version or not, and + //what that version number is + + ASSERT(verCheckThread->isComplete()); + + //Check to see if we got the version number OK. + // this might have failed, e.g. if the user has no net connection, + // or the remote RSS is not parseable + if(verCheckThread->isRetrieveOK()) + { + string remoteMax=verCheckThread->getVerStr().c_str(); + + vector maxVers; + maxVers.push_back(remoteMax); + maxVers.push_back(PROGRAM_VERSION); + + string s; + if(getMaxVerStr(maxVers) !=PROGRAM_VERSION) + { + //Use status bar message to notify user about update + s = string(TRANS("Update Notice: New version ")) + remoteMax + TRANS(" found online."); + } + else + { + s=string(TRANS("Online Check: " ))+string(PROGRAM_NAME) + TRANS(" is up-to-date."); + } + statusMessage(s.c_str(),MESSAGE_INFO); + } + + //Wait for, then delete the other thread, as we are done with it + verCheckThread->Wait(); + verCheckThread=0; + +} + +void MainWindowFrame::checkReloadAutosave() +{ + wxString configDirPath =wxStr(configFile.getConfigDir()); + configDirPath+=wxCStr("/") ; + + if(!wxDirExists(configDirPath)) + return; + + //obtain a list of autosave xml files + //-- + wxArrayString *dirListing= new wxArrayString; + std::string s; + s=std::string(AUTOSAVE_PREFIX) + + std::string("*") + std::string(AUTOSAVE_SUFFIX); + wxString fileMask = wxStr(s); + + wxDir::GetAllFiles(configDirPath,dirListing,fileMask,wxDIR_FILES); + + if(!dirListing->GetCount()) + { + delete dirListing; + return; + } + //-- + + + unsigned int prefixLen; + prefixLen = stlStr(configDirPath).size() + strlen(AUTOSAVE_PREFIX) + 1; + + //For convenience, Construct a mapping to the PIDs from the string + //-- + map autosaveNamePIDMap; + for(unsigned int ui=0;uiGetCount(); ui++) + { + std::string tmp; + tmp = stlStr(dirListing->Item(ui)); + //File name should match specified glob. + ASSERT(tmp.size() >=(strlen(AUTOSAVE_PREFIX) + strlen(AUTOSAVE_SUFFIX))); + + //Strip the non-glob bit out of the string + tmp = tmp.substr(prefixLen-1,tmp.size()-(strlen(AUTOSAVE_SUFFIX) + prefixLen-1)); + + unsigned int pid; + if(stream_cast(pid,tmp)) + continue; + autosaveNamePIDMap[stlStr(dirListing->Item(ui))] = pid; + } + delete dirListing; + //-- + + + //Filter on process existence and name match. + //--- + for(map::iterator it=autosaveNamePIDMap.begin(); + it!=autosaveNamePIDMap.end();) + { + //Note that map does not have a return value for erase in C++second) && processMatchesName(it->second,PROGRAM_NAME) ) + autosaveNamePIDMap.erase(it++); //Note postfix! + else + ++it; + } + //-- + + + //A little messy, but handles two cases of dialog + // one, where one file is either loaded, or deleted + // two, where one of multiple files are either loaded, all deleted or none deleted + vector removeFiles; + + //Do we want to full erase the files in removeFiles (true) + // or move (false) + bool doErase=false; + if(autosaveNamePIDMap.size() == 1) + { + //If we have exactly one autosave, ask the user about loading it + wxString filePath=wxStr(autosaveNamePIDMap.begin()->first); + wxMessageDialog *wxD =new wxMessageDialog(this, + wxTRANS("An auto-save state was found, would you like to restore it?.") + ,wxTRANS("Autosave"),wxCANCEL|wxOK|wxICON_QUESTION|wxYES_DEFAULT ); + + if(wxD->ShowModal()!= wxID_CANCEL) + { + if(!loadFile(filePath)) + { + doErase=true; + statusMessage(TRANS("Unable to load autosave file.."),MESSAGE_ERROR); + } + else + { + doErase=false; + requireFirstUpdate=true; + //Prevent the program from allowing save menu usage + //into autosave file + currentFile.clear(); + fileSave->Enable(false); + } + + + removeFiles.push_back(stlStr(filePath)); + } + } + else if(autosaveNamePIDMap.size() > 1) + { + //OK, so we have more than one autosave, from dead 3depict processes. + //ask the user which one they would like to load + vector > filenamesAndTimes; + + + for(map::iterator it=autosaveNamePIDMap.begin(); + it!=autosaveNamePIDMap.end();++it) + { + time_t timeStamp=wxFileModificationTime(wxStr(it->first)); + filenamesAndTimes.push_back(make_pair(timeStamp,it->first)); + } + + //Sort filenamesAndTimes by decreasing age, so that newest appears at + // top of dialog + ComparePairFirstReverse cmp; + std::sort(filenamesAndTimes.begin(),filenamesAndTimes.end(),cmp); + + vector autoSaveChoices; + time_t now = wxDateTime::Now().GetTicks(); + for(size_t ui=0;uisetItems(autoSaveChoices); + + + int dlgResult; + dlgResult=dlg->ShowModal(); + + //Show the dialog to get a choice from the user + //We need to load a file if, and only if, + // autosaves were not purged + if(dlgResult == wxID_OK) + { + if(!dlg->removedItems()) + { + requireFirstUpdate=true; + + std::string tmpStr; + tmpStr =filenamesAndTimes[dlg->getSelectedItem()].second; + + if(loadFile(wxStr(tmpStr))) + { + //Prevent the program from allowing save menu usage + //into autosave file + currentFile.clear(); + fileSave->Enable(false); + doErase=true; + } + else + doErase=false; + + //If it either does, or doesn't work, + //there is little point in keeping it + removeFiles.push_back(tmpStr); + + } + else + { + for(unsigned int ui=0;uiremovedItems()) + { + for(unsigned int ui=0;uiGetClientArea(); + + bool haveDisplaySizePref; + unsigned int xPref,yPref; + + haveDisplaySizePref=configFile.getInitialAppSize(xPref,yPref); + + //So Min size trumps all + // - then client area + // - then saved setting + // - then default size + wxSize winSize; + if(haveDisplaySizePref) + winSize.Set(xPref,yPref); + else + { + winSize.Set(DEFAULT_WIN_WIDTH,DEFAULT_WIN_HEIGHT); + } + + //Override using minimal window sizes + winSize.Set(std::max(winSize.GetWidth(),(int)MIN_WIN_WIDTH), + std::max(winSize.GetHeight(),(int)MIN_WIN_HEIGHT)); + + //Shrink to display size, as needed + winSize.Set(std::min(winSize.GetWidth(),r.GetWidth()), + std::min(winSize.GetHeight(),r.GetHeight())); + + + delete disp; + + return winSize; + +} + +void MainWindowFrame::set_properties() +{ + // begin wxGlade: MainWindowFrame::set_properties + SetTitle(wxCStr(PROGRAM_NAME)); + comboFilters->SetSelection(-1); + + comboFilters->SetToolTip(wxTRANS("List of available filters")); + treeFilters->SetToolTip(wxTRANS("Tree of data filters")); + checkAutoUpdate->SetToolTip(wxTRANS("Enable/Disable automatic updates of data when filter change takes effect")); + checkAutoUpdate->SetValue(true); + + 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")); + 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); + gridFilterPropGroup->EnableDragRowSize(false); + gridFilterPropGroup->SetColLabelValue(0, wxTRANS("Property")); + gridFilterPropGroup->SetColLabelValue(1, wxTRANS("Value")); + gridCameraProperties->CreateGrid(4, 2); + gridCameraProperties->EnableDragRowSize(false); + gridCameraProperties->SetSelectionMode(wxGrid::wxGridSelectRows); + gridCameraProperties->SetColLabelValue(0, wxTRANS("Property")); + gridCameraProperties->SetColLabelValue(1, wxTRANS("Value")); + gridCameraProperties->SetToolTip(wxTRANS("Camera data information")); + noteCamera->SetScrollRate(10, 10); + +#ifndef APPLE_EFFECTS_WORKAROUND + checkPostProcessing->SetToolTip(wxTRANS("Enable/disable visual effects on final 3D output")); +#endif + checkFxCrop->SetToolTip(wxTRANS("Enable cropping post-process effect")); + comboFxCropAxisOne->SetSelection(0); + comboFxCropAxisTwo->SetSelection(0); + checkFxEnableStereo->SetToolTip(wxTRANS("Colour based 3D effect enable/disable - requires appropriate colour filter 3D glasses.")); + comboFxStereoMode->SetToolTip(wxTRANS("Glasses colour mode")); + comboFxStereoMode->SetSelection(0); + sliderFxStereoBaseline->SetToolTip(wxTRANS("Level of separation between left and right images, which sets 3D depth to visual distortion tradeoff")); + gridRawData->CreateGrid(10, 2); + gridRawData->EnableEditing(false); + gridRawData->EnableDragRowSize(false); + gridRawData->SetColLabelValue(0, wxTRANS("X")); + gridRawData->SetColLabelValue(1, wxTRANS("Y")); + btnRawDataSave->SetToolTip(wxTRANS("Save raw data to file")); + btnRawDataClip->SetToolTip(wxTRANS("Copy raw data to clipboard")); + btnStashManage->SetToolTip(wxTRANS("Manage \"stashed\" data.")); + textConsoleOut->SetToolTip(wxTRANS("Program text output")); + comboCamera->SetToolTip(wxTRANS("Select active camera, or type to create new named camera")); + buttonRemoveCam->SetToolTip(wxTRANS("Remove the selected camera")); + checkFxCropCameraFrame->SetToolTip(wxTRANS("Perform cropping from coordinate frame of camera")); + spinCachePercent->SetToolTip(wxTRANS("Set the maximum amount of RAM to use in order to speed repeat computations")); + btnFilterTreeCollapse->SetToolTip(wxTRANS("Collapse the filter tree")); + btnFilterTreeExpand->SetToolTip(wxTRANS("Expand the filter tree")); + refreshButton->SetToolTip (wxTRANS("Process the filter tree, hold shift to purge cached filter data")); + + // end wxGlade + // + + PlotWrapper *p=new PlotWrapper; //plotting area + + panelSpectra->setPlotWrapper(p); + panelSpectra->setPlotList(plotList); + + //Set the controls that the viscontrol needs to interact with + visControl.setScene(&panelTop->currentScene); //GL scene + visControl.setRawGrid(gridRawData); //Raw data grid + visControl.setPlotWrapper(p); + visControl.setPlotList(plotList); + visControl.setConsole(textConsoleOut); + + + refreshButton->Enable(false); +#if wxCHECK_VERSION(2, 9, 0) + comboCamera->Bind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboCameraSetFocus, this); + comboStash->Bind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboStashSetFocus, this); + noteDataView->Bind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MainWindowFrame::OnNoteDataView, this); +#else + comboCamera->Connect(wxID_ANY, + wxEVT_SET_FOCUS, + wxFocusEventHandler(MainWindowFrame::OnComboCameraSetFocus), NULL, this); + comboStash->Connect(wxID_ANY, + wxEVT_SET_FOCUS, + wxFocusEventHandler(MainWindowFrame::OnComboStashSetFocus), NULL, this); + noteDataView->Connect(wxID_ANY, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, + wxNotebookEventHandler(MainWindowFrame::OnNoteDataView),NULL,this); +#endif + gridCameraProperties->clear(); + int widths[] = {-4,-2,-1}; + MainFrame_statusbar->SetStatusWidths(3,widths); + +} + +void MainWindowFrame::do_layout() +{ + // begin wxGlade: MainWindowFrame::do_layout + wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerTools = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerToolsRamUsage = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* postProcessSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerFxStereo = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerSetereoBaseline = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerStereoCombo = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* cropFxSizer = new wxBoxSizer(wxVERTICAL); + wxFlexGridSizer* sizerFxCropGridLow = new wxFlexGridSizer(3, 2, 2, 2); + wxBoxSizer* cropFxBodyCentreSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* rightPanelSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* textConsoleSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* rawDataGridSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* rawDataSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* plotListSizery = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* topPanelSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizerFxCropRHS = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerFxCropLHS = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* camPaneSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* camTopRowSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* filterPaneSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* filterPropGridSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* filterTreeLeftRightSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* filterRightOfTreeSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* filterMainCtrlSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* stashRowSizer = new wxBoxSizer(wxHORIZONTAL); + filterPaneSizer->Add(lblSettings, 0, 0, 0); + stashRowSizer->Add(comboStash, 1, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 3); + stashRowSizer->Add(btnStashManage, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); + filterPaneSizer->Add(stashRowSizer, 0, wxEXPAND, 0); + filterPaneSizer->Add(filteringLabel, 0, 0, 0); + filterMainCtrlSizer->Add(comboFilters, 0, wxLEFT|wxRIGHT|wxEXPAND, 4); + filterMainCtrlSizer->Add(treeFilters, 3, wxLEFT|wxBOTTOM|wxEXPAND, 3); + filterMainCtrlSizer->Add(lastRefreshLabel, 0, wxTOP, 8); + filterMainCtrlSizer->Add(listLastRefresh, 1, wxBOTTOM|wxEXPAND, 5); + filterTreeLeftRightSizer->Add(filterMainCtrlSizer, 3, wxEXPAND, 0); + filterRightOfTreeSizer->Add(checkAutoUpdate, 0, 0, 0); + filterRightOfTreeSizer->Add(10, 10, 0, 0, 0); + filterRightOfTreeSizer->Add(refreshButton, 0, wxALL, 2); + filterRightOfTreeSizer->Add(20, 20, 0, 0, 0); + filterRightOfTreeSizer->Add(btnFilterTreeCollapse, 0, wxLEFT, 6); + filterRightOfTreeSizer->Add(btnFilterTreeExpand, 0, wxLEFT, 6); + filterRightOfTreeSizer->Add(10, 10, 0, 0, 0); + filterRightOfTreeSizer->Add(btnFilterTreeErrs,0,wxLEFT,6); + btnFilterTreeErrs->Show(false); + filterTreeLeftRightSizer->Add(filterRightOfTreeSizer, 2, wxEXPAND, 0); + filterTreePane->SetSizer(filterTreeLeftRightSizer); + filterPropGridSizer->Add(propGridLabel, 0, 0, 0); + filterPropGridSizer->Add(gridFilterPropGroup, 1, wxLEFT|wxEXPAND, 4); + filterPropertyPane->SetSizer(filterPropGridSizer); +// filterSplitter->SplitHorizontally(filterTreePane, filterPropertyPane);//DISABLED This has to be done later to get the window to work. + filterPaneSizer->Add(filterSplitter, 1, wxEXPAND, 0); + noteData->SetSizer(filterPaneSizer); + camPaneSizer->Add(labelCameraName, 0, 0, 0); + camTopRowSizer->Add(comboCamera, 3, 0, 0); + camTopRowSizer->Add(buttonRemoveCam, 0, wxLEFT|wxRIGHT, 2); + camPaneSizer->Add(camTopRowSizer, 0, wxTOP|wxBOTTOM|wxEXPAND, 4); + camPaneSizer->Add(cameraNamePropertySepStaticLine, 0, wxEXPAND, 0); + camPaneSizer->Add(gridCameraProperties, 1, wxEXPAND, 0); + noteCamera->SetSizer(camPaneSizer); +#ifndef APPLE_EFFECTS_WORKAROUND + postProcessSizer->Add(checkPostProcessing, 0, wxALL, 5); +#endif + cropFxSizer->Add(checkFxCrop, 0, wxALL, 6); + cropFxSizer->Add(checkFxCropCameraFrame, 0, wxLEFT, 15); + sizerFxCropLHS->Add(comboFxCropAxisOne, 0, wxRIGHT|wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5); + sizerFxCropLHS->Add(panelFxCropOne, 1, wxRIGHT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + cropFxBodyCentreSizer->Add(sizerFxCropLHS, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); + sizerFxCropRHS->Add(comboFxCropAxisTwo, 0, wxLEFT|wxBOTTOM|wxEXPAND, 5); + sizerFxCropRHS->Add(panelFxCropTwo, 1, wxLEFT|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + cropFxBodyCentreSizer->Add(sizerFxCropRHS, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0); + cropFxSizer->Add(cropFxBodyCentreSizer, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5); + sizerFxCropGridLow->Add(labelFxCropDx, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); + sizerFxCropGridLow->Add(textFxCropDx, 0, 0, 0); + sizerFxCropGridLow->Add(labelFxCropDy, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); + sizerFxCropGridLow->Add(textFxCropDy, 0, 0, 0); + sizerFxCropGridLow->Add(labelFxCropDz, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); + sizerFxCropGridLow->Add(textFxCropDz, 0, 0, 0); + sizerFxCropGridLow->AddGrowableRow(0); + sizerFxCropGridLow->AddGrowableRow(1); + sizerFxCropGridLow->AddGrowableRow(2); + sizerFxCropGridLow->AddGrowableCol(0); + sizerFxCropGridLow->AddGrowableCol(1); + cropFxSizer->Add(sizerFxCropGridLow, 0, wxBOTTOM|wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + noteFxPanelCrop->SetSizer(cropFxSizer); + sizerFxStereo->Add(checkFxEnableStereo, 0, wxLEFT|wxTOP, 6); + sizerFxStereo->Add(20, 20, 0, 0, 0); + sizerStereoCombo->Add(lblFxStereoMode, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); + sizerStereoCombo->Add(comboFxStereoMode, 0, wxLEFT, 5); + sizerStereoCombo->Add(bitmapFxStereoGlasses, 0, 0, 0); + sizerFxStereo->Add(sizerStereoCombo, 0, wxBOTTOM|wxEXPAND, 15); + sizerSetereoBaseline->Add(labelFxStereoBaseline, 0, wxLEFT|wxTOP, 5); + sizerSetereoBaseline->Add(sliderFxStereoBaseline, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5); + sizerFxStereo->Add(sizerSetereoBaseline, 0, wxEXPAND, 0); + sizerFxStereo->Add(checkFxStereoLensFlip, 0, wxLEFT, 5); + noteFxPanelStereo->SetSizer(sizerFxStereo); + noteEffects->AddPage(noteFxPanelCrop, wxTRANS("Crop")); + noteEffects->AddPage(noteFxPanelStereo, wxTRANS("Stereo")); + postProcessSizer->Add(noteEffects, 1, wxEXPAND, 0); + notePost->SetSizer(postProcessSizer); + sizerTools->Add(checkAlphaBlend, 0, wxLEFT|wxTOP|wxBOTTOM, 5); + sizerTools->Add(checkLighting, 0, wxLEFT|wxTOP|wxBOTTOM, 6); + sizerTools->Add(checkWeakRandom, 0, wxLEFT|wxTOP|wxBOTTOM, 5); + sizerTools->Add(checkCaching, 0, wxLEFT|wxTOP|wxBOTTOM, 5); + sizerToolsRamUsage->Add(labelMaxRamUsage, 0, wxRIGHT|wxALIGN_RIGHT, 5); + sizerToolsRamUsage->Add(spinCachePercent, 0, 0, 5); + sizerTools->Add(sizerToolsRamUsage, 1, wxTOP|wxEXPAND, 5); + noteTools->SetSizer(sizerTools); + notebookControl->AddPage(noteData, wxTRANS("Data")); + notebookControl->AddPage(noteCamera, wxTRANS("Cam")); + notebookControl->AddPage(notePost, wxTRANS("Post")); + notebookControl->AddPage(noteTools, wxTRANS("Tools")); + sizerLeft->Add(notebookControl, 1, wxLEFT|wxBOTTOM|wxEXPAND, 2); + panelLeft->SetSizer(sizerLeft); + topPanelSizer->Add(panelView, 1, wxEXPAND, 0); + panelTop->SetSizer(topPanelSizer); + plotListSizery->Add(plotListLabel, 0, 0, 0); + plotListSizery->Add(plotList, 1, wxEXPAND, 0); + window_2_pane_2->SetSizer(plotListSizery); + splitterSpectra->SplitVertically(panelSpectra, window_2_pane_2); + rawDataGridSizer->Add(gridRawData, 3, wxEXPAND, 0); + rawDataSizer->Add(20, 20, 1, 0, 0); + rawDataSizer->Add(btnRawDataSave, 0, wxLEFT, 2); + rawDataSizer->Add(btnRawDataClip, 0, wxLEFT, 2); + rawDataGridSizer->Add(rawDataSizer, 0, wxTOP|wxEXPAND, 5); + noteRaw->SetSizer(rawDataGridSizer); + textConsoleSizer->Add(textConsoleOut, 1, wxEXPAND, 0); + noteDataViewConsole->SetSizer(textConsoleSizer); + noteDataView->AddPage(splitterSpectra, wxTRANS("Plot")); + noteDataView->AddPage(noteRaw, wxTRANS("Raw")); + noteDataView->AddPage(noteDataViewConsole, wxTRANS("Cons.")); + splitTopBottom->SplitHorizontally(panelTop, noteDataView); + rightPanelSizer->Add(splitTopBottom, 1, wxEXPAND, 0); + panelRight->SetSizer(rightPanelSizer); + splitLeftRight->SplitVertically(panelLeft, panelRight); + topSizer->Add(splitLeftRight, 1, wxEXPAND, 0); + SetSizer(topSizer); + Layout(); + // end wxGlade + // + // GTK fix hack thing. reparent window + + + + panelTop->Reparent(splitTopBottom); + + //Set the combo text + haveSetComboCamText=false; + comboCamera->SetValue(wxCStr(TRANS(cameraIntroString))); + haveSetComboStashText=false; + comboStash->SetValue(wxCStr(TRANS(stashIntroString))); + +} + diff -Nru 3depict-0.0.12/src/gui/mainFrame.h 3depict-0.0.13/src/gui/mainFrame.h --- 3depict-0.0.12/src/gui/mainFrame.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/mainFrame.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,394 @@ +/* + * 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 . +*/ + + +// begin wxGlade: ::dependencies +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// end wxGlade + +//Local stuff +#include "wxcommon.h" +#include "wxcomponents.h" +#include "glPane.h" +#include "mathglPane.h" +#include "cropPanel.h" // cropping tools + +#include "backend/viscontrol.h" +#include "backend/configFile.h" + +#ifndef THREEDEPICT_H +#define THREEDEPICT_H + +class FileDropTarget; + +enum +{ + MESSAGE_ERROR=1, + MESSAGE_INFO, + MESSAGE_HINT, + MESSAGE_NONE_BUT_HINT, + MESSAGE_NONE +}; + +class MainWindowFrame: public wxFrame { +public: + // begin wxGlade: MainWindowFrame::ids + // end wxGlade + + MainWindowFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE); + virtual ~MainWindowFrame(); + + //Drop the following files onto the given window XY coordinates. + void OnDropFiles(const wxArrayString &files, int x, int y); + + bool isCurrentlyUpdatingScene() const { return currentlyUpdatingScene;}; + + void linkCropWidgets(); + + wxSize getNiceWindowSize() const ; + + //Obtain the filterId that is associated with the given tree node. + // returns false if it is not able to do so (eg invalid TreeItemId) + bool getTreeFilterId(const wxTreeItemId &tId, size_t &filterId) const; + +private: + // begin wxGlade: MainWindowFrame::methods + void set_properties(); + void do_layout(); + // end wxGlade + + //!Give a message in the satus bar + void statusMessage(const char *message, unsigned int messageType=MESSAGE_ERROR); + + //!Update the progress information in the status bar + void updateProgressStatus(); + //!Perform an update to the 3D Scene. Returns false if refresh failed + bool doSceneUpdate(); + + //!Update the post-processing effects in the 3D scene. + void updatePostEffects(); + //!Load a file into the panel given the full path to the file + bool loadFile(const wxString &dataFile,bool merge=false); + + //!Load any errors that were detected in the last refresh into the filter tree + void setFilterTreeAnalysisImages(); + + //!Update the effects UI from some effects vector + void updateFxUI(const vector &fx); + + void setLockUI(bool amlocking,unsigned int lockMode); + + //!Scene - user interaction interface "visualisation control" + VisController visControl; + + //!Program on-disk configuration class + ConfigFile configFile; + + //!Blocking bool to prevent functions from responding to programatically generated wx events + bool programmaticEvent; + //!A flag stating if the first update needs a refresh after GL window OK + bool requireFirstUpdate; + //!Have we set the combo cam/stash text in this session? + bool haveSetComboCamText,haveSetComboStashText; + //!Are we in the middle of updating the scene? + bool currentlyUpdatingScene; + //!Have we aborted an update + bool haveAborted; + + //!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; + + //!Current fullscreen status + unsigned int fullscreenState; + + //!Did the main frame's constructor complete OK? + bool initedOK; + + //The type of status message last sent to user + unsigned int lastMessageType; + + //Pointer to version check thread, occasionally initialised at startup to + // check online for new program updates + VersionCheckThread *verCheckThread; + + //Map to convert filter drop down choices to IDs + map filterMap; + + +#ifdef DEBUG + ofstream fs; // file for writing the event log +#endif +protected: + wxTimer *statusTimer; + wxTimer *progressTimer; + wxTimer *updateTimer; //Periodically calls itself to check for updates from user interaction + wxTimer *autoSaveTimer; //Periodically calls itself to create an autosave state file + wxMenuItem *checkMenuControlPane; + wxMenuItem *checkMenuRawDataPane; + wxMenuItem *checkMenuSpectraList; + wxMenuItem *menuViewFullscreen; + wxMenuItem *checkViewLegend; + wxMenuItem *checkViewWorldAxis; + + wxMenuItem *editUndoMenuItem,*editRedoMenuItem; + wxMenuItem *fileSave; + wxMenu *recentFilesMenu; + wxMenu *fileMenu; + wxMenu *fileExport; + wxFileHistory *recentHistory; + + + // begin wxGlade: MainWindowFrame::attributes + wxMenuBar* MainFrame_Menu; + wxStaticText* lblSettings; + wxComboBox* comboStash; + wxButton* btnStashManage; + wxStaticText* filteringLabel; + wxComboBox* comboFilters; + wxTreeCtrl* treeFilters; + wxStaticText* lastRefreshLabel; + wxListCtrl* listLastRefresh; + wxCheckBox* checkAutoUpdate; + wxButton* refreshButton; + wxButton* btnFilterTreeExpand; + wxButton* btnFilterTreeCollapse; + wxBitmapButton* btnFilterTreeErrs; + wxPanel* filterTreePane; + wxStaticText* propGridLabel; + wxPropertyGrid* gridFilterPropGroup; + wxPanel* filterPropertyPane; + wxSplitterWindow* filterSplitter; + wxPanel* noteData; + wxStaticText* labelCameraName; + wxComboBox* comboCamera; + wxButton* buttonRemoveCam; + wxStaticLine* cameraNamePropertySepStaticLine; + wxPropertyGrid* gridCameraProperties; + wxScrolledWindow* noteCamera; + wxCheckBox* checkPostProcessing; + wxCheckBox* checkFxCrop; + wxComboBox* comboFxCropAxisOne; + CropPanel* panelFxCropOne; + wxComboBox* comboFxCropAxisTwo; + CropPanel* panelFxCropTwo; + wxCheckBox* checkFxCropCameraFrame; + wxStaticText* labelFxCropDx; + wxTextCtrl* textFxCropDx; + wxStaticText* labelFxCropDy; + wxTextCtrl* textFxCropDy; + wxStaticText* labelFxCropDz; + wxTextCtrl* textFxCropDz; + wxPanel* noteFxPanelCrop; + wxCheckBox* checkFxEnableStereo; + wxCheckBox* checkFxStereoLensFlip; + wxStaticText* lblFxStereoMode; + wxComboBox* comboFxStereoMode; + wxStaticBitmap* bitmapFxStereoGlasses; + wxStaticText* labelFxStereoBaseline; + wxSlider* sliderFxStereoBaseline; + wxPanel* noteFxPanelStereo; + wxNotebook* noteEffects; + wxPanel* notePost; + wxCheckBox* checkAlphaBlend; + wxCheckBox* checkLighting; + wxCheckBox* checkWeakRandom; + wxCheckBox* checkCaching; + wxStaticText* labelMaxRamUsage; + wxSpinCtrl* spinCachePercent; + wxPanel* noteTools; + wxNotebook* notebookControl; + wxPanel* panelLeft; + wxPanel* panelView; + BasicGLPane* panelTop; + MathGLPane* panelSpectra; + wxStaticText* plotListLabel; + wxListBox* plotList; + wxPanel* window_2_pane_2; + wxSplitterWindow* splitterSpectra; + CopyGrid* gridRawData; + wxButton* btnRawDataSave; + wxButton* btnRawDataClip; + wxPanel* noteRaw; + wxTextCtrl* textConsoleOut; + wxPanel* noteDataViewConsole; + wxNotebook* noteDataView; + wxPanel* panelBottom; + wxSplitterWindow* splitTopBottom; + wxPanel* panelRight; + wxSplitterWindow* splitLeftRight; + wxStatusBar* MainFrame_statusbar; + // end wxGlade + + DECLARE_EVENT_TABLE(); + +public: + virtual void OnFileOpen(wxCommandEvent &event); // wxGlade: + virtual void OnFileMerge(wxCommandEvent &event); // wxGlade: + virtual void OnFileSave(wxCommandEvent &event); // wxGlade: + virtual void OnFileSaveAs(wxCommandEvent &event); // wxGlade: + virtual void OnFileExit(wxCommandEvent &event); // wxGlade: + virtual void OnViewControlPane(wxCommandEvent &event); // wxGlade: + virtual void OnViewRawDataPane(wxCommandEvent &event); // wxGlade: + virtual void OnHelpHelp(wxCommandEvent &event); // wxGlade: + virtual void OnHelpContact(wxCommandEvent &event); // wxGlade: + virtual void OnHelpAbout(wxCommandEvent &event); // wxGlade: + virtual void OnComboStashText(wxCommandEvent &event); // wxGlade: + virtual void OnComboStashEnter(wxCommandEvent &event); // wxGlade: + virtual void OnComboStash(wxCommandEvent &event); // wxGlade: + virtual void OnTreeEndDrag(wxTreeEvent &event); // wxGlade: + virtual void OnTreeKeyDown(wxTreeEvent &event); // wxGlade: + virtual void OnTreeSelectionChange(wxTreeEvent &event); // wxGlade: + virtual void OnTreeDeleteItem(wxTreeEvent &event); // wxGlade: + virtual void OnTreeBeginDrag(wxTreeEvent &event); // wxGlade: + virtual void OnBtnExpandTree(wxCommandEvent &event); // wxGlade: + virtual void OnBtnCollapseTree(wxCommandEvent &event); // wxGlade: + virtual void OnBtnFilterTreeErrs(wxCommandEvent &event); // wxGlade: + virtual void OnComboCameraText(wxCommandEvent &event); // wxGlade: + + virtual void OnGridFilterPropertyChange(wxGridEvent &event); // wxGlade: + virtual void OnComboCameraEnter(wxCommandEvent &event); // wxGlade: + virtual void OnComboCamera(wxCommandEvent &event); // wxGlade: + + + virtual void OnEditUndo(wxCommandEvent &event); + virtual void OnEditRedo(wxCommandEvent &event); + virtual void OnEditPreferences(wxCommandEvent &event); + + virtual void OnButtonRemoveCam(wxCommandEvent &event); // wxGlade: + virtual void OnCheckPostProcess(wxCommandEvent &event); // wxGlade: + virtual void OnFxCropCheck(wxCommandEvent &event); // wxGlade: + virtual void OnFxCropCamFrameCheck(wxCommandEvent &event); // wxGlade: + virtual void OnFxCropAxisOne(wxCommandEvent &event); // wxGlade: + virtual void OnFxCropAxisTwo(wxCommandEvent &event); // wxGlade: + virtual void OnFxStereoEnable(wxCommandEvent &event); // wxGlade: + virtual void OnFxStereoCombo(wxCommandEvent &event); // wxGlade: + virtual void OnFxStereoBaseline(wxScrollEvent &event); // wxGlade: + virtual void OnFxStereoLensFlip(wxCommandEvent &event); // wxGlade: + virtual void OnButtonStashDialog(wxCommandEvent &event); // wxGlade: + virtual void OnCheckAlpha(wxCommandEvent &event); // wxGlade: + virtual void OnCheckLighting(wxCommandEvent &event); // wxGlade: + virtual void OnCheckCacheEnable(wxCommandEvent &event); // wxGlade: + virtual void OnCheckWeakRandom(wxCommandEvent &event); // wxGlade: + virtual void OnCacheRamUsageSpin(wxSpinEvent &event); // wxGlade: + virtual void OnSpectraListbox(wxCommandEvent &event); // wxGlade: + + virtual void OnComboFilterEnter(wxCommandEvent &event); // + virtual void OnComboFilter(wxCommandEvent &event); // + + virtual void OnStatusBarTimer(wxTimerEvent &event); // + virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // + virtual void OnFilterGridCellEditorHide(wxGridEvent &event); // + virtual void OnCameraGridCellEditorShow(wxGridEvent &event); // + virtual void OnCameraGridCellEditorHide(wxGridEvent &event); // + virtual void OnProgressTimer(wxTimerEvent &event); + virtual void OnProgressAbort(wxCommandEvent &event); + virtual void OnViewFullscreen(wxCommandEvent &event); + virtual void OnButtonRefresh(wxCommandEvent &event); + virtual void OnButtonGridCopy(wxCommandEvent &event); + virtual void OnButtonGridSave(wxCommandEvent &event); + virtual void OnRawDataUnsplit(wxSplitterEvent &event); + virtual void OnFilterPropDoubleClick(wxSplitterEvent &event); + virtual void OnControlUnsplit(wxSplitterEvent &event); + virtual void OnControlSplitMove(wxSplitterEvent &event); + virtual void OnTopBottomSplitMove(wxSplitterEvent &event); + virtual void OnSpectraUnsplit(wxSplitterEvent &event); + virtual void OnViewSpectraList(wxCommandEvent &event); + virtual void OnViewPlotLegend(wxCommandEvent &event); + virtual void OnViewWorldAxis(wxCommandEvent &event); + virtual void OnViewBackground(wxCommandEvent &event); + virtual void OnClose(wxCloseEvent &evt); + virtual void OnComboCameraSetFocus(wxFocusEvent &evt); + virtual void OnComboStashSetFocus(wxFocusEvent &evt); + virtual void OnNoteDataView(wxNotebookEvent &evt); + virtual void OnGridCameraPropertyChange(wxGridEvent &event); // wxGlade: + + virtual void OnFileExportPlot(wxCommandEvent &event); // wxGlade: + virtual void OnFileExportImage(wxCommandEvent &event); // wxGlade: + virtual void OnFileExportIons(wxCommandEvent &event); // wxGlade: + virtual void OnFileExportRange(wxCommandEvent &event); // wxGlade: + virtual void OnFileExportVideo(wxCommandEvent &event); + virtual void OnFileExportFilterVideo(wxCommandEvent &event); + virtual void OnFileExportPackage(wxCommandEvent &event); + virtual void OnRecentFile(wxCommandEvent &event); // wxGlade: + + virtual void OnTreeBeginLabelEdit(wxTreeEvent &evt); + virtual void OnTreeEndLabelEdit(wxTreeEvent &evt); + virtual void OnUpdateTimer(wxTimerEvent &evt); + virtual void OnAutosaveTimer(wxTimerEvent &evt); + + virtual void OnCheckUpdatesThread(wxCommandEvent &evt); + + virtual void SetCommandLineFiles(wxArrayString &files); + virtual void updateLastRefreshBox(); + + + //Check to see if we need to reload an autosave file (and reload it, as needed) + void checkReloadAutosave(); + + //Restore user UI defaults from config file (except panel defaults, which + // due to wx behviour need to be done after window show) + void restoreConfigDefaults(); + //Restore panel layout defaults + void restoreConfigPanelDefaults(); + + bool initOK() const {return initedOK;} + + //This is isolated from the layout code, due to "bug" 4815 in wx. The splitter window + //does not know how to choose a good size until the window is shown + void fixSplitterWindow() { + filterSplitter->SplitHorizontally(filterTreePane,filterPropertyPane); + restoreConfigPanelDefaults(); + }; + +}; // wxGlade: end class + + +class FileDropTarget : public wxFileDropTarget +{ +private: + MainWindowFrame *frame; +public: + FileDropTarget(MainWindowFrame *f) { + frame = f; + } + + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& files) + { + frame->OnDropFiles(files, x, y); + + return true; + }; + +}; + +#endif diff -Nru 3depict-0.0.12/src/gui/mathglPane.cpp 3depict-0.0.13/src/gui/mathglPane.cpp --- 3depict-0.0.12/src/gui/mathglPane.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/mathglPane.cpp 2013-04-07 12:17:43.000000000 +0000 @@ -0,0 +1,1353 @@ +/* + * mathglPane.cpp - mathgl-wx interface panel control + * 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 . +*/ + +#include +#include +#include "wxcomponents.h" + +#include "mathglPane.h" + +#include "wxcommon.h" +#include "common/translation.h" + +#ifdef USE_MGL2 + #include + #include +#else + #include +#endif + +//Panning speed modifier +const float MGL_PAN_SPEED=0.8f; +//Mathgl uses floating point loop computation, and can get stuck. Limit zoom precision +const float MGL_ZOOM_LIMIT=10.0f*sqrt(std::numeric_limits::epsilon()); + + +//Mouse action types +enum +{ + MOUSE_MODE_DRAG, //Free mouse drag on plot + MOUSE_MODE_DRAG_PAN, //dragging mouse using a "panning" action + MOUSE_MODE_DRAG_REGION, //Dragging a region + MOUSE_MODE_ENUM_END +}; + +//Do the particular enums require a redraw? +const bool MOUSE_ACTION_NEEDS_REDRAW[] = { false,true,true}; + + + +using std::ifstream; +using std::ios; + +BEGIN_EVENT_TABLE(MathGLPane, wxPanel) + EVT_MOTION(MathGLPane::mouseMoved) + EVT_LEFT_DOWN(MathGLPane::leftMouseDown) + EVT_LEFT_UP(MathGLPane::leftMouseReleased) + EVT_MIDDLE_DOWN(MathGLPane::middleMouseDown) + EVT_MIDDLE_UP(MathGLPane::middleMouseReleased) + EVT_RIGHT_DOWN(MathGLPane::rightClick) + EVT_LEAVE_WINDOW(MathGLPane::mouseLeftWindow) + EVT_LEFT_DCLICK(MathGLPane::mouseDoubleLeftClick) + EVT_SIZE(MathGLPane::resized) + EVT_KEY_DOWN(MathGLPane::keyPressed) + EVT_KEY_UP(MathGLPane::keyReleased) + EVT_MOUSEWHEEL(MathGLPane::mouseWheelMoved) + EVT_PAINT(MathGLPane::render) +END_EVENT_TABLE(); + + +enum +{ + AXIS_POSITION_INTERIOR=1, + AXIS_POSITION_LOW_X=2, + AXIS_POSITION_LOW_Y=4, +}; + + +MathGLPane::MathGLPane(wxWindow* parent, int id) : +wxPanel(parent, id, wxDefaultPosition, wxDefaultSize) +{ + COMPILE_ASSERT(THREEDEP_ARRAYSIZE(MOUSE_ACTION_NEEDS_REDRAW) == MOUSE_MODE_ENUM_END); + + hasResized=true; + limitInteract=haveUpdates=false; + mouseDragMode=MOUSE_MODE_ENUM_END; + leftWindow=true; + thePlot=0; + gr=0; + + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + +} + +MathGLPane::~MathGLPane() +{ + if(thePlot) + delete thePlot; + if(gr) + delete gr; +} + + +unsigned int MathGLPane::getAxisMask(int x, int y) const +{ + + ASSERT(thePlot && gr); + int w,h; + w=0;h=0; + + //Retrieve wx coordinates for window rectangle size + GetClientSize(&w,&h); + + //Retrieve XY position in graph coordinate space + // from XY coordinate in window space. + mglPoint mglCurMouse= gr->CalcXYZ(x,y); + + unsigned int retVal=0; + +#ifdef USE_MGL2 + if(mglCurMouse.x < gr->Self()->GetOrgX('x')) + retVal |=AXIS_POSITION_LOW_X; + + if(mglCurMouse.y < gr->Self()->GetOrgY('y')) + retVal |=AXIS_POSITION_LOW_Y; +#else + if(mglCurMouse.x < gr->Org.x) + retVal |=AXIS_POSITION_LOW_X; + + if(mglCurMouse.y < gr->Org.y) + retVal |=AXIS_POSITION_LOW_Y; +#endif + + if(!retVal) + retVal=AXIS_POSITION_INTERIOR; + + return retVal; +} + +void MathGLPane::setPlotWrapper(PlotWrapper *newPlot) +{ + if(thePlot) + delete thePlot; + + thePlot=newPlot; + + Refresh(); +} + + + +void MathGLPane::render(wxPaintEvent &event) +{ + + wxAutoBufferedPaintDC *dc=new wxAutoBufferedPaintDC(this); + + if(!thePlot || !plotSelList || thePlot->isInteractionLocked() ) + { + delete dc; + return; + } + + bool hasChanged; + hasChanged=thePlot->hasChanged(); + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + + if(!w || !h) + { + delete dc; + return; + } + + + //Set the enabled and disabled plots + wxArrayInt a; + + unsigned int nItems =plotSelList->GetSelections(a); + + if(!nItems) + { +#ifdef __WXGTK__ + wxBrush *b = new wxBrush; + b->SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND)); + dc->SetBackground(*b); + + dc->SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); +#endif +#if !defined(__APPLE__) + dc->Clear(); +#endif + + int clientW,clientH; + GetClientSize(&clientW,&clientH); + + + wxString str=wxTRANS("No plots selected."); + dc->GetMultiLineTextExtent(str,&w,&h); + dc->DrawText(str,(clientW-w)/2, (clientH-h)/2); + +#ifdef __WXGTK__ + delete b; +#endif + delete dc; + + return; + + } + + //Set which plots should be visible + thePlot->hideAll(); + std::vector newVisible; + for(unsigned int ui=0;uiGetClientObject(a[ui]); + plotID = l->value; + newVisible.push_back(ui); + thePlot->setVisible(plotID,true); + } + + + + + //If the plot has changed, been resized or is performing + // a mouse action that requires 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]) + { + + //clear the plot drawing entity + if(gr) + delete gr; + +#ifdef USE_MGL2 + gr = new mglGraph(0,w,h); +#else + gr = new mglGraphZB(w,h); +#endif + //change the plot by panningOneD it before we draw. + //if we need to + if(mouseDragMode==MOUSE_MODE_DRAG_PAN) + { + float xMin,xMax,yMin,yMax; + thePlot->getBounds(xMin,xMax,yMin,yMax); + + mglPoint pEnd,pStart; + pEnd = gr->CalcXYZ(draggingCurrent.x,draggingCurrent.y); + pStart = gr->CalcXYZ(draggingStart.x,draggingStart.y); + + float offX = pEnd.x-pStart.x; + + //I cannot for the life of me work out why + //this extra transformation is needed. + //but without this the code produces a scale-dependant pan speed. + offX*=xMax-xMin; + + //Modify for speed + offX*=MGL_PAN_SPEED; + + thePlot->setBounds(origPanMinX+offX/2,+origPanMaxX + offX/2.0, + yMin,yMax); + } + + //Draw the plot + thePlot->drawPlot(gr); + hasResized=false; + } + + //If the visibility hasn't changed, then reset the + //plot to "no changes" state. Otherwise, + //swap the visibility vectors + if(lastVisible.size() == newVisible.size() && + std::equal(lastVisible.begin(),lastVisible.end(),newVisible.begin())) + thePlot->resetChange(); + else + lastVisible.swap(newVisible); + + //Copy the plot's memory buffer into a wxImage object, then draw it +#ifdef USE_MGL2 + char *rgbdata = (char*)malloc(w*h*3); + gr->GetRGB((char*)rgbdata,w*h*3); + + wxImage img(w,h,(unsigned char*)rgbdata,true); + free(rgbdata); +#else + wxImage img(w,h,const_cast(gr->GetBits()),true); +#endif + dc->DrawBitmap(wxBitmap(img),0,0); + //If we are engaged in a dragging operation + //draw the nice little bits we need + switch(mouseDragMode) + { + case MOUSE_MODE_DRAG: + { + //Draw a rectangle between the start and end positions + wxCoord tlX,tlY,wRect,hRect; + + if(draggingStart.x < draggingCurrent.x) + { + tlX=draggingStart.x; + wRect = draggingCurrent.x - tlX; + } + else + { + tlX=draggingCurrent.x; + wRect = draggingStart.x - tlX; + } + + if(draggingStart.y < draggingCurrent.y) + { + tlY=draggingStart.y; + hRect = draggingCurrent.y - tlY; + } + else + { + tlY=draggingCurrent.y; + hRect = draggingStart.y - tlY; + } + + dc->SetBrush(wxBrush(*wxBLUE,wxTRANSPARENT)); + + const int END_MARKER_SIZE=5; + + //If the cursor is wholly below + //the axis, draw a line rather than a box + + unsigned int startMask, endMask; + startMask=getAxisMask(draggingStart.x, draggingStart.y); + endMask=getAxisMask(draggingCurrent.x, draggingCurrent.y); + + if( (startMask & AXIS_POSITION_LOW_X) + && (endMask & AXIS_POSITION_LOW_X) ) + { + if( !((startMask &AXIS_POSITION_LOW_Y) && (endMask & AXIS_POSITION_LOW_Y))) + { + //left of X-Axis event + //Draw a little I beam. + dc->DrawLine(draggingStart.x,tlY, + draggingStart.x,tlY+hRect); + dc->DrawLine(draggingStart.x-END_MARKER_SIZE,tlY+hRect, + draggingStart.x+END_MARKER_SIZE,tlY+hRect); + dc->DrawLine(draggingStart.x-END_MARKER_SIZE,tlY, + draggingStart.x+END_MARKER_SIZE,tlY); + } + } + else if( (startMask & AXIS_POSITION_LOW_Y) + && (endMask & AXIS_POSITION_LOW_Y) ) + { + //below Y axis event + //Draw a little |-| beam. + dc->DrawLine(tlX,draggingStart.y, + tlX+wRect,draggingStart.y); + dc->DrawLine(tlX+wRect,draggingStart.y-END_MARKER_SIZE, + tlX+wRect,draggingStart.y+END_MARKER_SIZE); + dc->DrawLine(tlX,draggingStart.y-END_MARKER_SIZE, + tlX,draggingStart.y+END_MARKER_SIZE); + + } + else + dc->DrawRectangle(tlX,tlY,wRect,hRect); + + break; + } + case MOUSE_MODE_DRAG_REGION: + { + drawRegionDraggingOverlay(dc); + break; + } + case MOUSE_MODE_DRAG_PAN: + + break; + case MOUSE_MODE_ENUM_END: + { + unsigned int axisMask; + axisMask=getAxisMask(curMouse.x,curMouse.y); + + //Draw any overlays + if(axisMask == AXIS_POSITION_INTERIOR) + drawInteractOverlay(dc); + break; + } + default: + ASSERT(false); + } + + delete dc; +} + +void MathGLPane::resized(wxSizeEvent& evt) +{ + hasResized=true; + Refresh(); +} + + +void MathGLPane::updateMouseCursor() +{ + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + + if(!w || !h || !thePlot ) + return; + + //Set cursor to normal by default + SetCursor(wxNullCursor); + if(!thePlot->getNumVisible()) + return; + + //Update mouse cursor + //--------------- + //Draw a rectangle between the start and end positions + + //If we are using shift, we slide along X axis anyway + if(wxGetKeyState(WXK_SHIFT)) + SetCursor(wxCURSOR_SIZEWE); + else + { + + //If the cursor is wholly beloe + //the axis, draw a line rather than abox + unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); + + float xMin,xMax,yMin,yMax; + + thePlot->getBounds(xMin,xMax,yMin,yMax); + //Look at mouse position relative to the axis position + //to determine the cursor style. + switch(axisMask) + { + case AXIS_POSITION_LOW_X: + //left of X-Axis event, draw up-down arrow + SetCursor(wxCURSOR_SIZENS); + break; + case AXIS_POSITION_LOW_Y: + //Below Y axis, draw line // to x axis + SetCursor(wxCURSOR_SIZEWE); + break; + case AXIS_POSITION_INTERIOR: + SetCursor(wxCURSOR_MAGNIFIER); + break; + default: + ; + } + } + //--------------- +} + +bool MathGLPane::getRegionUnderCursor(const wxPoint &mousePos, unsigned int &plotId, + unsigned int ®ionId) const +{ + ASSERT(gr); + + //Convert the mouse coordinates to data coordinates. + mglPoint pMouse= gr->CalcXYZ(mousePos.x,mousePos.y); + + + //Only allow range interaction within the plot bb +#ifdef USE_MGL2 + if(pMouse.x > gr->Self()->Max.x || pMouse.x < gr->Self()->Min.x) + return false; +#else + if(pMouse.x > gr->Max.x || pMouse.x < gr->Min.x) + return false; +#endif + //check if we actually have a region + if(!thePlot->getRegionIdAtPosition(pMouse.x,pMouse.y,plotId,regionId)) + return false; + + return true; +} + + +void MathGLPane::mouseMoved(wxMouseEvent& event) +{ + leftWindow=false; + if(!thePlot || !gr || thePlot->isInteractionLocked() ) + { + mouseDragMode=MOUSE_MODE_ENUM_END; + return; + } + + curMouse=event.GetPosition(); + + switch(mouseDragMode) + { + case MOUSE_MODE_DRAG: + if(!event.m_leftDown) + mouseDragMode=MOUSE_MODE_ENUM_END; + else + draggingCurrent=event.GetPosition(); + break; + case MOUSE_MODE_DRAG_PAN: + //Can only be dragging with shift/left or middle down + // we might not receive an left up if the user + // exits the window and then releases the mouse + if(!((event.m_leftDown && event.m_shiftDown) || event.m_middleDown)) + mouseDragMode=MOUSE_MODE_ENUM_END; + else + draggingCurrent=event.GetPosition(); + break; + default: + ; + } + //Check if we are still dragging + if(!(event.m_leftDown || event.m_middleDown) || limitInteract) + mouseDragMode=MOUSE_MODE_ENUM_END; + else + draggingCurrent=event.GetPosition(); + + + updateMouseCursor(); + + Refresh(); + +} + +void MathGLPane::mouseDoubleLeftClick(wxMouseEvent& event) +{ + if(!thePlot || !gr || thePlot->isInteractionLocked()) + return; + + //Cancel any mouse drag mode + mouseDragMode=MOUSE_MODE_ENUM_END; + + int w,h; + w=0;h=0; + GetClientSize(&w,&h); + + if(!w || !h ) + return; + + unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); + + switch(axisMask) + { + case AXIS_POSITION_LOW_X: + //left of X-Axis -- plot Y zoom + thePlot->disableUserAxisBounds(false); + break; + case AXIS_POSITION_LOW_Y: + //Below Y axis; plot X Zoom + thePlot->disableUserAxisBounds(true); + break; + case AXIS_POSITION_INTERIOR: + //reset plot bounds + thePlot->disableUserBounds(); + break; + default: + //bottom corner + thePlot->disableUserBounds(); + } + + Refresh(); +} + + +void MathGLPane::oneDMouseDownAction(bool leftDown,bool middleDown, + bool alternateDown, int dragX,int dragY) +{ + ASSERT(thePlot->getNumVisible()); + + int w,h; + w=0;h=0; + + GetClientSize(&w,&h); + + float xMin,xMax,yMin,yMax; + thePlot->getBounds(xMin,xMax,yMin,yMax); + + //Set the interaction mode + if(leftDown && !alternateDown ) + { + int axisMask; + axisMask = getAxisMask(curMouse.x,curMouse.y); + + draggingStart = wxPoint(dragX,dragY); + //check to see if we have hit a region + unsigned int plotId,regionId; + if(!limitInteract && !(axisMask &(AXIS_POSITION_LOW_X | AXIS_POSITION_LOW_Y)) + && getRegionUnderCursor(curMouse,plotId,regionId)) + { + PlotRegion r; + thePlot->getRegion(plotId,regionId,r); + + //TODO: Implement a more generic region handler? + ASSERT(thePlot->plotType(plotId) == PLOT_TYPE_ONED); + + mglPoint mglDragStart = gr->CalcXYZ(draggingStart.x,draggingStart.y); + //Get the type of move, and the region + //that is being moved, as well as the plot that this + //region belongs to. + regionMoveType=computeRegionMoveType(mglDragStart.x,mglDragStart.y, r); + startMouseRegion=regionId; + startMousePlot=plotId; + mouseDragMode=MOUSE_MODE_DRAG_REGION; + } + else + mouseDragMode=MOUSE_MODE_DRAG; + + } + + + if( (leftDown && alternateDown) || middleDown) + { + mouseDragMode=MOUSE_MODE_DRAG_PAN; + draggingStart = wxPoint(dragX,dragY); + + origPanMinX=xMin; + origPanMaxX=xMax; + } + +} + +void MathGLPane::leftMouseDown(wxMouseEvent& event) +{ + if(!gr || !thePlot->getNumVisible() || thePlot->isInteractionLocked()) + return; + + int w,h; + w=h=0; + GetClientSize(&w,&h); + if(!w || !h) + return; + + switch(thePlot->getVisibleType()) + { + case PLOT_TYPE_ONED: + oneDMouseDownAction(event.LeftDown(),false, + event.ShiftDown(), + event.GetPosition().x, + event.GetPosition().y); + break; + case PLOT_TYPE_ENUM_END: + //Do nothing + break; + default: + ASSERT(false); + } + + event.Skip(); +} + +void MathGLPane::middleMouseDown(wxMouseEvent &event) +{ + if(!gr || !thePlot->getNumVisible() || thePlot->isInteractionLocked()) + return; + + int w,h; + w=0;h=0; + GetClientSize(&w,&h); + + if(!w || !h) + return; + + switch(thePlot->getVisibleType()) + { + case PLOT_TYPE_ONED: + oneDMouseDownAction(false,event.MiddleDown(), + event.ShiftDown(), + event.GetPosition().x, + event.GetPosition().y); + break; + case PLOT_TYPE_ENUM_END: + //Do nothing + break; + default: + ASSERT(false); + } + + event.Skip(); +} + +void MathGLPane::mouseWheelMoved(wxMouseEvent& event) +{ + //If no valid plot, don't do anything + if(!thePlot || !gr || thePlot->isInteractionLocked() ) + return; + + //no action if currently dragging + if(!(mouseDragMode==MOUSE_MODE_ENUM_END)) + return; + + unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); + + + + //Bigger numbers mean faster + const float SCROLL_WHEEL_ZOOM_RATE=0.75; + float zoomRate=(float)event.GetWheelRotation()/(float)event.GetWheelDelta(); + zoomRate=zoomRate*SCROLL_WHEEL_ZOOM_RATE; + + //Convert from additive space to multiplicative + float zoomFactor; + if(zoomRate < 0.0f) + zoomFactor=-1.0f/zoomRate; + else + zoomFactor=zoomRate; + + + + ASSERT(zoomFactor >0.0f); + + + mglPoint mousePos; + mousePos=gr->CalcXYZ(curMouse.x,curMouse.y); + + float xPlotMin,xPlotMax,yPlotMin,yPlotMax; + float xMin,xMax,yMin,yMax; + //Get the current bounds for the plot + thePlot->getBounds(xMin,xMax,yMin,yMax); + //Get the absolute bounds for the plot + thePlot->scanBounds(xPlotMin,xPlotMax,yPlotMin,yPlotMax); + + + //Zoom around the point + switch(axisMask) + { + //below x axis -> y zoom only + case AXIS_POSITION_LOW_X: + { + float newYMax,newYMin; + //Zoom along Y + newYMin= mousePos.y + (yMin-mousePos.y)*zoomFactor ; + newYMax= mousePos.y + (yMax-mousePos.y)*zoomFactor ; + + newYMin=std::max(yPlotMin,newYMin); + newYMax=std::min(yPlotMax,newYMax); + + if(newYMax- newYMin> MGL_ZOOM_LIMIT) + thePlot->setBounds(xMin,xMax,newYMin,newYMax); + break; + } + //Below y axis -> x zoom only + case AXIS_POSITION_LOW_Y: + { + float newXMax,newXMin; + //Zoom along X + newXMin= mousePos.x + (xMin-mousePos.x)*zoomFactor ; + newXMax= mousePos.x + (xMax-mousePos.x)*zoomFactor ; + + newXMin=std::max(xPlotMin,newXMin); + newXMax=std::min(xPlotMax,newXMax); + + if(newXMax - newXMin > MGL_ZOOM_LIMIT) + thePlot->setBounds(newXMin,newXMax,yMin,yMax); + break; + } + //Zoom both axes + case AXIS_POSITION_INTERIOR: + { + float newXMax,newXMin; + float newYMax,newYMin; + + //Zoom along X + newXMin= mousePos.x + (xMin-mousePos.x)*zoomFactor ; + newXMax= mousePos.x + (xMax-mousePos.x)*zoomFactor ; + newYMin= mousePos.y + (yMin-mousePos.y)*zoomFactor ; + newYMax= mousePos.y + (yMax-mousePos.y)*zoomFactor ; + + + newXMin=std::max(xPlotMin,newXMin); + newXMax=std::min(xPlotMax,newXMax); + newYMin=std::max(yPlotMin,newYMin); + newYMax=std::min(yPlotMax,newYMax); + + if(newXMax - newXMin > MGL_ZOOM_LIMIT && + newYMax - newYMin > MGL_ZOOM_LIMIT) + thePlot->setBounds(newXMin,newXMax,newYMin,newYMax); + break; + } + default: + ; + } + + Refresh(); +} + +void MathGLPane::leftMouseReleased(wxMouseEvent& event) +{ + + if(!thePlot || !gr || thePlot->isInteractionLocked() ) + return; + + switch(mouseDragMode) + { + case MOUSE_MODE_DRAG: + { + wxPoint draggingEnd = event.GetPosition(); + updateDragPos(draggingEnd); + Refresh(); + break; + } + case MOUSE_MODE_DRAG_REGION: + { + if(!limitInteract) + { + //we need to tell viscontrol that we have done a region + //update + mglPoint mglCurMouse= gr->CalcXYZ(curMouse.x,curMouse.y); + + //Send the movement to the parent filter + thePlot->moveRegion(startMousePlot, + startMouseRegion,regionMoveType,mglCurMouse.x,mglCurMouse.y); + haveUpdates=true; + + } + Refresh(); + break; + } + default: + ; + } + + mouseDragMode=MOUSE_MODE_ENUM_END; + Refresh(); +} + +void MathGLPane::middleMouseReleased(wxMouseEvent& event) +{ + + if(!gr || thePlot->isInteractionLocked()) + return; + + if(mouseDragMode == MOUSE_MODE_DRAG_PAN) + { + mouseDragMode=MOUSE_MODE_ENUM_END; + //Repaint + Refresh(); + } +} + +void MathGLPane::updateDragPos(const wxPoint &draggingEnd) const +{ + ASSERT(mouseDragMode== MOUSE_MODE_DRAG); + + unsigned int startX, endX,startY,endY; + + int w,h; + GetSize(&w,&h); + //Define the rectangle + if(draggingEnd.x > draggingStart.x) + { + startX=draggingStart.x; + endX=draggingEnd.x; + } + else + { + startX=draggingEnd.x; + endX=draggingStart.x; + } + + if(h-draggingEnd.y > h-draggingStart.y) + { + startY=draggingStart.y; + endY=draggingEnd.y; + } + else + { + startY=draggingEnd.y; + endY=draggingStart.y; + } + + //Check that the start and end were not the same (i.e. null zoom in all cases) + if(startX == endX && startY == endY ) + return ; + + + //Compute the MGL coords + mglPoint pStart,pEnd; + pStart = gr->CalcXYZ(startX,startY); + pEnd = gr->CalcXYZ(endX,endY); + + + mglPoint cA; +#ifdef USE_MGL2 + cA.x=gr->Self()->GetOrgX('x'); + cA.y=gr->Self()->GetOrgY('y'); +#else + cA=gr->Org; +#endif + float currentAxisX,currentAxisY; + currentAxisX=cA.x; + currentAxisY=cA.y; + + if(pStart.x < currentAxisX && pEnd.x < currentAxisX ) + { + if(pStart.y < currentAxisY && pEnd.y < currentAxisY ) + { + //corner event + return ; // Do nothing + } + else + { + //Check if can't do anything with this, as it is a null zoom + if(startY == endY) + return; + + //left of X-Axis event + //Reset the axes such that the + //zoom is only along one dimension (y) +#ifdef USE_MGL2 + pStart.x = gr->Self()->Min.x; + pEnd.x = gr->Self()->Max.x; +#else + pStart.x = gr->Min.x; + pEnd.x = gr->Max.x; +#endif + } + } + else if(pStart.y < currentAxisY && pEnd.y < currentAxisY ) + { + //Check if can't do anything with this, as it is a null zoom + if(startX == endX) + return; + //below Y axis event + //Reset the axes such that the + //zoom is only along one dimension (x) +#ifdef USE_MGL2 + pStart.y = gr->Self()->Min.y; + pEnd.y = gr->Self()->Max.y; +#else + pStart.y = gr->Min.y; + pEnd.y = gr->Max.y; +#endif + } + + + //now that we have the rectangle defined, + //Allow for the plot to be zoomed + // + + float minXZoom,maxXZoom,minYZoom,maxYZoom; + + minXZoom=std::min(pStart.x,pEnd.x); + maxXZoom=std::max(pStart.x,pEnd.x); + + minYZoom=std::min(pStart.y,pEnd.y); + maxYZoom=std::max(pStart.y,pEnd.y); + + + //Enforce zoom limit to avoid FP aliasing + if(maxXZoom - minXZoom > MGL_ZOOM_LIMIT && + maxYZoom - minYZoom > MGL_ZOOM_LIMIT) + { + thePlot->setBounds(minXZoom,maxXZoom, + minYZoom,maxYZoom); + } + +} + +void MathGLPane::rightClick(wxMouseEvent& event) +{ +} + +void MathGLPane::mouseLeftWindow(wxMouseEvent& event) +{ + leftWindow=true; + Refresh(); +} + +void MathGLPane::keyPressed(wxKeyEvent& event) +{ + if(!gr || thePlot->isInteractionLocked() ) + return; + updateMouseCursor(); +} + +void MathGLPane::keyReleased(wxKeyEvent& event) +{ + if(!gr || thePlot->isInteractionLocked() ) + return; + updateMouseCursor(); +} + + +unsigned int MathGLPane::savePNG(const std::string &filename, + unsigned int width, unsigned int height) +{ + + if(gr) + delete gr; + + ASSERT(filename.size()); + try + { +#ifdef USE_MGL2 + gr = new mglGraph(0, width,height); +#else + gr = new mglGraphZB(width,height); +#endif + } + catch(std::bad_alloc) + { + gr=0; + return MGLPANE_ERR_BADALLOC; + } + char *mglWarnMsgBuf=new char[1024]; + *mglWarnMsgBuf=0; +#ifdef USE_MGL2 + gr->Self()->SetWarn(0,mglWarnMsgBuf); +#else + gr->SetWarn(0); + gr->Message=mglWarnMsgBuf; +#endif + thePlot->drawPlot(gr); + + gr->WritePNG(filename.c_str()); + + bool doWarn; +#ifdef USE_MGL2 + doWarn=gr->Self()->GetWarn(); +#else + doWarn=gr->WarnCode; +#endif + if(doWarn) + { + lastMglErr=mglWarnMsgBuf; + delete[] mglWarnMsgBuf; + delete gr; + gr=0; + return MGLPANE_ERR_MGLWARN; + } + + delete[] mglWarnMsgBuf; + delete gr; + gr=0; + //Hack. mathgl does not return an error value from its writer + //function :(. Check to see that the file is openable, and nonzero sized + + ifstream f(filename.c_str(),ios::binary); + + if(!f) + return MGLPANE_FILE_REOPEN_FAIL; + + f.seekg(0,ios::end); + + + if(!f.tellg()) + return MGLPANE_FILE_UNSIZED_FAIL; + + return 0; +} + +unsigned int MathGLPane::saveSVG(const std::string &filename) +{ + ASSERT(filename.size()); + + +#ifdef USE_MGL2 + mglGraph *grS; + grS = new mglGraph(); +#else + mglGraphPS *grS; + + //Width and height are not *really* important per se, + //since this is scale-less data. + grS = new mglGraphPS(1024,768); +#endif + + thePlot->drawPlot(grS); + + char *mglWarnMsgBuf=new char[1024]; + *mglWarnMsgBuf=0; +#ifdef USE_MGL2 + grS->Self()->SetWarn(0,mglWarnMsgBuf); +#else + grS->SetWarn(0); + grS->Message=mglWarnMsgBuf; +#endif + grS->WriteSVG(filename.c_str()); + + bool doWarn; +#ifdef USE_MGL2 + doWarn=grS->Self()->GetWarn(); +#else + doWarn=grS->WarnCode; +#endif + + if(doWarn) + { + lastMglErr=mglWarnMsgBuf; + delete[] mglWarnMsgBuf; + delete grS; + grS=0; + return MGLPANE_ERR_MGLWARN; + } + delete grS; + + //Hack. mathgl does not return an error value from its writer + //function :(. Check to see that the file is openable, and nonzero sized + + ifstream f(filename.c_str(),ios::binary); + + if(!f) + return MGLPANE_FILE_REOPEN_FAIL; + + f.seekg(0,ios::end); + + + if(!f.tellg()) + return MGLPANE_FILE_UNSIZED_FAIL; + + return 0; +} + +void MathGLPane::setPlotVisible(unsigned int plotId, bool visible) +{ + thePlot->setVisible(plotId,visible); +} + + +std::string MathGLPane::getErrString(unsigned int errCode) +{ + switch(errCode) + { + case MGLPANE_ERR_BADALLOC: + return std::string(TRANS("Unable to allocate requested memory.\n Try a lower resolution, or save as vector (SVG).")); + case MGLPANE_ERR_MGLWARN: + return std::string(TRANS("Plotting functions returned an error:\n"))+ lastMglErr; + case MGLPANE_FILE_REOPEN_FAIL: + return std::string(TRANS("File readback check failed")); + case MGLPANE_FILE_UNSIZED_FAIL: + return std::string(TRANS("Filesize during readback appears to be zero.")); + default: + ASSERT(false); + } + ASSERT(false); +} + +unsigned int MathGLPane::computeRegionMoveType(float dataX,float dataY,const PlotRegion &r) const +{ + + switch(r.bounds.size()) + { + case 1: + ASSERT(dataX >= r.bounds[0].first && dataX <=r.bounds[0].second); + //Can have 3 different aspects. Left, Centre and Right + return REGION_MOVE_EXTEND_XMINUS+(unsigned int)(3.0f*((dataX-r.bounds[0].first)/ + (r.bounds[0].second- r.bounds[0].first))); + default: + ASSERT(false); + } + + ASSERT(false); +} + +void MathGLPane::drawInteractOverlay(wxDC *dc) const +{ + + int w,h; + w=0;h=0; + GetClientSize(&w,&h); + + ASSERT(w && h); + + unsigned int regionId,plotId; + if(getRegionUnderCursor(curMouse,plotId,regionId)) + { + PlotRegion r; + thePlot->getRegion(plotId,regionId,r); + + wxPen *arrowPen; + if(limitInteract) + arrowPen= new wxPen(*wxLIGHT_GREY,2,wxSOLID); + else + arrowPen= new wxPen(*wxBLACK,2,wxSOLID); + dc->SetPen(*arrowPen); + //Use inverse drawing function so that we don't get + //black-on-black type drawing. + //Other option is to use inverse outlines. + dc->SetLogicalFunction(wxINVERT); + + const int ARROW_SIZE=8; + + + //Convert the mouse coordinates to data coordinates. + mglPoint pMouse= gr->CalcXYZ(curMouse.x,curMouse.y); + unsigned int regionMoveType=computeRegionMoveType(pMouse.x,pMouse.y,r); + + switch(regionMoveType) + { + //Left hand side of region + case REGION_MOVE_EXTEND_XMINUS: + dc->DrawLine(curMouse.x-ARROW_SIZE,h/2-ARROW_SIZE, + curMouse.x-2*ARROW_SIZE, h/2); + dc->DrawLine(curMouse.x-2*ARROW_SIZE, h/2, + curMouse.x-ARROW_SIZE,h/2+ARROW_SIZE); + break; + //right hand side of region + case REGION_MOVE_EXTEND_XPLUS: + dc->DrawLine(curMouse.x+ARROW_SIZE,h/2-ARROW_SIZE, + curMouse.x+2*ARROW_SIZE, h/2); + dc->DrawLine(curMouse.x+2*ARROW_SIZE, h/2, + curMouse.x+ARROW_SIZE,h/2+ARROW_SIZE); + break; + + //centre of region + case REGION_MOVE_TRANSLATE_X: + dc->DrawLine(curMouse.x-ARROW_SIZE,h/2-ARROW_SIZE, + curMouse.x-2*ARROW_SIZE, h/2); + dc->DrawLine(curMouse.x-2*ARROW_SIZE, h/2, + curMouse.x-ARROW_SIZE,h/2+ARROW_SIZE); + dc->DrawLine(curMouse.x+ARROW_SIZE,h/2-ARROW_SIZE, + curMouse.x+2*ARROW_SIZE, h/2); + dc->DrawLine(curMouse.x+2*ARROW_SIZE, h/2, + curMouse.x+ARROW_SIZE,h/2+ARROW_SIZE); + break; + default: + ASSERT(false); + + } + + dc->SetLogicalFunction(wxCOPY); + delete arrowPen; + } + + +} + +void MathGLPane::drawRegionDraggingOverlay(wxDC *dc) const +{ + int w,h; + w=0;h=0; + GetClientSize(&w,&h); + ASSERT(w && h); + //Well, we are dragging the region out some. + //let us draw a line from the original X position to + //the current mouse position/nearest region position + mglPoint mglCurMouse= gr->CalcXYZ(curMouse.x,curMouse.y); + + ASSERT(thePlot->plotType(startMousePlot) == PLOT_TYPE_ONED); + float regionLimitX,regionLimitY; + regionLimitX=mglCurMouse.x; + regionLimitY=mglCurMouse.y; + //See where extending the region is allowed up to. + thePlot->moveRegionLimit(startMousePlot,startMouseRegion, + regionMoveType, regionLimitX,regionLimitY); + + int deltaDrag; + mglPoint testPoint; + testPoint.x=regionLimitX; + testPoint.y=0; + int testX,testY; +#ifdef USE_MGL2 + mglPoint testOut; + testOut=gr->CalcScr(testPoint); + testX=testOut.x; testY=testOut.y; +#else + + gr->CalcScr(testPoint,&testX,&testY); +#endif + deltaDrag = testX-draggingStart.x; + + //Draw some text above the cursor to indicate the current position + std::string str; + stream_cast(str,regionLimitX); + wxString wxs; + wxs=wxStr(str); + wxCoord textW,textH; + dc->GetTextExtent(wxs,&textW,&textH); + + + wxPen *arrowPen; + arrowPen= new wxPen(*wxBLACK,2,wxSOLID); + + dc->SetPen(*arrowPen); + const int ARROW_SIZE=8; + + dc->SetLogicalFunction(wxINVERT); + //draw horiz line + dc->DrawLine(testX,h/2, + draggingStart.x,h/2); + if(deltaDrag > 0) + { + + dc->DrawText(wxs,testX-textW,h/2-textH*2); + //Draw arrow head to face right + dc->DrawLine(testX,h/2, + testX-ARROW_SIZE, h/2-ARROW_SIZE); + dc->DrawLine(testX, h/2, + testX-ARROW_SIZE,h/2+ARROW_SIZE); + + } + else + { + dc->DrawText(wxs,testX,h/2-textH*2); + //Draw arrow head to face left + dc->DrawLine(testX,h/2, + testX+ARROW_SIZE, h/2-ARROW_SIZE); + dc->DrawLine(testX, h/2, + testX+ARROW_SIZE,h/2+ARROW_SIZE); + } + + + switch(regionMoveType) + { + case REGION_MOVE_EXTEND_XMINUS: + case REGION_MOVE_EXTEND_XPLUS: + //No extra markers; we are cool as is + break; + case REGION_MOVE_TRANSLATE_X: + { + //This needs to be extended to support more + //plot types. + ASSERT(thePlot->plotType(startMousePlot) == PLOT_TYPE_ONED); + + //Draw "ghost" limits markers for move, + //these appear as moving vertical bars to outline + //where the translation result will be for both + //upper and lower + PlotRegion reg; + thePlot->getRegion(startMousePlot,startMouseRegion,reg); + mglPoint mglDragStart = gr->CalcXYZ(draggingStart.x,draggingStart.y); + + float newLower,newUpper; + newLower = reg.bounds[0].first + (mglCurMouse.x-mglDragStart.x); + newUpper = reg.bounds[0].second + (mglCurMouse.x-mglDragStart.x); + + int newLowerX,newUpperX,dummy; +#ifdef USE_MGL2 + mglPoint tmp; + tmp=gr->CalcScr(mglPoint(newLower,0.0f)); + newLowerX=tmp.x; + tmp=gr->CalcScr(mglPoint(newUpper,0.0f)); + newUpperX=tmp.x; +#else + gr->CalcScr(mglPoint(newLower,0.0f),&newLowerX,&dummy); + gr->CalcScr(mglPoint(newUpper,0.0f),&newUpperX,&dummy); +#endif + + dc->DrawLine(newLowerX,h/2+2*ARROW_SIZE,newLowerX,h/2-2*ARROW_SIZE); + dc->DrawLine(newUpperX,h/2+2*ARROW_SIZE,newUpperX,h/2-2*ARROW_SIZE); + break; + } + default: + ASSERT(false); + break; + } + + dc->SetLogicalFunction(wxCOPY); + delete arrowPen; + +} diff -Nru 3depict-0.0.12/src/gui/mathglPane.h 3depict-0.0.13/src/gui/mathglPane.h --- 3depict-0.0.12/src/gui/mathglPane.h 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/src/gui/mathglPane.h 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,173 @@ +/* + * mathglPanel.h - WxWidgets plotting panelf or interaction with mathgl + * 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 . +*/ + + +#ifndef MATHGLPANE_H +#define MATHGLPANE_H + +#include "backend/plot.h" + +#ifndef USE_MGL2 + #include + #undef is_nan +#endif + +// begin wxGlade: ::extracode +// end wxGlade + +//Error codes +enum +{ + MGLPANE_ERR_BADALLOC=1, + MGLPANE_ERR_MGLWARN, + MGLPANE_FILE_REOPEN_FAIL, + MGLPANE_FILE_UNSIZED_FAIL, + MGLPANE_ERRMAX, +}; + + +class MathGLPane: public wxPanel { +private: + //Current mouse position + wxPoint curMouse; + //!Has the mouse left the window? + bool leftWindow; + //!Last error reported by mathgl + std::string lastMglErr; + //!What is the user currently doing with the mouse? + unsigned int mouseDragMode; + + //!Has the window resized since the last draw? + bool hasResized; + //!Start and currentlocations for the drag + wxPoint draggingStart,draggingCurrent; + //!Original bounds during panning operations. + float origPanMinX, origPanMaxX; //1D and 2D actions + + //!region used at mouse down + unsigned int startMouseRegion,startMousePlot,regionMoveType; + + //!Do we have region updates? + bool haveUpdates; + + //!Should we be limiting interaction to + //things that won't modify filters (eg region dragging) + bool limitInteract; + + //!Pointer to the plot data holding class + PlotWrapper *thePlot; + //!Pointer to the listbox that is used for plot selection + wxListBox *plotSelList; + //!Pointer to the mathgl renderer +#ifdef USE_MGL2 + mglGraph *gr; +#else + mglGraphZB *gr; +#endif + //!Caching check vector for plot visibility + std::vector lastVisible; + + //!Update the mouse cursor style, based upon mouse position + void updateMouseCursor(); + + //!Compute the "aspect" for a given region; ie which grab handle type + // does this position correspond to + unsigned int computeRegionMoveType(float dataX,float dataY, const PlotRegion &r) const; + + //!Draw the interaction overlay objects + // like the ability to drag etc. + void drawInteractOverlay(wxDC *dc) const; + + //Draw the region Overlays (dragging arrows, bounds etc) + void drawRegionDraggingOverlay(wxDC *dc) const; + + // + void updateDragPos(const wxPoint &event) const; + + //Get the bitmask for the cursor position (below/above axis) from + //the specified window coordinates (use LH window coordinates, as from wx) + unsigned int getAxisMask(int x, int y) const ; + + //Action to perform when showing 1D plots and mouse down event occurs + void oneDMouseDownAction(bool leftDown,bool middleMouseDown, + bool alternateDown, int dragX,int dragY); +public: + + MathGLPane(wxWindow* parent, int id); + virtual ~MathGLPane(); + + //Set the plot pointer for this class to manipulate + void setPlotWrapper(PlotWrapper *plots); + //!Set the plot listbox for this class to use + void setPlotList(wxListBox *box){plotSelList=box;}; + + std::string getErrString(unsigned int code); + + //save an SVG file + unsigned int saveSVG(const std::string &filename); + //Save a PNG file + unsigned int savePNG(const std::string &filename, + unsigned int width,unsigned int height); + //Get the number of visible plots + unsigned int getNumVisible() const {return thePlot->getNumVisible();}; + + //!Get the region under the cursor. Returns region num [0->...) or + //numeric_limits::max() if nothing. + bool getRegionUnderCursor(const wxPoint &mousePos, unsigned int &plotId, unsigned int ®ionId) const; + + //!Do we have updates? + bool hasUpdates() const { return haveUpdates;} + //Instruct the plot that we no loger have updates available. + void clearUpdates() { haveUpdates=false;} + //Resize event for window + void resized(wxSizeEvent& evt); + //Draw window event + void render(wxPaintEvent& evt); + //!wx Event that triggers on mouse movement on grah + void mouseMoved(wxMouseEvent& event); + //Left mouse depress on window + void middleMouseDown(wxMouseEvent& event); + //Right mouse depress on window + void leftMouseDown(wxMouseEvent& event); + //Mouse doubleclick on window + void mouseDoubleLeftClick(wxMouseEvent& event); + //Mousewheel Scroll event + void mouseWheelMoved(wxMouseEvent& event); + //Button being released inside box + void leftMouseReleased(wxMouseEvent& event); + //! Middle mouse button has been let go + void middleMouseReleased(wxMouseEvent& event); + //Right button down-release + void rightClick(wxMouseEvent& event); + //Button leaving client area + void mouseLeftWindow(wxMouseEvent& event); + void keyPressed(wxKeyEvent& event); + void keyReleased(wxKeyEvent& event); + //Select, by ID, which plot we would like to set to being shown + void setPlotVisible(unsigned int plotID, bool visible); + //Show/hide legent + void setLegendVisible(bool visible){thePlot->setLegendVisible(visible);} + //Prevent the user from interacting with the plot + void limitInteraction(bool doLimit=true){ limitInteract=doLimit;}; +protected: + DECLARE_EVENT_TABLE() +}; + + + +#endif diff -Nru 3depict-0.0.12/src/isoSurface.cpp 3depict-0.0.13/src/isoSurface.cpp --- 3depict-0.0.12/src/isoSurface.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/isoSurface.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,742 +0,0 @@ -/* - * IsoSurface.cpp - Isosurface interface generation - * Copyright (C) 2012, 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 . -*/ - -#include "isoSurface.h" - -#include -#include - - -#ifdef DEBUG -template -bool mapUnique(const std::map &m) -{ - vector vec; - vec.reserve(m.size()); - - for(typename std::map::const_iterator it = m.begin(); it!=m.end(); ++it) - { - if(std::find(vec.begin(),vec.end(),it->second) != vec.end()) - return false; - - vec.push_back(it->second); - - } - - return true; -} -#endif - - -//input vector "vec" must be sorted and unique -template -void removeElements( const std::vector &elems,std::vector &vec) -{ - if(vec.empty() || elems.empty()) - return; - - if(vec.size() == elems.size()) - { - vec.clear(); - return; - } - - size_t offset=vec.size()-1; - //Run backwards, swapping out - for(size_t ui=elems.size();ui--;) - { - ASSERT(ui <= offset); - std::swap(vec[elems[ui]],vec[offset]); - offset--; - } - vec.resize(offset+1); -} - - - - -void TriangleWithVertexNorm::computeACWNormal(Point3D &n) const -{ - Point3D a,b; - - a = p[0]-p[1]; - b = p[0]-p[2]; - - n=a.crossProd(b); - n.normalise(); -} - -void TriangleWithVertexNorm::safeComputeACWNormal(Point3D &n) const -{ - Point3D a,b; - - a = p[0]-p[1]; - b = p[0]-p[2]; - - n=a.crossProd(b); - if(n.sqrMag() < sqrt(std::numeric_limits::epsilon()) ) - n=Point3D(0,0,1); - else - n.normalise(); - - - -} - -float TriangleWithVertexNorm::computeArea() const -{ - Point3D a,b; - - a = p[0]-p[1]; - b = p[0]-p[2]; - - return a.crossProd(b).sqrMag(); - -} - -bool TriangleWithVertexNorm::isDegenerate() const -{ - return (p[0].sqrDist(p[1]) < std::numeric_limits::epsilon() || - p[0].sqrDist(p[2]) < std::numeric_limits::epsilon() || - p[2].sqrDist(p[1]) < std::numeric_limits::epsilon()); -} - -void TriangleWithVertexNorm::getCentroid(Point3D &c) const -{ - c=p[0]; - c+=p[1]; - c+=p[2]; - - c*=1.0f/3.0f; -} - -//This code is a modified version of the following: -//============== -// Marching Cubes Example Program -// by Cory Bloyd (corysama@yahoo.com) -// -// A simple, portable and complete implementation of the Marching Cubes -// and Marching Tetrahedrons algorithms in a single source file. -// There are many ways that this code could be made faster, but the -// intent is for the code to be easy to understand. -// -// For a description of the algorithm go to -// http://astronomy.swin.edu.au/pbourke/modelling/polygonise/ -// -// The original code is public domain, and is used here under the GNU General Public Licence, V3 or later. -// ========= - -// For any edge, if one vertex is inside of the surface and the other is outside of the surface -// then the edge intersects the surface -// For each of the 8 vertices of the cube can be two possible states : either inside or outside of the surface -// For any cube the are 2^8=256 possible sets of vertex states -// This table lists the edges intersected by the surface for all 256 possible vertex states -// There are 12 edges. For each entry in the table, if edge #n is intersected, then bit #n is set to 1 -int aiCubeEdgeFlags[256]= -{ - 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, - 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, - 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, - 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, - 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, - 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, - 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, - 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, - 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, - 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, - 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, - 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460, - 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, - 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230, - 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, - 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 -}; - -// For each of the possible vertex states listed in aiCubeEdgeFlags there is a specific triangulation -// of the edge intersection points. a2iTriangleConnectionTable lists all of them in the form of -// 0-5 edge triples with the list terminated by the invalid value -1. -// For example: a2iTriangleConnectionTable[3] list the 2 triangles formed when corner[0] -// and corner[1] are inside of the surface, but the rest of the cube is not. -// -// I found this table in an example program someone wrote long ago. It was probably generated by hand - -int a2iTriangleConnectionTable[256][16] = -{ - {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, - {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, - {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, - {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, - {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, - {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, - {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, - {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, - {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, - {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, - {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, - {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, - {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, - {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, - {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, - {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, - {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, - {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, - {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, - {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, - {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, - {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, - {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, - {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, - {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, - {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, - {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, - {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, - {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, - {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, - {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, - {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, - {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, - {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, - {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, - {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, - {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, - {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, - {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, - {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, - {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, - {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, - {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, - {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, - {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, - {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, - {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, - {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, - {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, - {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, - {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, - {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, - {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, - {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, - {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, - {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, - {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, - {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, - {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, - {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, - {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, - {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, - {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, - {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, - {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, - {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, - {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, - {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, - {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, - {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, - {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, - {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, - {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, - {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, - {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, - {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, - {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, - {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, - {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, - {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, - {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, - {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, - {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, - {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, - {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, - {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, - {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, - {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, - {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, - {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, - {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, - {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, - {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, - {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, - {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, - {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, - {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, - {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, - {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, - {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, - {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, - {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, - {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, - {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, - {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, - {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, - {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, - {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, - {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, - {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, - {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, - {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, - {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, - {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, - {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, - {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, - {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, - {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, - {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, - {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, - {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, - {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, - {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, - {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, - {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, - {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, - {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, - {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, - {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, - {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, - {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, - {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, - {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, - {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, - {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, - {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, - {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, - {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, - {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, - {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, - {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, - {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, - {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, - {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, - {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, - {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, - {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, - {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, - {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, - {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, - {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, - {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, - {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, - {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, - {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, - {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, - {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, - {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, - {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, - {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, - {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, - {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, - {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, - {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} -}; - -//a2fVertexOffset lists the positions, relative to vertex0, of each of the 8 vertices of a cube -static const float a2fVertexOffset[8][3] = -{ - {0.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}, - {0.0, 0.0, 1.0},{1.0, 0.0, 1.0},{1.0, 1.0, 1.0},{0.0, 1.0, 1.0} -}; - -//The deltas for the vertex offsets. This is the int version of a2fVertexOffset -const unsigned int VERTEX_OFFSET[8][3] = -{ - {0, 0, 0},{1, 0, 0},{1, 1, 0},{0, 1, 0}, - {0, 0, 1},{1, 0, 1},{1, 1, 1},{0, 1, 1} -}; - -//a2iEdgeConnection lists the index of the endpoint vertices for each of the 12 edges of the cube -static const int a2iEdgeConnection[12][2] = -{ - {0,1}, {1,2}, {2,3}, {3,0}, - {4,5}, {5,6}, {6,7}, {7,4}, - {0,4}, {1,5}, {2,6}, {3,7} -}; - -//a2fEdgeDirection lists the direction vector (vertex1-vertex0) for each edge in the cube -static const float a2fEdgeDirection[12][3] = -{ - {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0}, - {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0}, - {0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{ 0.0, 0.0, 1.0},{0.0, 0.0, 1.0} -}; - -//Mapping between edges as defined in a2iEdgeConenction, (and thus implicitly in edge table) -//and the voxels.h definition -int edgeRemap[12] ={ 0,6,1,4, - 2,7,3,5, - 8,10,11,9}; - - -//vMarchingCubes iterates over the entire dataset, calling vMarchCube on each cube -void marchingCubes(const Voxels &v,float isoValue, vector &tVec) -{ - size_t nx,ny,nz; - v.getSize(nx,ny,nz); - - ASSERT(nx > 1 && ny>1 && nz>1); - - //Don't try to isosurface a any volume with a unitary dimension. - if(nx ==1 || ny ==1 || nz == 1) - return; - - Point3D gridSpacing; - gridSpacing=v.getPitch(); - -#ifdef DEBUG - BoundCube boundC; - boundC.setBounds(v.getMinBounds(),v.getMaxBounds()); -#endif - - vector indexedTriVec; - - //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 - for(size_t iX = 0; iX < nx-1; iX++) - { - int iEdgeFlags,iFlagIndex; - for(size_t iY = 0; iY < ny-1; iY++) - { - for(size_t iZ = 0; iZ < nz-1; iZ++) - { - iEdgeFlags=iFlagIndex=0; - Point3D position; - //Lower left corner of cell for dual grid - position=v.getPoint(iX,iY,iZ) + gridSpacing*0.5; - - //Find which vertices are inside of the surface and which are outside - for(int iVertexTest = 0; iVertexTest < 8; iVertexTest++) - { - float f; - f=v.getData(iX+VERTEX_OFFSET[iVertexTest][0], - iY+VERTEX_OFFSET[iVertexTest][1], - iZ+VERTEX_OFFSET[iVertexTest][2]); - - //Compute posiion in triangle and edge connection - //tables - if(f <= isoValue) - iFlagIndex |= 1< > edgeTriMap; -#pragma omp parallel for - for(size_t ui=0;ui >::iterator it; - it = edgeTriMap.find((indexedTriVec[ui].p[uj] >>2 ) << 2); - if(it == edgeTriMap.end()) - { - - list seedList; - seedList.push_back(ui); -#pragma omp critical - edgeTriMap.insert( - make_pair((indexedTriVec[ui].p[uj] >>2 ) << 2,seedList)); - - } - else - { - it->second.push_back(ui); - } - } - - } - - - //Generate the position points for each edge - map pointMap; - for(map >::iterator it=edgeTriMap.begin(); - it!=edgeTriMap.end(); ++it) - { - Point3D low,high,voxelFrameIntersection; - float lowF,highF; - - if(pointMap.find((it->first>>2)<<2) != pointMap.end()) - continue; - - //Low/high sides of edge's scalar values - v.getEdgeEndApproxVals(it->first,lowF,highF); - - - //Get the edge's low and high end node positions - v.getEdgeEnds((it->first>>2)<<2,low,high); - - //OK, now we have that, lets use the values to "lever" the - //solution point note node locations for isosurface - if(fabs(highF-lowF) < sqrt(std::numeric_limits::epsilon())) - { - //Prevent divide by zero - voxelFrameIntersection=(low+high)*0.5; - } - else - { - //interpolate - float alpha; - alpha= (isoValue- lowF) / (highF- lowF); - voxelFrameIntersection=low + (high-low)*alpha; - } - - - pointMap.insert(make_pair((it->first>>2)<<2,voxelFrameIntersection)); - } - - - tVec.resize(indexedTriVec.size()); - vector popTris; - //Set all triangle verticies - #pragma omp parallel for - for(size_t ui=0;ui>2)<<2); - - if(tVec[ui].isDegenerate()) - { -#pragma omp critical - popTris.push_back(ui); - } - } - - - //Remove any degenerate triangles from both indexed and real maps - removeElements(popTris,tVec); - removeElements(popTris,indexedTriVec); - - if(tVec.empty()) - return; - - //set all triangle edge normals by inverse face area weighting. - // The idea is that big triangles don't affect the normal at the pooint - // as they are quite delocalised. Little triangles affect it mroe. - // This is entirely empirical - // ---- - - vector origNormal; - origNormal.resize(indexedTriVec.size()); - #pragma omp parallel for - for(size_t ui=0;ui::iterator it=pointMap.begin(); - it!=pointMap.end();++it) - it->second=Point3D(0,0,0); - - //Construct the shared normals - float smallNum=sqrt(std::numeric_limits::epsilon()); - for(size_t ui=0;ui smallNum) - { - for(int uj=0;uj<3;uj++) - pointMap.at((indexedTriVec[ui].p[uj]>>2) <<2)+=origNormal[ui]*weight; - } - } - - - //re-normalise normals - for(map::iterator it=pointMap.begin(); - it!=pointMap.end();++it) - { - if(it->second.sqrMag() > smallNum) - it->second.normalise(); - else - it->second=Point3D(0,0,1); - } - - //assign these normals to the vertices of each triangle - #pragma omp parallel for - for(size_t ui=0;ui>2)<<2); - } - // -- - - // ---- - - - //TODO: We could use something like triStripper - // to optimise this, rather than just build the raw triangles - // http://users.telenet.be/tfautre/softdev/tristripper/ - -} diff -Nru 3depict-0.0.12/src/isoSurface.h 3depict-0.0.13/src/isoSurface.h --- 3depict-0.0.12/src/isoSurface.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/isoSurface.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * isoSurface.h - Marching cubes implementation - * 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 - * 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 . - */ - - -#ifndef ISOSURFACE_H -#define ISOSURFACE_H - -#include "mathfuncs.h" -#include "voxels.h" - -class TriangleWithVertexNorm -{ - public: - Point3D p[3]; - Point3D normal[3]; - - void getCentroid(Point3D &p) const; - void computeACWNormal(Point3D &p) const; - void safeComputeACWNormal(Point3D &p) const; - float computeArea() const; - bool isDegenerate() const; -}; - -struct TriangleWithIndexedVertices -{ - size_t p[3]; -}; - - -//Perform marching cube algorithm -void marchingCubes(const Voxels &v,float isoValue, - std::vector &tVec); - - -#endif diff -Nru 3depict-0.0.12/src/mathfuncs.cpp 3depict-0.0.13/src/mathfuncs.cpp --- 3depict-0.0.12/src/mathfuncs.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/mathfuncs.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,667 +0,0 @@ -/* - * mathfuncs.cpp - Miscellaneous mathematical functions implementation. - * Copyright (C) 2012, 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 . -*/ -#include "mathfuncs.h" - -#include "../config.h" - -#include -#include - - - -const int MBIG = std::numeric_limits::max(); - -void Point3D::copyValueArr(float *valArr) const -{ - ASSERT(valArr); - //compiler should unroll this automatically - for(unsigned int ui=0; ui<3; ui++) - { - *(valArr+ui) = *(value+ui); - } -} - -bool Point3D::operator==(const Point3D &pt) const -{ - return (value[0] == pt.value[0] && value[1] == pt.value[1] && value[2] == pt.value[2]); -} - -const Point3D &Point3D::operator=(const Point3D &pt) -{ - value [0] = pt.value[0]; - value [1] = pt.value[1]; - value [2] = pt.value[2]; - return *this; -} - -const Point3D &Point3D::operator+=(const Point3D &pt) -{ - for(unsigned int ui=0;ui<3; ui++) - value[ui]+= pt.value[ui]; - - return *this; -} - -const Point3D Point3D::operator+(const Point3D &pt) const -{ - Point3D ptTmp; - - for(unsigned int ui=0;ui<3; ui++) - ptTmp.value[ui] = value[ui] + pt.value[ui]; - - return ptTmp; -} - -const Point3D Point3D::operator+(float f) const -{ - Point3D pTmp; - for(unsigned int ui=0;ui<3; ui++) - pTmp.value[ui] = value[ui] + f; - - return pTmp; -} - -const Point3D Point3D::operator-(const Point3D &pt) const -{ - Point3D ptTmp; - - for(unsigned int ui=0;ui<3; ui++) - ptTmp.value[ui] = value[ui] - pt.value[ui]; - - return ptTmp; -} - -const Point3D Point3D::operator-() const -{ - Point3D ptTmp; - - for(unsigned int ui=0;ui<3; ui++) - ptTmp.value[ui] = -value[ui]; - - return ptTmp; -} - -const Point3D &Point3D::operator*=(const float scale) -{ - value[0] = value[0]*scale; - value[1] = value[1]*scale; - value[2] = value[2]*scale; - - return *this; -} - -const Point3D Point3D::operator*(float scale) const -{ - Point3D tmpPt; - - tmpPt.value[0] = value[0]*scale; - tmpPt.value[1] = value[1]*scale; - tmpPt.value[2] = value[2]*scale; - - return tmpPt; -} - -const Point3D Point3D::operator*(const Point3D &pt) const -{ - Point3D tmpPt; - - tmpPt.value[0] = value[0]*pt[0]; - tmpPt.value[1] = value[1]*pt[1]; - tmpPt.value[2] = value[2]*pt[2]; - - return tmpPt; -} - -const Point3D Point3D::operator/(float scale) const -{ - Point3D tmpPt; - - scale = 1.0f/scale; - tmpPt.value[0] = value[0]*scale; - tmpPt.value[1] = value[1]*scale; - tmpPt.value[2] = value[2]*scale; - - return tmpPt; -} - -float Point3D::sqrDist(const Point3D &pt) const -{ - return (pt.value[0]-value[0])*(pt.value[0]-value[0])+ - (pt.value[1]-value[1])*(pt.value[1]-value[1])+ - (pt.value[2]-value[2])*(pt.value[2]-value[2]); -} - -float Point3D::dotProd(const Point3D &pt) const -{ - //Return the inner product - return value[0]*pt.value[0] + value[1]*pt.value[1] + value[2]*pt.value[2]; -} - -Point3D Point3D::crossProd(const Point3D &pt) const -{ - Point3D cross; - - cross.value[0] = (pt.value[2]*value[1] - pt.value[1]*value[2]); - cross.value[1] = -(value[0]*pt.value[2] - pt.value[0]*value[2]); - cross.value[2] = (value[0]*pt.value[1] - value[1]*pt.value[0]); - - return cross; -} - -bool Point3D::insideBox(const Point3D &farPoint) const -{ - - return (value[0] < farPoint.value[0] && value[0] >=0) && - (value[1] < farPoint.value[1] && value[1] >=0) && - (value[2] < farPoint.value[2] && value[2] >=0); -} - -bool Point3D::insideBox(const Point3D &lowPt,const Point3D &highPt) const -{ - - return (value[0] < highPt.value[0] && value[0] >=lowPt.value[0]) && - (value[1] < highPt.value[1] && value[1] >=lowPt.value[1]) && - (value[2] < highPt.value[2] && value[2] >=lowPt.value[2]); -} - -//This is different to +=, because it generates no return value -void Point3D::add(const Point3D &obj) -{ - value[0] = obj.value[0] + value[0]; - value[1] = obj.value[1] + value[1]; - value[2] = obj.value[2] + value[2]; -} - -float Point3D::sqrMag() const -{ - return value[0]*value[0] + value[1]*value[1] + value[2]*value[2]; -} - -Point3D Point3D::normalise() -{ - float mag = sqrtf(sqrMag()); - - value[0]/=mag; - value[1]/=mag; - value[2]/=mag; - - return *this; -} - -void Point3D::negate() -{ - value[0] = -value[0]; - value[1] = -value[1]; - value[2] = -value[2]; -} - -float Point3D::angle(const Point3D &pt) const -{ - return acos(dotProd(pt)/(sqrtf(sqrMag()*pt.sqrMag()))); -} - -bool Point3D::orthogonalise(const Point3D &pt) -{ - Point3D crossp; - crossp=this->crossProd(pt); - - //They are co-linear, or near-enough to be not resolvable. - if(crossp.sqrMag() < sqrt(std::numeric_limits::epsilon())) - return false; - crossp.normalise(); - - crossp=crossp.crossProd(pt); - *this=crossp.normalise()*sqrt(this->sqrMag()); - - return true; -} - -#ifdef __LITTLE_ENDIAN__ - -void Point3D::switchEndian() -{ - floatSwapBytes(&value[0]); - floatSwapBytes(&value[1]); - floatSwapBytes(&value[2]); -} -#endif - -std::ostream& operator<<(std::ostream &stream, const Point3D &pt) -{ - stream << "(" << pt.value[0] << "," << pt.value[1] << "," << pt.value[2] << ")"; - return stream; -} - - -void Point3D::transform3x3(const float *matrix) -{ - for(unsigned int ui=0;ui<3;ui++) - { - value[ui] = value[ui]*matrix[ui*3] + - value[ui]*matrix[ui*3+1] + value[ui]*matrix[ui*3+2]; - } -} -RandNumGen::RandNumGen() -{ - //Initialisation is NOT performed here, because we need a random seed - //to generate our sequence.... - - //we dont initially have gaussian - //value to spare - haveGaussian=false; -} - -void RandNumGen::initialise(int seed) -{ - long mj,mk; - - int ii; - //initialise ma[55] with seed - mj=labs((MBIG-labs(seed))); - mj%=MBIG; - ma[55]=mj; - mk=1; - - - //Initialise the rest of the table - for(unsigned int i=1; i<55; i++) - { - ii=(21*i)%55; - - ma[ii]=mk; - mk=mj-mk; - - if(mk<0) - mk+=MBIG; - mj=ma[ii]; - } - - //"warm up" the rng - for(unsigned int j=1;j<=4;j++) - { - for(unsigned int i=1;i<=55;i++) - { - ma[i] -=ma[1+ (i+30)%55]; - if(ma[i] < 0) - ma[i]+=MBIG; - } - } - //the constant 31 is special - inext=0; - inextp=31; -} - - -float RandNumGen::genUniformDev() -{ - long mj; - - if(++inext==56) - inext=1; - if(++inextp == 56) - inextp=1; - - mj=ma[inext]-ma[inextp]; - if(mj<0) - mj+=MBIG; - - ma[inext]=mj; - - return mj*(1.0/MBIG); -} - - -int RandNumGen::genInt() -{ - long mj; - - if(++inext==56) - inext=1; - if(++inextp == 56) - inextp=1; - - mj=ma[inext]-ma[inextp]; - if(mj<0) - mj+=MBIG; - - ma[inext]=mj; - - return mj; -} - - -//This is known as the Box-Muller transform -//You can change it from being a uniform variance -//by simply multiplying by the std deviation of your choice -//this will cause the random number returned to be stretched -//in the x axis from unit variance to your number -float RandNumGen::genGaussDev() -{ - float v1,v2,rsq,fac; - //This algorithm generates - //two gaussian numbers from two Uniform Devs, - //however we only want one. So to speed things up - //remember the second and spit it out as required - if(haveGaussian) - { - haveGaussian=false; - return gaussSpare; - } - - do - { - //grab two uniform Devs and - //move them into (-1,+1) domain - v1=2.0f*genUniformDev()-1.0f; - v2=2.0f*genUniformDev()-1.0f; - rsq=v1*v1+v2*v2; - //reject them if they dont lie in unit circle - //or if rsq is at the origin of the unit circle - //(as eqn below is undefined at origin) - }while(rsq>=1.0f || rsq==0.0f); - - fac=sqrtf(-2.0f*log(rsq)/rsq); - gaussSpare=v1*fac; - haveGaussian=true; - return v2*fac; - -} - -int RandNumGen::initTimer() -{ - timeval tp; - - gettimeofday(&tp,NULL); - - initialise(tp.tv_sec+ tp.tv_usec); - - return tp.tv_sec + tp.tv_usec; -} - -//quaternion multiplication, assuming q2 has no "a" component -void quat_mult_no_second_a(Quaternion *result, Quaternion *q1, Quaternion *q2) -{ - result->a = (-q1->b*q2->b-q1->c*q2->c -q1->d*q2->d); - result->b = (q1->a*q2->b +q1->c*q2->d -q1->d*q2->c); - result->c = (q1->a*q2->c -q1->b*q2->d +q1->d*q2->b); - result->d = (q1->a*q2->d +q1->b*q2->c -q1->c*q2->b ); -} - -//this is a little optimisation that doesnt calculate the a component for -//the returned quaternion, and implicitly performs conjugation. -//Note that the result is specific to quaternion rotation -void quat_pointmult(Point3f *result, Quaternion *q1, Quaternion *q2) -{ - result->fx = (-q1->a*q2->b +q1->b*q2->a -q1->c*q2->d +q1->d*q2->c); - result->fy = (-q1->a*q2->c +q1->b*q2->d +q1->c*q2->a -q1->d*q2->b); - result->fz = (-q1->a*q2->d -q1->b*q2->c +q1->c*q2->b +q1->d*q2->a); - -} - -//Uses quaternion mathematics to perform a rotation around your favourite axis -//IMPORTANT: Rotvec must be normalised before passing to this function -//failure to do so will have wierd results. -//For better performance on multiple rotations, use other functio -//Note result is stored in returned point -void quat_rot(Point3f *point, 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::epsilon())); - - double sinCoeff; - Quaternion rotQuat; - Quaternion pointQuat; - Quaternion temp; - - //remember this value so we dont recompute it -#ifdef _GNU_SOURCE - double cosCoeff; - //GNU provides sincos which is about twice the speed of sin/cos separately - sincos(angle*0.5f,&sinCoeff,&cosCoeff); - rotQuat.a=cosCoeff; -#else - angle*=0.5f; - sinCoeff=sin(angle); - - rotQuat.a = cos(angle); -#endif - rotQuat.b=sinCoeff*rotVec->fx; - rotQuat.c=sinCoeff*rotVec->fy; - rotQuat.d=sinCoeff*rotVec->fz; - -// pointQuat.a =0.0f; This is implied in the pointQuat multiplcation function - pointQuat.b = point->fx; - pointQuat.c = point->fy; - pointQuat.d = point->fz; - - - //perform rotation - quat_mult_no_second_a(&temp,&rotQuat,&pointQuat); - quat_pointmult(point, &temp,&rotQuat); - -} - - -//Retrieve the quaternion for repeated rotation. pass to the quat_rot_apply_quats -void quat_get_rot_quat(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::epsilon())); - double sinCoeff; -#ifdef _GNU_SOURCE - double cosCoeff; - //GNU provides sincos which is about twice the speed of sin/cos separately - sincos(angle*0.5f,&sinCoeff,&cosCoeff); - rotQuat->a=cosCoeff; -#else - angle*=0.5f; - sinCoeff=sin(angle); - rotQuat->a = cos(angle); -#endif - - rotQuat->b=sinCoeff*rotVec->fx; - rotQuat->c=sinCoeff*rotVec->fy; - rotQuat->d=sinCoeff*rotVec->fz; -} - -//Use previously generated quats from quat_get_rot_quats to rotate a point -void quat_rot_apply_quat(Point3f *point, Quaternion *rotQuat) -{ - Quaternion pointQuat,temp; -// pointQuat.a =0.0f; No need to set this, as we do not use it in the multiplciation function - pointQuat.b = point->fx; - pointQuat.c = point->fy; - pointQuat.d = point->fz; - //perform rotation - quat_mult_no_second_a(&temp,rotQuat,&pointQuat); - quat_pointmult(point, &temp,rotQuat); -} - -//For the table to work, we need the sizeof(size_T) at preprocess time -#ifndef SIZEOF_SIZE_T -#error sizeof(size_t) macro is undefined... At time of writing, this is usually 4 (32 bit) or 8. You can work it out from a simple C++ program which prints out sizeof(size_t). This cant be done automatically due to preprocessor behaviour. -#endif - -//Maximum period linear shift register values (computed by -//other program for galois polynomial) -//Unless otherwise noted, all these entries have been verfied using the -//verifyTable routine. -// -//If you don't trust me, (who doesn't trust some random person on the internet?) -//you can re-run the verfication routine. -// -//Note that verfication time *doubles* with every entry, so full 64-bit verification -//is computationally intensive. I achieved 40 bits in half a day. 48 bits took over a week. -size_t maximumLinearTable[] = { - 0x03, - 0x06, - 0x0C, - 0x14, - 0x30, - 0x60, - 0xb8, - 0x0110, - 0x0240, - 0x0500, - 0x0e08, - 0x1c80, - 0x3802, - 0x6000, - 0xb400, - 0x12000, - 0x20400, - 0x72000, - 0x90000, - 0x140000, - 0x300000, - 0x420000, - 0xD80000, - 0x1200000, - 0x3880000, - 0x7200000, - 0x9000000, - 0x14000000, - 0x32800000, - 0x48000000, - -#if (SIZEOF_SIZE_T > 4) - 0xA3000000, - 0x100080000, - 0x262000000, - 0x500000000, - 0x801000000, - 0x1940000000, - 0x3180000000, - 0x4400000000, - 0x9C00000000, - 0x12000000000, - 0x29400000000, - 0x63000000000, - 0xA6000000000, - 0x1B0000000000, - 0x20E000000000, - 0x420000000000, - 0x894000000000, - //Maximal linear table entries below line are unverified - //Verifying the full table might take a few months of computing time - //But who needs to count beyond 2^49-1 (~10^14) anyway?? - 0x1008000000000, - - //Really, there are more entries beyond this, but I consider it pretty much not worth the effort. -#endif -}; - - -void LinearFeedbackShiftReg::setMaskPeriod(unsigned int newMask) -{ - //Don't fall off the table - ASSERT((newMask-3) < sizeof(maximumLinearTable)/sizeof(size_t)); - - maskVal=maximumLinearTable[newMask-3]; - - //Set the mask to be all ones - totalMask=0; - for(size_t ui=0;ui> 1) ^ -(lfsr & (ull)(1u)) & maskVal; - lfsr&=totalMask; - if( lfsr == 0u) - lfsr=1u; - - return lfsr; -} - -double det3by3(const double *ptArray) -{ - return (ptArray[0]*(ptArray[4]*ptArray[8] - - ptArray[7]*ptArray[5]) - - ptArray[1]*(ptArray[3]*ptArray[8] - - ptArray[6]*ptArray[5]) - + ptArray[2]*(ptArray[3]*ptArray[7] - - ptArray[4]*ptArray[6])); -} - -//Determines the volume of a quadrilateral pyramid -//input points "planarpts" must be adjacent (connected) by -//0 <-> 1 <-> 2 <-> 0, all points connected to apex -double pyramidVol(const Point3D *planarPts, const Point3D &apex) -{ - - //Array for 3D simplex volumed determination - // | (a_x - b_x) (b_x - c_x) (c_x - d_x) | - //v_simplex =1/6| (a_y - b_y) (b_y - c_y) (c_y - d_y) | - // | (a_z - b_z) (b_z - c_z) (c_z - d_z) | - double simplexA[9]; - - //simplex A (a,b,c,apex) is as follows - //a=planarPts[0] b=planarPts[1] c=planarPts[2] - - simplexA[0] = (double)( (planarPts[0])[0] - (planarPts[1])[0] ); - simplexA[1] = (double)( (planarPts[1])[0] - (planarPts[2])[0] ); - simplexA[2] = (double)( (planarPts[2])[0] - (apex)[0] ); - - simplexA[3] = (double)( (planarPts[0])[1] - (planarPts[1])[1] ); - simplexA[4] = (double)( (planarPts[1])[1] - (planarPts[2])[1] ); - simplexA[5] = (double)( (planarPts[2])[1] - (apex)[1] ); - - simplexA[6] = (double)( (planarPts[0])[2] - (planarPts[1])[2] ); - simplexA[7] = (double)( (planarPts[1])[2] - (planarPts[2])[2] ); - simplexA[8] = (double)( (planarPts[2])[2] - (apex)[2] ); - - return 1.0/6.0 * (fabs(det3by3(simplexA))); -} - - diff -Nru 3depict-0.0.12/src/mathfuncs.h 3depict-0.0.13/src/mathfuncs.h --- 3depict-0.0.12/src/mathfuncs.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/mathfuncs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -/* - * mathfuncs.h - General mathematic functions header - * Copyright (C) 2012, 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 . -*/ -#ifndef MATHFUNCS_H -#define MATHFUNCS_H - -#include -#include -#include -#include - -#include "assertion.h" -#include "endianTest.h" - - -//!A 3D point data class storage -/*! A 3D point data class - * contains operator overloads and some basic - * mathematical functions - */ -class Point3D -{ - private: - //!Value data - float value[3]; - public: - //!Constructor - inline Point3D() {}; - //!Constructor with initialising values - inline Point3D(float x,float y,float z) - { value[0] = x, value[1] = y, value[2] = z;} - //!Set by value (ith dim 0, 1 2) - inline void setValue(unsigned int ui, float val){value[ui]=val;}; - //!Set all values - inline void setValue(float fX,float fY, float fZ) - {value[0]=fX; value[1]=fY; value[2]=fZ;} - - //!Set by pointer - inline void setValueArr(const float *val) - { - value[0]=*val; - value[1]=*(val+1); - value[2]=*(val+2); - }; - - //!Get value of ith dim (0, 1, 2) - inline float getValue(unsigned int ui) const {return value[ui];}; - //Retrieve the internal pointer. Only use if you know why. - inline const float *getValueArr() const { return value;}; - - //!get into an array (note array must hold sizeof(float)*3 bytes of valid mem - void copyValueArr(float *value) const; - - //!Add a point to this, without generating a return value - void add(const Point3D &obj); - - //!Equality operator - bool operator==(const Point3D &pt) const; - //!assignment operator - const Point3D &operator=(const Point3D &pt); - //!+= operator - const Point3D &operator+=(const Point3D &pt); - - const Point3D operator+(float f) const; - //!multiplication operator - const Point3D &operator*=(const float scale); - //!Addition operator - const Point3D operator+(const Point3D &pt) const; - //!elemental multiplication - const Point3D operator*(float scale) const; - //!multiplication - const Point3D operator*(const Point3D &pt) const; - //!Division. - const Point3D operator/(float scale) const; - //!Subtraction - const Point3D operator-(const Point3D &pt) const; - //!returns a negative of the existing value - const Point3D operator-() const; - //!Output streaming operator. Users (x,y,z) as format for output - friend std::ostream &operator<<(std::ostream &stream, const Point3D &); - //!make point unit magnitude, maintaining direction - Point3D normalise(); - //!returns the square of distance another pt - float sqrDist(const Point3D &pt) const; - - //!Calculate the dot product of this and another pint - float dotProd(const Point3D &pt) const; - //!Calculate the cross product of this and another point - Point3D crossProd(const Point3D &pt) const; - - //!Calculate the angle between two position vectors in radiians - float angle(const Point3D &pt) const; - - //!overload for array indexing returns |pt|^2 - float sqrMag() const; - - //!Retrieve by value - inline float operator[](unsigned int ui) const { ASSERT(ui < 3); return value[ui];} - //!Retrieve element by referene - inline float &operator[](unsigned int ui) { ASSERT(ui < 3); return value[ui];} - - //!Is a given point stored inside a box bounded by orign and this pt? - /*!returns true if this point is located inside (0,0,0) -> Farpoint - * assuming box shape (non zero edges return false) - * farPoint must be positive in all dim - */ - bool insideBox(const Point3D &farPoint) const; - - - //!Tests if this point lies inside the rectangular prism - /*!Returns true if this point lies inside the box bounded - * by lowPoint and highPoint - */ - bool insideBox(const Point3D &lowPoint, const Point3D &highPoint) const; - - //!Makes each value negative of old value - void negate(); - - //Perform a 3x3 matrix transformation. - void transform3x3(const float *matrix); - - //Perform a cross-product based orthogonalisation - //with the specified vector - bool orthogonalise(const Point3D &p); -#ifdef __LITTLE_ENDIAN__ - //!Flip the endian state for data stored in this point - void switchEndian(); -#endif -}; - -//IMPORTANT!!! -//=============== -//Do NOT use multiple instances of this in your code -//with the same initialisation technique (e.g. initialising from system clock) -//this would be BAD, correlations might well be introduced into your results -//that are simply a result of using correlated random sequences!!! (think about it) -//use ONE random number generator in the project, initialise it and then "register" -//it with any objects that need a random generator. -//============== -class RandNumGen -{ - private: - int ma[56]; - int inext,inextp; - float gaussSpare; - bool haveGaussian; - - public: - RandNumGen(); - void initialise(int seedVal); - int initTimer(); - - int genInt(); - float genUniformDev(); - - //This generates a number chosen from - //a gaussian distribution range is (-inf, inf) - float genGaussDev(); -}; - -//needed for sincos -#ifdef __LINUX__ -#ifdef __GNUC__ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#endif -#endif - -typedef struct -{ - float a; - float b; - float c; - float d; -} Quaternion; - -typedef struct -{ - float fx; - float fy; - float fz; -} Point3f; - -//Uses quaternion mathematics to perform a rotation around your favourite axis -//IMPORTANT: rotVec must be normalised before passing to this function -//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); - -//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); - -//Use previously generated quats from quat_get_rot_quats to rotate a point -void quat_rot_apply_quat(Point3f *point, Quaternion *rotQuat); - -//This class implements a Linear Feedback Shift Register (in software) -//This is a mathematical construct based upon polynomials over closed natural numbers (N mod p). -//This will generate a weakly random digit string, but with guaranteed no duplicates, using O(1) -//memory and O(n) calls. The no duplicate guarantee is weak-ish, with no repetition in the -//shift register for 2^n-1 iterations. n can be set by setMaskPeriod. -class LinearFeedbackShiftReg -{ - size_t lfsr; - size_t maskVal; - size_t totalMask; - public: - //Get a value from the shift register, and advance - size_t clock(); - //Set the internal lfsr state. Note 0 is the lock-up state. - void setState(size_t newState) { lfsr=newState;}; - //set the mask to use such that the period is 2^n-1. 3 is minimum 60 is maximum - void setMaskPeriod(unsigned int newMask); - - //!Check the validity of the table - bool verifyTable(); -}; - - -//Determines the volume of a quadrilateral pyramid -//input points "planarpts" must be adjacent (connected) by -//0 <-> 1 <-> 2 <-> 0, all points connected to apex -double pyramidVol(const Point3D *planarPts, const Point3D &apex); - -//!Inline func for calculating a(dot)b -inline float dotProduct(float a1, float a2, float a3, - float b1, float b2, float b3) -{ - return a1*b1 + a2*b2 + a3* b3; -} - -inline unsigned int ilog2(unsigned int value) -{ - unsigned int l = 0; - while( (value >> l) > 1 ) - ++l; - return l; -} -#endif diff -Nru 3depict-0.0.12/src/mathglPane.cpp 3depict-0.0.13/src/mathglPane.cpp --- 3depict-0.0.12/src/mathglPane.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/mathglPane.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1367 +0,0 @@ -/* - * mathglPane.cpp - mathgl-wx interface panel control - * Copyright (C) 2012, 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 . -*/ - -#include -#include -#include -#include "mathglPane.h" - -#include "wxcomponents.h" -#include "wxcommon.h" -#include "translation.h" - -#include - -#include -#include - -//Uncomment me if using MGL >=1_10 to -//enable nice drawing of rectangular bars -#define MGL_GTE_1_10 - -//Panning speed modifier -const float MGL_PAN_SPEED=0.8f; -//Mathgl uses floating point loop computation, and can get stuck. Limit zoom precision -const float MGL_ZOOM_LIMIT=10.0f*sqrt(std::numeric_limits::epsilon()); - - -//Mouse action types -enum -{ - MOUSE_MODE_DRAG, //Free mouse drag on plot - MOUSE_MODE_DRAG_PAN, //dragging mouse using a "panning" action - MOUSE_MODE_DRAG_REGION, //Dragging a region - MOUSE_MODE_ENUM_END -}; - -//Do the particular enums require a redraw? -const bool MOUSE_ACTION_NEEDS_REDRAW[] = { false,true,true}; - - - -using std::ifstream; -using std::ios; - -BEGIN_EVENT_TABLE(MathGLPane, wxPanel) - EVT_MOTION(MathGLPane::mouseMoved) - EVT_LEFT_DOWN(MathGLPane::leftMouseDown) - EVT_LEFT_UP(MathGLPane::leftMouseReleased) - EVT_MIDDLE_DOWN(MathGLPane::middleMouseDown) - EVT_MIDDLE_UP(MathGLPane::middleMouseReleased) - EVT_RIGHT_DOWN(MathGLPane::rightClick) - EVT_LEAVE_WINDOW(MathGLPane::mouseLeftWindow) - EVT_LEFT_DCLICK(MathGLPane::mouseDoubleLeftClick) - EVT_SIZE(MathGLPane::resized) - EVT_KEY_DOWN(MathGLPane::keyPressed) - EVT_KEY_UP(MathGLPane::keyReleased) - EVT_MOUSEWHEEL(MathGLPane::mouseWheelMoved) - EVT_PAINT(MathGLPane::render) -END_EVENT_TABLE(); - - -enum -{ - AXIS_POSITION_INTERIOR=1, - AXIS_POSITION_LOW_X=2, - AXIS_POSITION_LOW_Y=4, -}; - - -MathGLPane::MathGLPane(wxWindow* parent, int id) : -wxPanel(parent, id, wxDefaultPosition, wxDefaultSize) -{ - COMPILE_ASSERT(ARRAYSIZE(MOUSE_ACTION_NEEDS_REDRAW) == MOUSE_MODE_ENUM_END); - - hasResized=true; - limitInteract=haveUpdates=false; - mouseDragMode=MOUSE_MODE_ENUM_END; - leftWindow=true; - thePlot=0; - gr=0; - - SetBackgroundStyle(wxBG_STYLE_CUSTOM); - -} - -MathGLPane::~MathGLPane() -{ - if(thePlot) - delete thePlot; - if(gr) - delete gr; -} - - -unsigned int MathGLPane::getAxisMask(int x, int y) const -{ - - ASSERT(thePlot && gr); - int w,h; - w=0;h=0; - - //Retrieve wx coordinates for window rectangle size - GetClientSize(&w,&h); - - //Retrieve XY position in graph coordinate space - // from XY coordinate in window space. - mglPoint mglCurMouse= gr->CalcXYZ(x,y); - - unsigned int retVal=0; - - if(mglCurMouse.x < gr->Org.x) - retVal |=AXIS_POSITION_LOW_X; - - if(mglCurMouse.y < gr->Org.y) - retVal |=AXIS_POSITION_LOW_Y; - - if(!retVal) - retVal=AXIS_POSITION_INTERIOR; - - return retVal; -} - -void MathGLPane::setPlotWrapper(PlotWrapper *newPlot) -{ - if(thePlot) - delete thePlot; - - thePlot=newPlot; - - Refresh(); -} - - - -void MathGLPane::render(wxPaintEvent &event) -{ -#ifdef DEBUG - extern EventLogger evtlog; - evtlog.insert(event); -#endif - - wxAutoBufferedPaintDC *dc=new wxAutoBufferedPaintDC(this); - - if(!thePlot || !plotSelList || thePlot->isInteractionLocked() ) - { - delete dc; - return; - } - - bool hasChanged; - hasChanged=thePlot->hasChanged(); - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - - if(!w || !h) - { - delete dc; - return; - } - - - //Set the enabled and disabled plots - wxArrayInt a; - - unsigned int nItems =plotSelList->GetSelections(a); - - if(!nItems) - { -#ifdef __WXGTK__ - wxBrush *b = new wxBrush; - b->SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND)); - dc->SetBackground(*b); - - dc->SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); -#endif -#if !defined(__APPLE__) - dc->Clear(); -#endif - - int clientW,clientH; - GetClientSize(&clientW,&clientH); - - - wxString str=wxTRANS("No plots selected."); - dc->GetMultiLineTextExtent(str,&w,&h); - dc->DrawText(str,(clientW-w)/2, (clientH-h)/2); - -#ifdef __WXGTK__ - delete b; -#endif - delete dc; - - return; - - } - - //Set which plots should be visible - thePlot->hideAll(); - std::vector newVisible; - for(unsigned int ui=0;uiGetClientObject(a[ui]); - plotID = l->value; - newVisible.push_back(ui); - thePlot->setVisible(plotID,true); - } - - - - - //If the plot has changed, been resized or is performing - // 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]) - { - - //clear the plot drawing entity - if(gr) - delete gr; - - gr = new mglGraphZB(w,h); - - //change the plot by panningOneD it before we draw. - //if we need to - if(mouseDragMode==MOUSE_MODE_DRAG_PAN) - { - float xMin,xMax,yMin,yMax; - thePlot->getBounds(xMin,xMax,yMin,yMax); - - mglPoint pEnd,pStart; - pEnd = gr->CalcXYZ(draggingCurrent.x,draggingCurrent.y); - pStart = gr->CalcXYZ(draggingStart.x,draggingStart.y); - - float offX = pEnd.x-pStart.x; - - //I cannot for the life of me work out why - //this extra transformation is needed. - //but without this the code produces a scale-dependant pan speed. - offX*=xMax-xMin; - - //Modify for speed - offX*=MGL_PAN_SPEED; - - thePlot->setBounds(origPanMinX+offX/2,+origPanMaxX + offX/2.0, - yMin,yMax); - } - - //Draw the plot - thePlot->drawPlot(gr); - hasResized=false; - } - - //If the visiblity hasn't changed, then reset the - //plot to "no changes" state. Otherwise, - //swap the visibility vectors - if(lastVisible.size() == newVisible.size() && - std::equal(lastVisible.begin(),lastVisible.end(),newVisible.begin())) - thePlot->resetChange(); - else - lastVisible.swap(newVisible); - - //Copy the plot's memory buffer into a wxImage object, then draw it - wxImage img(w,h,const_cast(gr->GetBits()),true); - dc->DrawBitmap(wxBitmap(img),0,0); - - //If we are engaged in a dragging operation - //draw the nice little bits we need - //Compute the MGL coords - int axisX,axisY; - gr->CalcScr(gr->Org,&axisX,&axisY); - - switch(mouseDragMode) - { - case MOUSE_MODE_DRAG: - { - //Draw a rectangle between the start and end positions - wxCoord tlX,tlY,wRect,hRect; - - if(draggingStart.x < draggingCurrent.x) - { - tlX=draggingStart.x; - wRect = draggingCurrent.x - tlX; - } - else - { - tlX=draggingCurrent.x; - wRect = draggingStart.x - tlX; - } - - if(draggingStart.y < draggingCurrent.y) - { - tlY=draggingStart.y; - hRect = draggingCurrent.y - tlY; - } - else - { - tlY=draggingCurrent.y; - hRect = draggingStart.y - tlY; - } - - dc->SetBrush(wxBrush(*wxBLUE,wxTRANSPARENT)); - - const int END_MARKER_SIZE=5; - - //If the cursor is wholly below - //the axis, draw a line rather than abox - - unsigned int startMask, endMask; - startMask=getAxisMask(draggingStart.x, draggingStart.y); - endMask=getAxisMask(draggingCurrent.x, draggingCurrent.y); - - if( (startMask & AXIS_POSITION_LOW_X) - && (endMask & AXIS_POSITION_LOW_X) ) - { - if( !((startMask &AXIS_POSITION_LOW_Y) && (endMask & AXIS_POSITION_LOW_Y))) - { - //left of X-Axis event - //Draw a little I beam. - dc->DrawLine(draggingStart.x,tlY, - draggingStart.x,tlY+hRect); - dc->DrawLine(draggingStart.x-END_MARKER_SIZE,tlY+hRect, - draggingStart.x+END_MARKER_SIZE,tlY+hRect); - dc->DrawLine(draggingStart.x-END_MARKER_SIZE,tlY, - draggingStart.x+END_MARKER_SIZE,tlY); - } - } - else if( (startMask & AXIS_POSITION_LOW_Y) - && (endMask & AXIS_POSITION_LOW_Y) ) - { - //below Y axis event - //Draw a little |-| beam. - dc->DrawLine(tlX,draggingStart.y, - tlX+wRect,draggingStart.y); - dc->DrawLine(tlX+wRect,draggingStart.y-END_MARKER_SIZE, - tlX+wRect,draggingStart.y+END_MARKER_SIZE); - dc->DrawLine(tlX,draggingStart.y-END_MARKER_SIZE, - tlX,draggingStart.y+END_MARKER_SIZE); - - } - else - dc->DrawRectangle(tlX,tlY,wRect,hRect); - - break; - } - case MOUSE_MODE_DRAG_REGION: - { - drawRegionDraggingOverlay(dc); - break; - } - case MOUSE_MODE_DRAG_PAN: - - break; - case MOUSE_MODE_ENUM_END: - { - unsigned int axisMask; - axisMask=getAxisMask(curMouse.x,curMouse.y); - - //Draw any overlays - if(axisMask == AXIS_POSITION_INTERIOR) - drawInteractOverlay(dc); - break; - } - default: - ASSERT(false); - } - - delete dc; -} - -void MathGLPane::resized(wxSizeEvent& evt) -{ - hasResized=true; - Refresh(); -} - - -void MathGLPane::updateMouseCursor() -{ - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - - if(!w || !h || !thePlot ) - return; - - //Set cursor to normal by default - SetCursor(wxNullCursor); - if(!thePlot->getNumVisible()) - return; - - //Update mouse cursor - //--------------- - //Draw a rectangle between the start and end positions - - //If we are using shift, we slide along X axis anyway - if(wxGetKeyState(WXK_SHIFT)) - SetCursor(wxCURSOR_SIZEWE); - else - { - - //If the cursor is wholly beloe - //the axis, draw a line rather than abox - unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); - - float xMin,xMax,yMin,yMax; - - thePlot->getBounds(xMin,xMax,yMin,yMax); - //Look at mouse position relative to the axis position - //to determine the cursor style. - switch(axisMask) - { - case AXIS_POSITION_LOW_X: - //left of X-Axis event, draw up-down arrow - SetCursor(wxCURSOR_SIZENS); - break; - case AXIS_POSITION_LOW_Y: - //Below Y axis, draw line // to x axis - SetCursor(wxCURSOR_SIZEWE); - break; - case AXIS_POSITION_INTERIOR: - SetCursor(wxCURSOR_MAGNIFIER); - break; - default: - ; - } - } - //--------------- -} - -bool MathGLPane::getRegionUnderCursor(const wxPoint &mousePos, unsigned int &plotId, - unsigned int ®ionId) const -{ - ASSERT(gr); - - //Convert the mouse coordinates to data coordinates. - mglPoint pMouse= gr->CalcXYZ(mousePos.x,mousePos.y); - - - //Only allow range interaction within the plot bb - if(pMouse.x > gr->Max.x || pMouse.x < gr->Min.x) - return false; - - //check if we actually have a region - if(!thePlot->getRegionIdAtPosition(pMouse.x,pMouse.y,plotId,regionId)) - return false; - - return true; -} - - -void MathGLPane::mouseMoved(wxMouseEvent& event) -{ - leftWindow=false; - if(!thePlot || !gr || thePlot->isInteractionLocked() ) - { - mouseDragMode=MOUSE_MODE_ENUM_END; - return; - } - - curMouse=event.GetPosition(); - - switch(mouseDragMode) - { - case MOUSE_MODE_DRAG: - if(!event.m_leftDown) - mouseDragMode=MOUSE_MODE_ENUM_END; - else - draggingCurrent=event.GetPosition(); - break; - case MOUSE_MODE_DRAG_PAN: - //Can only be dragging with shift/left or middle down - // we might not receive an left up if the user - // exits the window and then releases the mouse - if(!((event.m_leftDown && event.m_shiftDown) || event.m_middleDown)) - mouseDragMode=MOUSE_MODE_ENUM_END; - else - draggingCurrent=event.GetPosition(); - break; - default: - ; - } - //Check if we are still dragging - if(!(event.m_leftDown || event.m_middleDown) || limitInteract) - mouseDragMode=MOUSE_MODE_ENUM_END; - else - draggingCurrent=event.GetPosition(); - - - updateMouseCursor(); - - Refresh(); - -} - -void MathGLPane::mouseDoubleLeftClick(wxMouseEvent& event) -{ - if(!thePlot || !gr || thePlot->isInteractionLocked()) - return; - - //Cancel any mouse drag mode - mouseDragMode=MOUSE_MODE_ENUM_END; - - int w,h; - w=0;h=0; - GetClientSize(&w,&h); - - if(!w || !h ) - return; - - unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); - - switch(axisMask) - { - case AXIS_POSITION_LOW_X: - //left of X-Axis -- plot Y zoom - thePlot->disableUserAxisBounds(false); - break; - case AXIS_POSITION_LOW_Y: - //Below Y axis; plot X Zoom - thePlot->disableUserAxisBounds(true); - break; - case AXIS_POSITION_INTERIOR: - //reset plot bounds - thePlot->disableUserBounds(); - break; - default: - //bottom corner - thePlot->disableUserBounds(); - } - - Refresh(); -} - - -void MathGLPane::oneDMouseDownAction(bool leftDown,bool middleDown, - bool alternateDown, int dragX,int dragY) -{ - ASSERT(thePlot->getNumVisible()); - - int w,h; - w=0;h=0; - - GetClientSize(&w,&h); - - float xMin,xMax,yMin,yMax; - thePlot->getBounds(xMin,xMax,yMin,yMax); - - //Set the interaction mode - if(leftDown && !alternateDown ) - { - int axisMask; - axisMask = getAxisMask(curMouse.x,curMouse.y); - - draggingStart = wxPoint(dragX,dragY); - //check to see if we have hit a region - unsigned int plotId,regionId; - if(!limitInteract && !(axisMask &(AXIS_POSITION_LOW_X | AXIS_POSITION_LOW_Y)) - && getRegionUnderCursor(curMouse,plotId,regionId)) - { - PlotRegion r; - thePlot->getRegion(plotId,regionId,r); - - //TODO: Implement a more generic region handler? - ASSERT(thePlot->plotType(plotId) == PLOT_TYPE_ONED); - - mglPoint mglDragStart = gr->CalcXYZ(draggingStart.x,draggingStart.y); - //Get the type of move, and the region - //that is being moved, as well as the plot that this - //region belongs to. - regionMoveType=computeRegionMoveType(mglDragStart.x,mglDragStart.y, r); - startMouseRegion=regionId; - startMousePlot=plotId; - mouseDragMode=MOUSE_MODE_DRAG_REGION; - } - else - mouseDragMode=MOUSE_MODE_DRAG; - - } - - - if( (leftDown && alternateDown) || middleDown) - { - mouseDragMode=MOUSE_MODE_DRAG_PAN; - draggingStart = wxPoint(dragX,dragY); - - origPanMinX=xMin; - origPanMaxX=xMax; - } - -} - -void MathGLPane::leftMouseDown(wxMouseEvent& event) -{ - if(!gr || !thePlot->getNumVisible() || !thePlot->isInteractionLocked()) - return; - - int w,h; - w=h=0; - GetClientSize(&w,&h); - if(!w || !h) - return; - - switch(thePlot->getVisibleType()) - { - case PLOT_TYPE_ONED: - oneDMouseDownAction(event.LeftDown(),false, - event.ShiftDown(), - event.GetPosition().x, - event.GetPosition().y); - break; - case PLOT_TYPE_ENUM_END: - //Do nothing - break; - default: - ASSERT(false); - } - - event.Skip(); -} - -void MathGLPane::middleMouseDown(wxMouseEvent &event) -{ - if(!gr || !thePlot->getNumVisible() || thePlot->isInteractionLocked()) - return; - - int w,h; - w=0;h=0; - GetClientSize(&w,&h); - - if(!w || !h) - return; - - switch(thePlot->getVisibleType()) - { - case PLOT_TYPE_ONED: - oneDMouseDownAction(false,event.MiddleDown(), - event.ShiftDown(), - event.GetPosition().x, - event.GetPosition().y); - break; - case PLOT_TYPE_ENUM_END: - //Do nothing - break; - default: - ASSERT(false); - } - - event.Skip(); -} - -void MathGLPane::mouseWheelMoved(wxMouseEvent& event) -{ - //If no valid plot, don't do anything - if(!thePlot || !gr || thePlot->isInteractionLocked() ) - return; - - //no action if currently dragging - if(!(mouseDragMode==MOUSE_MODE_ENUM_END)) - return; - - unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); - - - - //Bigger numbers mean faster - const float SCROLL_WHEEL_ZOOM_RATE=0.75; - float zoomRate=(float)event.GetWheelRotation()/(float)event.GetWheelDelta(); - zoomRate=zoomRate*SCROLL_WHEEL_ZOOM_RATE; - - //Convert from additive space to multiplicative - float zoomFactor; - if(zoomRate < 0.0f) - zoomFactor=-1.0f/zoomRate; - else - zoomFactor=zoomRate; - - - - ASSERT(zoomFactor >0.0f); - - - mglPoint mousePos; - mousePos=gr->CalcXYZ(curMouse.x,curMouse.y); - - float xPlotMin,xPlotMax,yPlotMin,yPlotMax; - float xMin,xMax,yMin,yMax; - //Get the current bounds for the plot - thePlot->getBounds(xMin,xMax,yMin,yMax); - //Get the absolute bounds for the plot - thePlot->scanBounds(xPlotMin,xPlotMax,yPlotMin,yPlotMax); - - - //Zoom around the point - switch(axisMask) - { - //below x axis -> y zoom only - case AXIS_POSITION_LOW_X: - { - float newYMax,newYMin; - //Zoom along Y - newYMin= mousePos.y + (yMin-mousePos.y)*zoomFactor ; - newYMax= mousePos.y + (yMax-mousePos.y)*zoomFactor ; - - newYMin=std::max(yPlotMin,newYMin); - newYMax=std::min(yPlotMax,newYMax); - - if(newYMax- newYMin> MGL_ZOOM_LIMIT) - thePlot->setBounds(xMin,xMax,newYMin,newYMax); - break; - } - //Below y axis -> x zoom only - case AXIS_POSITION_LOW_Y: - { - float newXMax,newXMin; - //Zoom along X - newXMin= mousePos.x + (xMin-mousePos.x)*zoomFactor ; - newXMax= mousePos.x + (xMax-mousePos.x)*zoomFactor ; - - newXMin=std::max(xPlotMin,newXMin); - newXMax=std::min(xPlotMax,newXMax); - - if(newXMax - newXMin > MGL_ZOOM_LIMIT) - thePlot->setBounds(newXMin,newXMax,yMin,yMax); - break; - } - //Zoom both axes - case AXIS_POSITION_INTERIOR: - { - float newXMax,newXMin; - float newYMax,newYMin; - - //Zoom along X - newXMin= mousePos.x + (xMin-mousePos.x)*zoomFactor ; - newXMax= mousePos.x + (xMax-mousePos.x)*zoomFactor ; - newYMin= mousePos.y + (yMin-mousePos.y)*zoomFactor ; - newYMax= mousePos.y + (yMax-mousePos.y)*zoomFactor ; - - - newXMin=std::max(xPlotMin,newXMin); - newXMax=std::min(xPlotMax,newXMax); - newYMin=std::max(yPlotMin,newYMin); - newYMax=std::min(yPlotMax,newYMax); - - if(newXMax - newXMin > MGL_ZOOM_LIMIT && - newYMax - newYMin > MGL_ZOOM_LIMIT) - thePlot->setBounds(newXMin,newXMax,newYMin,newYMax); - break; - } - default: - ; - } - -} - -void MathGLPane::leftMouseReleased(wxMouseEvent& event) -{ - - if(!thePlot || !gr || thePlot->isInteractionLocked() ) - return; - - switch(mouseDragMode) - { - case MOUSE_MODE_DRAG: - { - wxPoint draggingEnd = event.GetPosition(); - updateDragPos(draggingEnd); - Refresh(); - break; - } - case MOUSE_MODE_DRAG_REGION: - { - if(!limitInteract) - { - //we need to tell viscontrol that we have done a region - //update - mglPoint mglCurMouse= gr->CalcXYZ(curMouse.x,curMouse.y); - - //Send the movement to the parent filter - thePlot->moveRegion(startMousePlot, - startMouseRegion,regionMoveType,mglCurMouse.x,mglCurMouse.y); - haveUpdates=true; - - } - Refresh(); - break; - } - default: - ; - } - - mouseDragMode=MOUSE_MODE_ENUM_END; -} - -void MathGLPane::middleMouseReleased(wxMouseEvent& event) -{ - - if(!gr || thePlot->isInteractionLocked()) - return; - - if(mouseDragMode == MOUSE_MODE_DRAG_PAN) - { - mouseDragMode=MOUSE_MODE_ENUM_END; - //Repaint - Refresh(); - } -} - -void MathGLPane::updateDragPos(const wxPoint &draggingEnd) const -{ - ASSERT(mouseDragMode== MOUSE_MODE_DRAG); - - unsigned int startX, endX,startY,endY; - - int w,h; - GetSize(&w,&h); - //Define the rectangle - if(draggingEnd.x > draggingStart.x) - { - startX=draggingStart.x; - endX=draggingEnd.x; - } - else - { - startX=draggingEnd.x; - endX=draggingStart.x; - } - - if(h-draggingEnd.y > h-draggingStart.y) - { - startY=draggingStart.y; - endY=draggingEnd.y; - } - else - { - startY=draggingEnd.y; - endY=draggingStart.y; - } - - //Check that the start and end were not the same (i.e. null zoom in all cases) - if(startX == endX && startY == endY ) - return ; - - - //Compute the MGL coords - mglPoint pStart,pEnd; - pStart = gr->CalcXYZ(startX,startY); - pEnd = gr->CalcXYZ(endX,endY); - - - mglPoint cA=gr->Org; - - float currentAxisX,currentAxisY; - currentAxisX=cA.x; - currentAxisY=cA.y; - - if(pStart.x < currentAxisX && pEnd.x < currentAxisX ) - { - if(pStart.y < currentAxisY && pEnd.y < currentAxisY ) - { - //corner event - return ; // Do nothing - } - else - { - //Check if can't do anything with this, as it is a null zoom - if(startY == endY) - return; - - //left of X-Axis event - //Reset the axes such that the - //zoom is only along one dimension (y) - pStart.x = gr->Min.x; - pEnd.x = gr->Max.x; - } - } - else if(pStart.y < currentAxisY && pEnd.y < currentAxisY ) - { - //Check if can't do anything with this, as it is a null zoom - if(startX == endX) - return; - //below Y axis event - //Reset the axes such that the - //zoom is only along one dimension (x) - pStart.y = gr->Min.y; - pEnd.y = gr->Max.y; - - } - - - //now that we have the rectangle defined, - //Allow for the plot to be zoomed - // - - float minXZoom,maxXZoom,minYZoom,maxYZoom; - - minXZoom=std::min(pStart.x,pEnd.x); - maxXZoom=std::max(pStart.x,pEnd.x); - - minYZoom=std::min(pStart.y,pEnd.y); - maxYZoom=std::max(pStart.y,pEnd.y); - - - //Enforce zoom limit to avoid FP aliasing - if(maxXZoom - minXZoom > MGL_ZOOM_LIMIT && - maxYZoom - minYZoom > MGL_ZOOM_LIMIT) - { - thePlot->setBounds(minXZoom,maxXZoom, - minYZoom,maxYZoom); - } - -} - -void MathGLPane::rightClick(wxMouseEvent& event) -{ -} - -void MathGLPane::mouseLeftWindow(wxMouseEvent& event) -{ - leftWindow=true; - Refresh(); -} - -void MathGLPane::keyPressed(wxKeyEvent& event) -{ - if(!gr || thePlot->isInteractionLocked() ) - return; - updateMouseCursor(); -} - -void MathGLPane::keyReleased(wxKeyEvent& event) -{ - if(!gr || thePlot->isInteractionLocked() ) - return; - updateMouseCursor(); -} - - -unsigned int MathGLPane::savePNG(const std::string &filename, - unsigned int width, unsigned int height) -{ - - if(gr) - delete gr; - - ASSERT(filename.size()); - try - { - gr = new mglGraphZB(width,height); - } - catch(std::bad_alloc) - { - gr=0; - return MGLPANE_ERR_BADALLOC; - } - char *mglWarnMsgBuf=new char[1024]; - gr->SetWarn(0); - gr->Message=mglWarnMsgBuf; - thePlot->drawPlot(gr); - - gr->WritePNG(filename.c_str()); - if(gr->WarnCode) - { - lastMglErr=mglWarnMsgBuf; - delete[] mglWarnMsgBuf; - delete gr; - gr=0; - return MGLPANE_ERR_MGLWARN; - } - - delete[] mglWarnMsgBuf; - delete gr; - gr=0; - //Hack. mathgl does not return an error value from its writer - //function :(. Check to see that the file is openable, and nonzero sized - - ifstream f(filename.c_str(),ios::binary); - - if(!f) - return MGLPANE_FILE_REOPEN_FAIL; - - f.seekg(0,ios::end); - - - if(!f.tellg()) - return MGLPANE_FILE_UNSIZED_FAIL; - - return 0; -} - -unsigned int MathGLPane::saveSVG(const std::string &filename) -{ - ASSERT(filename.size()); - - - mglGraphPS *grS; - - //Width and height are not *really* important per se, - //since this is scale-less data. - grS = new mglGraphPS(1024,768); - - - thePlot->drawPlot(grS); - - - grS->SetWarn(0); - grS->WriteSVG(filename.c_str()); - - if(grS->WarnCode) - { - delete grS; - return MGLPANE_ERR_MGLWARN; - } - delete grS; - - //Hack. mathgl does not return an error value from its writer - //function :(. Check to see that the file is openable, and nonzero sized - - ifstream f(filename.c_str(),ios::binary); - - if(!f) - return MGLPANE_FILE_REOPEN_FAIL; - - f.seekg(0,ios::end); - - - if(!f.tellg()) - return MGLPANE_FILE_UNSIZED_FAIL; - - return 0; -} - -void MathGLPane::setPlotVisible(unsigned int plotId, bool visible) -{ - thePlot->setVisible(plotId,visible); -} - - -std::string MathGLPane::getErrString(unsigned int errCode) -{ - switch(errCode) - { - case MGLPANE_ERR_BADALLOC: - return std::string(TRANS("Unable to allocate requested memory.\n Try a lower resolution, or save as vector (SVG).")); - case MGLPANE_ERR_MGLWARN: - return std::string(TRANS("Plotting functions returned an error:\n"))+ lastMglErr; - case MGLPANE_FILE_REOPEN_FAIL: - return std::string(TRANS("File readback check failed")); - case MGLPANE_FILE_UNSIZED_FAIL: - return std::string(TRANS("Filesize during readback appears to be zero.")); - default: - ASSERT(false); - } - ASSERT(false); -} - -unsigned int MathGLPane::computeRegionMoveType(float dataX,float dataY,const PlotRegion &r) const -{ - - switch(r.bounds.size()) - { - case 1: - ASSERT(dataX >= r.bounds[0].first && dataX <=r.bounds[0].second); - //Can have 3 different aspects. Left, Centre and Right - return REGION_MOVE_EXTEND_XMINUS+(unsigned int)(3.0f*((dataX-r.bounds[0].first)/ - (r.bounds[0].second- r.bounds[0].first))); - default: - ASSERT(false); - } - - ASSERT(false); -} - -void MathGLPane::drawInteractOverlay(wxDC *dc) const -{ - - int w,h; - w=0;h=0; - GetClientSize(&w,&h); - - ASSERT(w && h); - - unsigned int regionId,plotId; - if(getRegionUnderCursor(curMouse,plotId,regionId)) - { - PlotRegion r; - thePlot->getRegion(plotId,regionId,r); - - wxPen *arrowPen; - if(limitInteract) - arrowPen= new wxPen(*wxLIGHT_GREY,2,wxSOLID); - else - arrowPen= new wxPen(*wxBLACK,2,wxSOLID); - dc->SetPen(*arrowPen); - //Use inverse drawing function so that we don't get - //black-on-black type drawing. - //Other option is to use inverse outlines. - dc->SetLogicalFunction(wxINVERT); - - const int ARROW_SIZE=8; - - - //Convert the mouse coordinates to data coordinates. - mglPoint pMouse= gr->CalcXYZ(curMouse.x,curMouse.y); - unsigned int regionMoveType=computeRegionMoveType(pMouse.x,pMouse.y,r); - - switch(regionMoveType) - { - //Left hand side of region - case REGION_MOVE_EXTEND_XMINUS: - dc->DrawLine(curMouse.x-ARROW_SIZE,h/2-ARROW_SIZE, - curMouse.x-2*ARROW_SIZE, h/2); - dc->DrawLine(curMouse.x-2*ARROW_SIZE, h/2, - curMouse.x-ARROW_SIZE,h/2+ARROW_SIZE); - break; - //right hand side of region - case REGION_MOVE_EXTEND_XPLUS: - dc->DrawLine(curMouse.x+ARROW_SIZE,h/2-ARROW_SIZE, - curMouse.x+2*ARROW_SIZE, h/2); - dc->DrawLine(curMouse.x+2*ARROW_SIZE, h/2, - curMouse.x+ARROW_SIZE,h/2+ARROW_SIZE); - break; - - //centre of region - case REGION_MOVE_TRANSLATE_X: - dc->DrawLine(curMouse.x-ARROW_SIZE,h/2-ARROW_SIZE, - curMouse.x-2*ARROW_SIZE, h/2); - dc->DrawLine(curMouse.x-2*ARROW_SIZE, h/2, - curMouse.x-ARROW_SIZE,h/2+ARROW_SIZE); - dc->DrawLine(curMouse.x+ARROW_SIZE,h/2-ARROW_SIZE, - curMouse.x+2*ARROW_SIZE, h/2); - dc->DrawLine(curMouse.x+2*ARROW_SIZE, h/2, - curMouse.x+ARROW_SIZE,h/2+ARROW_SIZE); - break; - default: - ASSERT(false); - - } - - dc->SetLogicalFunction(wxCOPY); - delete arrowPen; - } - - -} - -void MathGLPane::drawRegionDraggingOverlay(wxDC *dc) const -{ - int w,h; - w=0;h=0; - GetClientSize(&w,&h); - ASSERT(w && h); - //Well, we are dragging the region out some. - //let us draw a line from the original X position to - //the current mouse position/nearest region position - mglPoint mglCurMouse= gr->CalcXYZ(curMouse.x,curMouse.y); - - ASSERT(thePlot->plotType(startMousePlot) == PLOT_TYPE_ONED); - float regionLimitX,regionLimitY; - regionLimitX=mglCurMouse.x; - regionLimitY=mglCurMouse.y; - //See where extending the region is allowed up to. - thePlot->moveRegionLimit(startMousePlot,startMouseRegion, - regionMoveType, regionLimitX,regionLimitY); - - int deltaDrag; - mglPoint testPoint; - testPoint.x=regionLimitX; - testPoint.y=0; - int testX,testY; - gr->CalcScr(testPoint,&testX,&testY); - deltaDrag = testX-draggingStart.x; - - //Draw some text above the cursor to indicate the current position - std::string str; - stream_cast(str,regionLimitX); - wxString wxs; - wxs=wxStr(str); - wxCoord textW,textH; - dc->GetTextExtent(wxs,&textW,&textH); - - - wxPen *arrowPen; - arrowPen= new wxPen(*wxBLACK,2,wxSOLID); - - dc->SetPen(*arrowPen); - const int ARROW_SIZE=8; - - dc->SetLogicalFunction(wxINVERT); - //draw horiz line - dc->DrawLine(testX,h/2, - draggingStart.x,h/2); - if(deltaDrag > 0) - { - - dc->DrawText(wxs,testX-textW,h/2-textH*2); - //Draw arrow head to face right - dc->DrawLine(testX,h/2, - testX-ARROW_SIZE, h/2-ARROW_SIZE); - dc->DrawLine(testX, h/2, - testX-ARROW_SIZE,h/2+ARROW_SIZE); - - } - else - { - dc->DrawText(wxs,testX,h/2-textH*2); - //Draw arrow head to face left - dc->DrawLine(testX,h/2, - testX+ARROW_SIZE, h/2-ARROW_SIZE); - dc->DrawLine(testX, h/2, - testX+ARROW_SIZE,h/2+ARROW_SIZE); - } - - - switch(regionMoveType) - { - case REGION_MOVE_EXTEND_XMINUS: - case REGION_MOVE_EXTEND_XPLUS: - //No extra markers; we are cool as is - break; - case REGION_MOVE_TRANSLATE_X: - { - //This needs to be extended to suppport more - //plot types. - ASSERT(thePlot->plotType(startMousePlot) == PLOT_TYPE_ONED); - - //Draw "ghost" limits markers for move, - //these appear as moving vertical bars to outline - //where the translation result will be for both - //upper and lower - PlotRegion reg; - thePlot->getRegion(startMousePlot,startMouseRegion,reg); - mglPoint mglDragStart = gr->CalcXYZ(draggingStart.x,draggingStart.y); - - float newLower,newUpper; - newLower = reg.bounds[0].first + (mglCurMouse.x-mglDragStart.x); - newUpper = reg.bounds[0].second + (mglCurMouse.x-mglDragStart.x); - - int newLowerX,newUpperX,dummy; - gr->CalcScr(mglPoint(newLower,0.0f),&newLowerX,&dummy); - gr->CalcScr(mglPoint(newUpper,0.0f),&newUpperX,&dummy); - - dc->DrawLine(newLowerX,h/2+2*ARROW_SIZE,newLowerX,h/2-2*ARROW_SIZE); - dc->DrawLine(newUpperX,h/2+2*ARROW_SIZE,newUpperX,h/2-2*ARROW_SIZE); - break; - } - default: - ASSERT(false); - break; - } - - dc->SetLogicalFunction(wxCOPY); - delete arrowPen; - -} -/* -void MathGLPane::drawActionHintOverlay(wxDC *dc) -{ - const char *overlays[] = { - "mouse-shift-pan.png", - "mousewheel-zoom.png", - "mousewheel-zoom-x.png", - "mousewheel-zoom-y.png", - "mousewheel-pan.png", - "axis-zoom-x.png", - "axis-zoom-y.png", - }; - - //Axis mask on current position - //required in order for overlay - //to be displayed. 0 means show always - const int overlayAxisMask ={ - 0, - 0, - AXIS_POSITION_LOW_X, - AXIS_POSITION_LOW_Y, - 0, - AXIS_POSITION_LOW_X, - AXIS_POSITION_LOW_Y - }; - - - unsigned int axisMask=getAxisMask(curMouse.x,curMouse.y); - - - vector overlaysToDraw; - overlaysToDraw.resize(NUM_OVERLAYS); - - //find the overlays that need to be drawn, according to their mask - for(unsigned int ui=0;ui > coords; - for(unsigned int ui=0;ui. -*/ - - -#include "plot.h" - -#include -#undef is_nan - -#include -#ifndef MATHGLPANE_H -#define MATHGLPANE_H - -// begin wxGlade: ::extracode -// end wxGlade - -//Error codes -enum -{ - MGLPANE_ERR_BADALLOC=1, - MGLPANE_ERR_MGLWARN, - MGLPANE_FILE_REOPEN_FAIL, - MGLPANE_FILE_UNSIZED_FAIL, - MGLPANE_ERRMAX, -}; - - -class MathGLPane: public wxPanel { -private: - //Current mouse position - wxPoint curMouse; - //!Has the mouse left the window? - bool leftWindow; - //!Last error reported by mathgl - std::string lastMglErr; - //!What is the user currently doing with the mouse? - unsigned int mouseDragMode; - - //!Has the window resized since the last draw? - bool hasResized; - //!Start and currentlocations for the drag - wxPoint draggingStart,draggingCurrent; - //!Original bounds during panning operations. - float origPanMinX, origPanMaxX; //1D and 2D actions - - //!region used at mouse down - unsigned int startMouseRegion,startMousePlot,regionMoveType; - - //!Do we have region updates? - bool haveUpdates; - - //!Should we be limiting interaction to - //things that won't modify filters (eg region dragging) - bool limitInteract; - - //!Pointer to the plot data holding class - PlotWrapper *thePlot; - //!Pointer to the listbox that is used for plot selection - wxListBox *plotSelList; - //!Pointer to the mathgl renderer - mglGraphZB *gr; - //!Caching check vector for plot visibility - std::vector lastVisible; - - //!Update the mouse cursor style, based upon mouse position - void updateMouseCursor(); - - //!Compute the "aspect" for a given region; ie which grab handle type - // does this position correspond to - unsigned int computeRegionMoveType(float dataX,float dataY, const PlotRegion &r) const; - - //!Draw the interaction overlay objects - // like the ability to drag etc. - void drawInteractOverlay(wxDC *dc) const; - - //Draw the region Overlays (dragging arrows, bounds etc) - void drawRegionDraggingOverlay(wxDC *dc) const; - - // - void updateDragPos(const wxPoint &event) const; - - //Get the bitmask for the cursor position (below/above axis) from - //the specified window coordinates (use LH window coordinates, as from wx) - unsigned int getAxisMask(int x, int y) const ; - - //Action to perform when showing 1D plots and mouse down event occurs - void oneDMouseDownAction(bool leftDown,bool middleMouseDown, - bool alternateDown, int dragX,int dragY); -public: - - MathGLPane(wxWindow* parent, int id); - virtual ~MathGLPane(); - - //Set the plot pointer for this class to manipulate - void setPlotWrapper(PlotWrapper *plots); - //!Set the plot listbox for this class to use - void setPlotList(wxListBox *box){plotSelList=box;}; - - std::string getErrString(unsigned int code); - - //save an SVG file - unsigned int saveSVG(const std::string &filename); - //Save a PNG file - unsigned int savePNG(const std::string &filename, - unsigned int width,unsigned int height); - //Get the number of visible plots - unsigned int getNumVisible() const {return thePlot->getNumVisible();}; - - //!Get the region under the cursor. Returns region num [0->...) or - //numeric_limits::max() if nothing. - bool getRegionUnderCursor(const wxPoint &mousePos, unsigned int &plotId, unsigned int ®ionId) const; - - //!Do we have updates? - bool hasUpdates() const { return haveUpdates;} - //Instruct the plot that we no loger have updates available. - void clearUpdates() { haveUpdates=false;} - //Resize event for window - void resized(wxSizeEvent& evt); - //Draw window event - void render(wxPaintEvent& evt); - //!wx Event that triggers on mouse movement on grah - void mouseMoved(wxMouseEvent& event); - //Left mouse depress on window - void middleMouseDown(wxMouseEvent& event); - //Right mouse depress on window - void leftMouseDown(wxMouseEvent& event); - //Mouse doubleclick on window - void mouseDoubleLeftClick(wxMouseEvent& event); - //Mousewheel Scroll event - void mouseWheelMoved(wxMouseEvent& event); - //Button being released inside box - void leftMouseReleased(wxMouseEvent& event); - //! Middle mouse button has been let go - void middleMouseReleased(wxMouseEvent& event); - //Right button down-release - void rightClick(wxMouseEvent& event); - //Button leaving client area - void mouseLeftWindow(wxMouseEvent& event); - void keyPressed(wxKeyEvent& event); - void keyReleased(wxKeyEvent& event); - //Select, by ID, which plot we would like to set to being shown - void setPlotVisible(unsigned int plotID, bool visible); - //Show/hide legent - void setLegendVisible(bool visible){thePlot->setLegendVisible(visible);} - //Prevent the user from interacting with the plot - void limitInteraction(bool doLimit=true){ limitInteract=doLimit;}; -protected: - DECLARE_EVENT_TABLE() -}; - - - -#endif diff -Nru 3depict-0.0.12/src/plot.cpp 3depict-0.0.13/src/plot.cpp --- 3depict-0.0.12/src/plot.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/plot.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1413 +0,0 @@ -/* - * plot.cpp - mathgl plot wrapper class - * Copyright (C) 2012, 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 . -*/ - - -#include "basics.h" -#include "plot.h" - - -#include "translation.h" - - -#include -#include -#ifndef ASSERT - #define ASSERT(f) -#endif - -//Uncomment me if using MGL >=1_10 to -//enable plot cutting and colouring -#define MGL_GTE_1_10 - -//!Plot error bar estimation strings -const char *errModeStrings[] = { - NTRANS("None"), - NTRANS("Moving avg.") - }; - -const char *plotModeStrings[]= { - NTRANS("Lines"), - NTRANS("Bars"), - NTRANS("Steps"), - NTRANS("Stem"), - NTRANS("Points") - }; - -using std::string; -using std::pair; -using std::vector; - - -//Axis min/max bounding box is disallowed to be exactly zero on any given axis -// perform a little "push off" by this fudge factor -const float AXIS_MIN_TOLERANCE=10*sqrtf(std::numeric_limits::epsilon()); - -int MGLColourFixer::maxCols=-1; - -void MGLColourFixer::reset() -{ - rs.clear(); - gs.clear(); - bs.clear(); -} - -char MGLColourFixer::haveExactColour(float r, float g, float b) const -{ - ASSERT(rs.size() == gs.size()) - ASSERT(gs.size() == bs.size()) - - ASSERT(rs.size() <=getMaxColours()); - - for(unsigned int ui=0; ui::epsilon() - && fabs(g-gs[ui]) ::epsilon() - && fabs(b-bs[ui]) ::epsilon()) - return mglColorIds[ui+1].id; //Add one to offset to avoid the reserved "k" - } - - return 0; -} - -unsigned int MGLColourFixer::getMaxColours() -{ - //Used cached value if available - if(maxCols!=-1) - return maxCols; - - //The array is statically defined in - //mgl/mgl_main.cpp, and must end with an id of zero. - // - //this is not documented at all. - maxCols=0; - while(mglColorIds[maxCols].id) - maxCols++; - - return maxCols; -} - -char MGLColourFixer::getNextBestColour(float r, float g, float b) -{ - ASSERT(rs.size() == gs.size()); - ASSERT(gs.size() == bs.size()); - - - //As a special case, mgl has its own black - if(r == 0.0f && g == 0.0f && b == 0.0f) - return mglColorIds[0].id; - - - ASSERT(graph); - unsigned int best=0; - if(rs.size() == getMaxColours()) - { - ASSERT(getMaxColours()); - //Looks like we ran out of pallete colours. - //lets just give up and try to match this against our existing colours - - //TODO: let this modify the existing pallette - // to find a better match. - float distanceSqr=std::numeric_limits::max(); - for(unsigned int ui=0; uiSetPalColor(best,r,g,b); - mglColorIds[best].col = mglColor(r,g,b); - - rs.push_back(r); - gs.push_back(g); - bs.push_back(b); - } - - ASSERT(mglColorIds[best].id != 'k'); - return mglColorIds[best].id; -} - -//Mathgl uses some internal for(float=...) constructions, -// which are just generally a bad idea, as they often won't terminate -// as the precision is not guaranteed. Try to catch these by detecting this -bool mglFloatTooClose(float a, float b) -{ - //For small numbers an absolute delta can catch - // too close values - if(fabs(a-b) < sqrt(std::numeric_limits::epsilon())) - return true; - - const int FLOAT_ACC_MASK=0xffff0000; - union FLT_INT - { - float f; - int i; - }; - FLT_INT u; - u.f=a; - //For big numbers, we have to either bit-bash, or something - u.i&=FLOAT_ACC_MASK; - a=u.f; - - u.f=b; - u.i&=FLOAT_ACC_MASK; - b=u.f; - - if(fabs(a-b) < sqrt(std::numeric_limits::epsilon())) - return true; - - return false; -} - - -//Nasty string conversion functions. -std::wstring strToWStr(const std::string& s) -{ - std::wstring temp(s.length(),L' '); - std::copy(s.begin(), s.end(), temp.begin()); - return temp; -} - -std::string wstrToStr(const std::wstring& s) -{ - std::string temp(s.length(), ' '); - std::copy(s.begin(), s.end(), temp.begin()); - return temp; -} - - -//TODO: Refactor these functions to use a common string map -//----------- -string plotString(unsigned int traceType) -{ - ASSERT(traceType< PLOT_TRACE_ENDOFENUM); - return TRANS(plotModeStrings[traceType]); -} - -unsigned int plotID(const std::string &plotString) -{ - for(unsigned int ui=0;ui &x, const std::vector &y, - std::vector &errBars, const PLOT_ERROR &errMode) -{ - switch(errMode.mode) - { - case PLOT_ERROR_NONE: - return; - case PLOT_ERROR_MOVING_AVERAGE: - { - ASSERT(errMode.movingAverageNum); - errBars.resize(y.size()); - for(int ui=0;uivisible && plottingData[ui]->parentObject) - { - lastVisiblePlots.push_back(std::make_pair(plottingData[ui]->parentObject, - plottingData[ui]->parentPlotIndex)); - } - } - } - else - applyUserBounds=false; - - - //Free the plotting data pointers - for(size_t ui=0;uixLabel = strToWStr(x); - plottingData[plotPos]->yLabel = strToWStr(y); - - plottingData[plotPos]->title = strToWStr(t); - plotChanged=true; -} - -void PlotWrapper::setParentData(unsigned int plotID, const void *parentObj, unsigned int idx) -{ - unsigned int plotPos=plotIDHandler.getPos(plotID); - plottingData[plotPos]->parentObject= parentObj; - plottingData[plotPos]->parentPlotIndex=idx; - - plotChanged=true; -} - -void PlotWrapper::setTraceStyle(unsigned int plotUniqueID,unsigned int mode) -{ - - ASSERT(modetraceType=mode; - plotChanged=true; -} - -void PlotWrapper::setColours(unsigned int plotUniqueID, float rN,float gN,float bN) -{ - unsigned int plotPos=plotIDHandler.getPos(plotUniqueID); - plottingData[plotPos]->r=rN; - plottingData[plotPos]->g=gN; - plottingData[plotPos]->b=bN; - plotChanged=true; -} - -void PlotWrapper::setBounds(float xMin, float xMax, - float yMin,float yMax) -{ - ASSERT(!interactionLocked); - - ASSERT(xMin::epsilon() && - fabs(yUserMin -yMin)<=std::numeric_limits::epsilon()) - { - applyUserBounds=false; - } - - plotChanged=true; -} - -void PlotWrapper::getBounds(float &xMin, float &xMax, - float &yMin,float &yMax) const -{ - if(applyUserBounds) - { - xMin=xUserMin; - yMin=yUserMin; - xMax=xUserMax; - yMax=yUserMax; - } - else - scanBounds(xMin,xMax,yMin,yMax); - - ASSERT(xMin ::max(); - xMax=-std::numeric_limits::max(); - yMin=std::numeric_limits::max(); - yMax=-std::numeric_limits::max(); - - for(unsigned int uj=0;ujvisible) - continue; - - //Expand our bounding box to encompass that of this visible plot - float tmpXMin,tmpXMax,tmpYMin,tmpYMax; - plottingData[uj]->getBounds(tmpXMin,tmpXMax,tmpYMin,tmpYMax); - - xMin=std::min(xMin,tmpXMin); - xMax=std::max(xMax,tmpXMax); - yMin=std::min(yMin,tmpYMin); - yMax=std::max(yMax,tmpYMax); - - } - - ASSERT(xMin < xMax && yMin <=yMax); -} - -void PlotWrapper::bestEffortRestoreVisibility() -{ - //Try to match up the last visible plots to the - //new plots. Use index and owner as guiding data - - for(unsigned int uj=0;ujvisible=false; - - for(unsigned int ui=0; uiparentObject == lastVisiblePlots[ui].first - && plottingData[uj]->parentPlotIndex == lastVisiblePlots[ui].second) - { - plottingData[uj]->visible=true; - break; - } - - } - } - - lastVisiblePlots.clear(); - plotChanged=true; -} - -void PlotWrapper::getRawData(vector > > &data, - std::vector > &labels) const -{ - if(plottingData.empty()) - return; - - //Determine if we have multiple types of plot. - //if so, we cannot really return the raw data for this - //in a meaningful fashion - switch(getVisibleType()) - { - case PLOT_TYPE_ONED: - { - //Try to retrieve the raw data from the visible plots - for(unsigned int ui=0;uivisible) - { - vector > thisDat,dummy; - vector thisLabel; - plottingData[ui]->getRawData(thisDat,thisLabel); - - //Data title size should hopefully be the same - //as the label size - ASSERT(thisLabel.size() == thisDat.size()); - - if(thisDat.size()) - { - data.push_back(dummy); - data.back().swap(thisDat); - - labels.push_back(thisLabel); - } - } - } - break; - } - case PLOT_TYPE_ENUM_END: - return; - default: - ASSERT(false); - } -} - -unsigned int PlotWrapper::getVisibleType() const -{ - unsigned int visibleType=PLOT_TYPE_ENUM_END; - for(unsigned int ui=0;uivisible && - plottingData[ui]->plotType!= visibleType) - { - if(visibleType == PLOT_TYPE_ENUM_END) - { - visibleType=plottingData[ui]->plotType; - continue; - } - else - { - visibleType=PLOT_TYPE_MIXED; - break; - } - } - } - - return visibleType; -} - -void PlotWrapper::drawPlot(mglGraph *gr) const -{ - unsigned int visType = getVisibleType(); - if(visType == PLOT_TYPE_ENUM_END || - visType == PLOT_TYPE_MIXED) - { - //We don't handle the drawing case well here, so assert this. - // calling code should check this case and ensure that it draws something - // meaningful - ASSERT(false); - return; - } - - //Un-fudger for mathgl plots - MGLColourFixer colourFixer; - colourFixer.setGraph(gr); - - bool haveMultiTitles=false; - float minX,maxX,minY,maxY; - minX=std::numeric_limits::max(); - maxX=-std::numeric_limits::max(); - minY=std::numeric_limits::max(); - maxY=-std::numeric_limits::max(); - - //Compute the bounding box in data coordinates - std::wstring xLabel,yLabel,plotTitle; - - for(unsigned int ui=0;uivisible) - { - - 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); - - - if(!xLabel.size()) - xLabel=plottingData[ui]->xLabel; - else - { - - if(xLabel!=plottingData[ui]->xLabel) - xLabel=stlStrToStlWStr(TRANS("Multiple data types")); - } - if(!yLabel.size()) - yLabel=plottingData[ui]->yLabel; - else - { - - if(yLabel!=plottingData[ui]->yLabel) - yLabel=stlStrToStlWStr(TRANS("Multiple data types")); - } - if(!haveMultiTitles && !plotTitle.size()) - plotTitle=plottingData[ui]->title; - else - { - - if(plotTitle!=plottingData[ui]->title) - { - plotTitle=L"";//L prefix means wide char - haveMultiTitles=true; - } - } - - - } - } - - - - string sX,sY; - sX.assign(xLabel.begin(),xLabel.end()); //unicode conversion - sY.assign(yLabel.begin(),yLabel.end()); //unicode conversion - - string sT; - sT.assign(plotTitle.begin(), plotTitle.end()); //unicode conversion - gr->Title(sT.c_str()); - - - switch(visType) - { - case PLOT_TYPE_ONED: - { - //OneD connected value line plot f(x) - bool useLogPlot=false; - bool notLog=false; - - - for(unsigned int ui=0;uivisible) - { - if(((Plot1D*)plottingData[ui])->wantLogPlot()) - useLogPlot=true; - else - notLog=true; - } - } - - //work out the bounding box for the plot, - //and where the axis should cross - mglPoint axisCross; - mglPoint min,max; - if(applyUserBounds) - { - ASSERT(yUserMax >=yUserMin); - ASSERT(xUserMax >=xUserMin); - - max.x =xUserMax; - max.y=yUserMax; - - min.x =xUserMin; - min.y =yUserMin; - - axisCross.x=min.x; - axisCross.y=min.y; - - } - else - { - //Retreive the bounds of the data that is in the plot - - min.x=minX; - min.y=minY; - max.x=maxX; - - if(useLogPlot && maxY > 0.0f) - max.y =log10(maxY); - else - max.y=maxY; - - axisCross.x = minX; - axisCross.y=min.y; - - gr->Org=axisCross; - } - - //"Push" bounds around to prevent min == max - // This is a hack to prevent mathgl from inf. looping - //--- - if(mglFloatTooClose(min.x , max.x)) - { - min.x-=5; - max.x+=5; - } - - if(mglFloatTooClose(min.y , max.y)) - max.y+=1; - //------ - - //tell mathgl about the bounding box - gr->Axis(min,max,axisCross); - - WARN((fabs(min.x-max.x) > sqrt(std::numeric_limits::epsilon())), - "WARNING: Mgl limits (X) too Close! Due to limitiations in MGL, This may inf. loop!"); - WARN((fabs(min.y-max.y) > sqrt(std::numeric_limits::epsilon())), - "WARNING: Mgl limits (Y) too Close! Due to limitiations in MGL, This may inf. loop!"); - - gr->AdjustTicks("x"); - gr->SetXTT("%g"); //Set the tick type - gr->Axis("xy"); //Build an X-Y crossing axis - //--- - - //Loop through the plots, drawing them as needed - for(unsigned int ui=0;uivisible) - continue; - - - curPlot->drawRegions(gr,colourFixer,min,max); - curPlot->drawPlot(gr,colourFixer); - - if(drawLegend) - { - //Fake an mgl colour code - char colourCode[2]; - colourCode[0]=colourFixer.getNextBestColour( - curPlot->r,curPlot->g,curPlot->b); - colourCode[1]='\0'; - gr->AddLegend(curPlot->title.c_str(),colourCode); - } - } - - //Prevent mathgl from dropping lines that straddle the plot bound. - gr->SetCut(false); - - if(useLogPlot && !notLog) - sY = string("\\log_{10}(") + sY + ")"; - else if (useLogPlot && notLog) - { - sY = string(TRANS("Mixed log/non-log:")) + sY ; - } - - break; - } - default: - ASSERT(false); - } - - - gr->Label('x',sX.c_str()); - gr->Label('y',sY.c_str(),0); - - if(haveMultiTitles) - { -#ifdef MGL_GTE_1_10 - gr->SetLegendBox(false); -#endif - //I have NO idea what this size value is about, - //I just kept changing the number until it looked nice. - //the library default is -0.85 (why negative??) - const float LEGEND_SIZE=-1.1f; - - //Legend at top right (0x3), in default font "rL" at specified size - gr->Legend(0x3,"rL",LEGEND_SIZE); - } - -} - -void PlotWrapper::hideAll() -{ - for(unsigned int ui=0;uivisible=false; - plotChanged=true; -} - -void PlotWrapper::setVisible(unsigned int uniqueID, bool setVis) -{ - unsigned int plotPos = plotIDHandler.getPos(uniqueID); - - plottingData[plotPos]->visible=setVis; - plotChanged=true; -} - -bool PlotWrapper::getRegionIdAtPosition(float x, float y, unsigned int &pId, unsigned int &rId) const -{ - for(size_t ui=0;uivisible) - continue; - - if(plottingData[ui]->getRegionIdAtPosition(x,y,rId)) - { - pId=ui; - return true; - } - } - - return false; -} - -unsigned int PlotWrapper::getNumVisible() const -{ - unsigned int num=0; - for(unsigned int ui=0;uivisible) - num++; - } - - - return num; -} - -bool PlotWrapper::isPlotVisible(unsigned int plotID) const -{ - return plottingData[plotIDHandler.getPos(plotID)]->visible; -} - -void PlotWrapper::getRegion(unsigned int plotId, unsigned int regionId, PlotRegion ®ion) const -{ - plottingData[plotIDHandler.getPos(plotId)]->getRegion(regionId,region); -} - -unsigned int PlotWrapper::plotType(unsigned int plotId) const -{ - return plottingData[plotIDHandler.getPos(plotId)]->plotType; -} - - -void PlotWrapper::moveRegionLimit(unsigned int plotId, unsigned int regionId, - unsigned int movementType, float &constrainX, float &constrainY) const -{ - plottingData[plotIDHandler.getPos(plotId)]->moveRegionLimit( - regionId,movementType,constrainX,constrainY); -} - - -void PlotWrapper::moveRegion(unsigned int plotID, unsigned int regionId, unsigned int movementType, - float newX, float newY) const -{ - plottingData[plotIDHandler.getPos(plotID)]->moveRegion(regionId,movementType,newX,newY); -} -//----------- - - -Plot1D::Plot1D() -{ - //Set the default plot properties - visible=(true); - traceType=PLOT_TRACE_LINES; - plotType=PLOT_TYPE_ONED; - xLabel=(strToWStr("")); - yLabel=(strToWStr("")); - title=(strToWStr("")); - r=(0);g=(0);b=(1); -} - -void Plot1D::setData(const vector &vX, const vector &vY, - const vector &vErr) -{ - - ASSERT(vX.size() == vY.size()); - ASSERT(vErr.size() == vY.size() || !vErr.size()); - - - //Fill up vectors with data - xValues.resize(vX.size()); - std::copy(vX.begin(),vX.end(),xValues.begin()); - yValues.resize(vY.size()); - std::copy(vY.begin(),vY.end(),yValues.begin()); - - errBars.resize(vErr.size()); - std::copy(vErr.begin(),vErr.end(),errBars.begin()); - - //Compute minima and maxima of plot data, and keep a copy of it - float maxThis=-std::numeric_limits::max(); - float minThis=std::numeric_limits::max(); - for(unsigned int ui=0;ui::max(); - minThis=std::numeric_limits::max(); - for(unsigned int ui=0;ui > &v) -{ - vector dummyVar; - - setData(v,dummyVar); - -} -void Plot1D::setData(const vector > &v,const vector &vErr) -{ - //Fill up vectors with data - xValues.resize(v.size()); - yValues.resize(v.size()); - for(unsigned int ui=0;ui::max(); - float minThis=std::numeric_limits::max(); - for(unsigned int ui=0;ui::max(); - minThis=std::numeric_limits::max(); - if(vErr.size()) - { - ASSERT(vErr.size() == v.size()); - for(unsigned int ui=0;ui 0.0) - bufferY[uj] = log10(yValues[uj]); - else - bufferY[uj] = 0; - - } - } - else - { - for(unsigned int uj=0;ujSetCut(true); - - gr->Plot(xDat,yDat,colourCode); - if(showErrs) - gr->Error(xDat,yDat,eDat,colourCode); - gr->SetCut(false); -#else - gr->Plot(xDat,yDat); -#endif - break; - case PLOT_TRACE_BARS: -#if !defined(__WIN32) && !defined(__WIN64) -#ifdef MGL_GTE_1_10 - gr->Bars(xDat,yDat,colourCode); -#else - gr->Bars(xDat,yDat); -#endif -#endif - - break; - case PLOT_TRACE_STEPS: - //Same problem as for line plot. -#ifdef MGL_GTE_1_10 - gr->SetCut(true); - gr->Step(xDat,yDat,colourCode); - gr->SetCut(false); -#else - gr->Step(xDat,yDat); -#endif - break; - case PLOT_TRACE_STEM: -#ifdef MGL_GTE_1_10 - gr->Stem(xDat,yDat,colourCode); -#else - gr->Stem(xDat,yDat); -#endif - break; - - case PLOT_TRACE_POINTS: - { -#ifdef MGL_GTE_1_10 - std::string s; - s = colourCode; - //Mathgl uses strings to manipulate line styles - s+=" "; - //space means "no line" - s+="x"; //x shaped point markers - - gr->SetCut(true); - - gr->Plot(xDat,yDat,s.c_str()); - if(showErrs) - gr->Error(xDat,yDat,eDat,s.c_str()); - gr->SetCut(false); -#else - gr->Plot(xDat,yDat," x"); -#endif - break; - } - default: - ASSERT(false); - break; - } - - delete[] bufferX; - delete[] bufferY; - if(showErrs) - delete[] bufferErr; - - - -} - - -void Plot1D::addRegion(unsigned int parentPlot,unsigned int regionID,float start, float end, - float rNew, float gNew, float bNew, Filter *parentFilter) -{ - ASSERT(start =0.0 && rNew <= 1.0); - ASSERT( gNew>=0.0 && gNew <= 1.0); - ASSERT( bNew>=0.0 && bNew <= 1.0); - - PlotRegion region; - //1D plots only have one bounding direction - region.bounds.push_back(std::make_pair(start,end)); - region.boundAxis.push_back(0); // the bounding direction is along the X axis - region.parentFilter = parentFilter; - - //Set the ID and create a unique ID (one that is invariant if regions are added or removed) - //for the region - region.id = regionID; - region.uniqueID = regionIDHandler.genId(regions.size()); - - region.r=rNew; - region.g=gNew; - region.b=bNew; - - regions.push_back(region); -} - -//---- - -void Plot1D::getRawData(std::vector > &rawData, - std::vector &labels) const -{ - - vector tmp,dummy; - - tmp.resize(xValues.size()); - std::copy(xValues.begin(),xValues.end(),tmp.begin()); - rawData.push_back(dummy); - rawData.back().swap(tmp); - - tmp.resize(yValues.size()); - std::copy(yValues.begin(),yValues.end(),tmp.begin()); - rawData.push_back(dummy); - rawData.back().swap(tmp); - - labels.push_back(xLabel); - if(titleAsRawDataLabel) - labels.push_back(title); - else - labels.push_back(yLabel); - - - if(errBars.size()) - { - tmp.resize(errBars.size()); - std::copy(errBars.begin(),errBars.end(),tmp.begin()); - - rawData.push_back(dummy); - rawData.back().swap(tmp); - labels.push_back(stlStrToStlWStr(TRANS("error"))); - } -} - - -void Plot1D::moveRegionLimit(unsigned int regionID, - unsigned int method, float &newPosX, float &newPosY) const -{ - - unsigned int region=regionIDHandler.getPos(regionID); - - ASSERT(region mean) - - { - //Disallow hitting other bounds - for(unsigned int ui=0; ui mean && ui != region) ) - newPosX=std::min(newPosX,regions[ui].bounds[0].first); - } - newPosX=std::max(newPosX,xMin); - } - else - { - //Disallow hitting other bounds - for(unsigned int ui=0; ui mean && ui != region)) - newPosX=std::min(newPosX,regions[ui].bounds[0].first); - } - //Dont allow past self left - newPosX=std::max(newPosX,regions[region].bounds[0].first); - //Dont extend outside plot - newPosX=std::min(newPosX,xMax); - break; - default: - ASSERT(false); - } - -} - - -void Plot1D::moveRegion(unsigned int regionID, unsigned int method, float newPosX,float newPosY) const -{ - //Well, we should have called this externally to determine location - //let us confirm that this is the case - moveRegionLimit(regionID,method,newPosX,newPosY); - - - unsigned int region=regionIDHandler.getPos(regionID); - ASSERT(regions[region].parentFilter); - - //Pass the filter ID value stored in the region to the filter, along with the new - //value to take for that filter ID - regions[region].parentFilter->setPropFromRegion(method,regions[region].id,newPosX); - -} - - -void Plot1D::drawRegions(mglGraph *gr,MGLColourFixer &fixer, - const mglPoint &min,const mglPoint &max) const -{ - //Mathgl pallette colour name - char colourCode[2]; - colourCode[1]='\0'; - - for(unsigned int uj=0;uj rMinX && rMaxY > rMinY) - { - colourCode[0] = fixer.getNextBestColour(regions[uj].r, - regions[uj].g,regions[uj].b); - colourCode[1] = '\0'; - gr->FaceZ(rMinX,rMinY,-1,rMaxX-rMinX,rMaxY-rMinY, - colourCode); - - } - } -} - - -void Plot1D::clear( bool preserveVisiblity) -{ - regions.clear(); - regionIDHandler.clear(); -} - -bool Plot1D::getRegionIdAtPosition(float x, float y, unsigned int &id) const -{ - for(unsigned int ui=0;ui x ) - { - id=ui; - return true; - } - } - - - return false; -} - -void Plot1D::getRegion(unsigned int id, PlotRegion &r) const -{ - r = regions[regionIDHandler.getPos(id)]; -} - - diff -Nru 3depict-0.0.12/src/plot.h 3depict-0.0.13/src/plot.h --- 3depict-0.0.12/src/plot.h 2012-11-18 10:53:26.000000000 +0000 +++ 3depict-0.0.13/src/plot.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,399 +0,0 @@ -/* - * plot.h - plotting wraper for mathgl - * Copyright (C) 2012, 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 . -*/ - -#ifndef PLOT_H -#define PLOT_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "filter.h" - - -#if defined(WIN32) || defined(WIN64) - //Help mathgl out a bit: we don't need the GSL on this platform - #define NO_GSL -#endif - - - -#include - -//mathgl shadows std::isnan -#undef isnan - - -#include "basics.h" - - - -enum -{ - PLOT_TYPE_ONED, - PLOT_TYPE_MIXED, - PLOT_TYPE_ENUM_END //not a plot, just end of enum -}; - - - - -//!Return a human readable string for a given plot type -std::string plotString(unsigned int traceType); - -//!Return a human readable string for the plot error mode -std::string plotErrmodeString(unsigned int errMode); - -//!Return the plot type given a human readable string -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 -class MGLColourFixer -{ - private: - vector rs,gs,bs; - static int maxCols; - mglGraph *graph; - public: - void setGraph(mglGraph *g) { graph=g;}; - //Restore the MGL colour strings - void reset(); - //Return the exact colour, if there is one - char haveExactColour(float r, float g, float b) const; - //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 - char getNextBestColour(float r, float g, float b); - - static unsigned int getMaxColours(); -}; - -//!Data class for holding info about non-overlapping -// interactive rectilinear "zones" overlaid on plots -class PlotRegion -{ - public: - //Axis along which bounds are set. Each entry is unique - vector boundAxis; - //Bounding limits for axial bind - vector > bounds; - - //Bounding region colour - float r,g,b; - //The parent filter, so region can tell who the parent is - Filter *parentFilter; - //The ID value for this region, used when interacting with parent filter - unsigned int id; - //!Unique ID for region across entire multiplot - unsigned int uniqueID; -}; - -//!Base class for data plotting -class PlotBase -{ - public: - PlotBase(){}; - virtual ~PlotBase(){}; - //The type of plot (ie what class is it?) - unsigned int plotType; - - //!Bounding box for plot - may exceed plot data area - float minX,maxX,minY,maxY; - - //!Colour of trace - float r,g,b; - //!Is trace visible? - bool visible; - //!Type of plot (lines, bars, sticks, etc) - unsigned int traceType; - //!xaxis label - std::wstring xLabel; - //!y axis label - std::wstring yLabel; - //!Plot title - std::wstring title; - - //!Use the plot title for Y data label when exporting raw data - // (true), or use the yLabel - bool titleAsRawDataLabel; - - //!Pointer to some constant object that generated this plot - const void *parentObject; - - //!Interactive, or otherwise marked plot regions - vector regions; - //ID handler for regions - UniqueIDHandler regionIDHandler; - - //!integer to show which of the n plots that the parent generated - //that this data is represented by - unsigned int parentPlotIndex; - - //Draw the plot onto a given MGL graph - virtual void drawPlot(mglGraph *graph, MGLColourFixer &fixer) const=0; - - //!Scan for the data bounds. - virtual void getBounds(float &xMin,float &xMax, - float &yMin,float &yMax) const = 0; - - //Retrieve the raw data associated with this plot. - virtual void getRawData(vector > &f, - std::vector &labels) const=0; - - //!Retrieve the ID of the non-overlapping region in X-Y space - virtual bool getRegionIdAtPosition(float x, float y, unsigned int &id) const=0; - //!Retrieve a region using its unique ID - virtual void getRegion(unsigned int id, PlotRegion &r) const=0; - - //!Get the number of regions; - size_t getNumRegions() const { return regions.size();}; - - //!Pass the region movement information to the parent filter object - virtual void moveRegion(unsigned int regionId, unsigned int method, - float newX, float newY) const=0; - - //!Obtain limit of motion for a given region movement type - virtual void moveRegionLimit(unsigned int regionId, - unsigned int movementType, float &maxX, float &maxY) const=0; - -}; - -//!1D Function f(x) Plot with ranges -// data must be a pure Function. -class Plot1D : public PlotBase -{ - private: - - //!Should plot logarithm (+1) of data? Be careful of -ve values. - bool logarithmic; - //!Data - std::vector xValues,yValues,errBars; - - - public: - Plot1D(); - - - void getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const; - - //!Set the plot data from a pair and symmetric Y error - void setData(const vector > &v); - void setData(const vector > &v,const vector &symYErr); - //!Set the plot data from two vectors and symmetric Y error - void setData(const vector &vX, const vector &vY); - void setData(const vector &vX, const vector &vY, - const vector &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); - - //!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) - float moveRegionTest(unsigned int region, unsigned int method, float newPos) const; - - //!Move a region to a new location. MUST call moveRegionTest first. - void moveRegion(unsigned int region, unsigned int method, float newPos); - - void clear(bool preserveVisibility); - - - //Draw the plot onto a given MGL graph - virtual void drawPlot(mglGraph *graph,MGLColourFixer &fixer) const; - - //Draw the associated regions - void drawRegions(mglGraph *graph, MGLColourFixer &fixer, - const mglPoint &min, const mglPoint &max) const; - - - //!Retrieve the raw data associated with the currently visible plots. - //note that this is the FULL data not the zoomed data for the current user bounds - void getRawData(std::vector > &rawData, - std::vector &labels) const; - - //!Retrieve the ID of the non-overlapping region in X-Y space - bool getRegionIdAtPosition(float x, float y, unsigned int &id) const; - - //!Retrieve a region using its unique ID - void getRegion(unsigned int id, PlotRegion &r) const; - - //!Pass the region movement information to the parent filter object - void moveRegion(unsigned int regionId, unsigned int method, float newX, float newY) const; - - //Get the region motion limits, to ensure that the selected region does not - //overlap after a move operation. Note that the output variables will only - //be set for the appropriate motion direction. Eg, an X only move will not - //set limitY. - void moveRegionLimit(unsigned int regionId, - unsigned int movementType, float &limitX, float &limitY) const; - - bool wantLogPlot() const { return logarithmic;}; - void setLogarithmic(bool p){logarithmic=p;}; -}; - -//Wrapper class for containing multiple plots -class PlotWrapper -{ - protected: - //!Has the plot changed since we last rendered it? - bool plotChanged; - //!Elements of the plot - std::vector plottingData; - - //!which plots were last visible? - std::vector > lastVisiblePlots; - - //Position independant ID handling for the - //plots inserted into the vector - UniqueIDHandler plotIDHandler; - - - //!Use user-specified bounding values? - bool applyUserBounds; - //!User mininum bounds - float xUserMin,yUserMin; - //!User maximum bounds - float xUserMax,yUserMax; - - //!Switch to enable or disable drawing of the plot legend - bool drawLegend; - - //!is user interaction with the plot supposed to be locked? - // - is used to ensure that when updating plot, UI control - // will be hinted to take correct action - bool interactionLocked; - - public: - //!Constructor - PlotWrapper(); - - //!Destructor must delete target plots - ~PlotWrapper(); - - - bool isInteractionLocked() const { return interactionLocked;}; - - void lockInteraction(bool lock=true) {interactionLocked=lock;}; - - //!Has the contents of the plot changed since the last call to resetChange? - bool hasChanged() const { return plotChanged;}; - - void resetChange() { plotChanged=false;} - - //!Erase all the plot data - void clear(bool preserveVisibility=false); - - //!Hide all plots (sets all visibility to false) - void hideAll(); - - //!Set the visibilty of a plot, based upon its uniqueID - void setVisible(unsigned int uniqueID, bool isVisible=true); - - //!Get the bounds for the plot - void scanBounds(float &xMin,float &xMax,float &yMin,float &yMax) const; - //Draw the plot onto a given MGL graph. Only one type (1D,2D etc) of plot may be visible - void drawPlot(mglGraph *graph) const; - - //!Set the X Y and title strings - void setStrings(unsigned int plotID, - const char *x, const char *y, const char *t); - void setStrings(unsigned int plotID,const std::string &x, - const std::string &y,const std::string &t); - //!Set the parent information for a given plot - void setParentData(unsigned int plotID, - const void *parentObj, unsigned int plotIndex); - - //!Set the plotting mode. - void setTraceStyle(unsigned int plotID,unsigned int mode); - - //!Set the plot colours - void setColours(unsigned int plotID, float rN,float gN,float bN); - //!Set the bounds on the plot - void setBounds(float xMin, float xMax, - float yMin,float yMax); - //!Get the bounds for the plot - void getBounds(float &xMin, float &xMax, - float &yMin,float &yMax) const; - //!Automatically use the data limits to compute bounds - void resetBounds(); - - - //!Get the number of visible plots - unsigned int getNumVisible() const; - - //!Returns true if plot is visible, based upon its uniqueID. - bool isPlotVisible(unsigned int plotID) const; - - //!Disable user bounds - void disableUserBounds(){plotChanged=true;applyUserBounds=false;}; - - //!Disable user axis bounds along one axis only - void disableUserAxisBounds(bool xAxis); - - //!Do our best to restore the visibility of the plot to what it was - //before the last clear based upon the plot data owner information. - //Note that this will erase the last stored visibility data when complete. - void bestEffortRestoreVisibility(); - - - //!Set whether to enable the legend or not - void setLegendVisible(bool vis) { drawLegend=vis;plotChanged=true;}; - - //!Add a plot to the list of available plots. Control of the pointer becomes - //transferred to this class, so do *NOT* delete it after calling this function - unsigned int addPlot(PlotBase *plot); - - //!Get the ID (return value) and the contents of the plot region at the given position. - // Returns false if no region can be found, and true if valid region found - bool getRegionIdAtPosition(float px, float py, - unsigned int &plotId, unsigned int ®ionID ) const; - - - //Return the region data for the given regionID/plotID combo - void getRegion(unsigned int plotId, unsigned int regionId, PlotRegion &r) const; - - //!Retrieve the raw data associated with the selected plots. - void getRawData(vector > > &data, std::vector > &labels) const; - - - //!obtain the type of a plot, given the plot's uniqueID - unsigned int plotType(unsigned int plotId) const; - - //Retrieve the types of visible plots - unsigned int getVisibleType() const; - - //!Obtain limit of motion for a given region movement type - void moveRegionLimit(unsigned int plotId, unsigned int regionId, - unsigned int movementType, float &maxX, float &maxY) const; - - //!Pass the region movement information to the parent filter object - void moveRegion(unsigned int plotID, unsigned int regionId, unsigned int movementType, - float newX, float newY) const; -}; - -#endif diff -Nru 3depict-0.0.12/src/pngread.c 3depict-0.0.13/src/pngread.c --- 3depict-0.0.12/src/pngread.c 2012-11-11 19:54:31.000000000 +0000 +++ 3depict-0.0.13/src/pngread.c 2013-03-22 18:31:39.000000000 +0000 @@ -21,6 +21,8 @@ #include "pngread.h" +#include + int check_if_png(const char *file_name, FILE **fp, unsigned int bytes_to_check) { char buf[bytes_to_check]; diff -Nru 3depict-0.0.12/src/pngread.h 3depict-0.0.13/src/pngread.h --- 3depict-0.0.12/src/pngread.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/pngread.h 2013-03-22 18:31:39.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (C) 2002 Thomas Schumm - * Modifications 2011 D Haley + * Modifications 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 @@ -25,7 +25,6 @@ #include -#include #ifndef PNG_LIBPNG_VER #error Requires libpng! diff -Nru 3depict-0.0.12/src/rdf.cpp 3depict-0.0.13/src/rdf.cpp --- 3depict-0.0.12/src/rdf.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/rdf.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,757 +0,0 @@ - /* - * rdf.cpp - Radial distribution function implentation - * 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 - * 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 . - */ - -#include "rdf.h" -#include "mathfuncs.h" - -#include - -using std::vector; -#ifdef DEBUG -#include -#include -using std::cerr; -using std::endl; -#endif - -#ifdef _OPENMP -#include -#endif -//QHull library -//Build fix for qhull ; wx defines powerpc without -//assigning a value, causing build fail on powerpc -#ifdef __POWERPC__ - #pragma push_macro("__POWERPC__") - #define __POWERPC__ 1 -#endif -extern "C" -{ - #include -} -#ifdef __POWERPC__ - #pragma pop_macro("__POWERPC__") -#endif - -const unsigned int CALLBACK_REDUCE=5000; - -enum PointDir{ POINTDIR_TOGETHER =0, - POINTDIR_IN_COMMON, - POINTDIR_APART - }; -//!Check which way vectors attached to two 3D points "point", -/*! Two vectors may point "together", /__\ "apart" \__/ or - * "In common" /__/ or \__\ - */ -unsigned int vectorPointDir(const Point3D &pA, const Point3D &pB, - const Point3D &vC, const Point3D &vD) -{ - //Check which way vectors attached to two 3D points "point", - // - "together", "apart" or "in common" - - //calculate AB.CA, BA.DB - float dot1 = (pB-pA).dotProd(vC - pA); - float dot2= (pA - pB).dotProd(vD - pB); - - //We shall somehwat arbitrarily call perpendicular cases "together" - if(dot1 ==0.0f || dot2 == 0.0f) - return POINTDIR_TOGETHER; - - //If they have opposite signs, then they are "in common" - if(( dot1 < 0.0f && dot2 > 0.0f) || (dot1 > 0.0f && dot2 < 0.0f) ) - return POINTDIR_IN_COMMON; - - if( dot1 < 0.0f && dot2 <0.0f ) - return POINTDIR_APART; - - ASSERT(dot1 > 0.0f && dot2 > 0.0f ); - - return POINTDIR_TOGETHER; -} - -//! Returns the shortest distance between a line segment and a given point -/* The inputs are the ends of the line segment and the point. Uses the formula that - * \f$ - * D = \abs{\vec{PE}}\f$ - * \f[ - * \mathrm{~if~} \vec{PA} \cdot \vec{AB} > 0 - * \rightarrow \vec{PE} = \vec{A} - * \f] - * \f[ - * \mathrm{~if~} \vec{AB} \cdot \vec{PB} > 0 ~\&~ \vec{PA} \cdot \vec{AB} < 0 - * \rightarrow \vec{PB} \cdot \frac{\vec{AB}}{\abs{\vec{AB}}} - * \f] - * \f[ - * \mathrm{~if~} \vec{PB} \cdot \vec{AB} < 0 - * \rightarrow \vec{B} - * \f] - */ -float distanceToSegment(const Point3D &fA, const Point3D &fB, const Point3D &p) -{ - - //If the vectors ar pointing "together" then use point-line formula - if(vectorPointDir(fA,fB,p,p) == POINTDIR_TOGETHER) - { - Point3D closestPt; - Point3D vAB= fB-fA; - - //Use formula d^2 = |(B-A)(cross)(A-P)|^2/|B-A|^2 - return sqrtf( (vAB.crossProd(fA-p)).sqrMag()/(vAB.sqrMag())); - } - - return sqrtf( std::min(fB.sqrDist(p), fA.sqrDist(p)) ); -} - - -//!Find the distance between a point, and a triangular facet -- may be positive or negative -/* The inputs are the facet points (ABC) and the point P. - * distance is shortest using standard plane version - * \f$ D = \vec{AB} \cdot \vec{n} \f$ - * iff dot products to each combination of \f$ \left( AP,BP,CP \right) \leq 0 \f$ - * otherwise closest point is on the boundary of the simplex. - * tested by shortest distance to each line segment (E is shortest pt. AB is line segement) - * \f$ \vec{E} = \frac{\vec{AB}}{|\vec{AB}|} - * ( \vec{PB} \cdot \vec{AB})\f$ - */ -float distanceToFacet(const Point3D &fA, const Point3D &fB, - const Point3D &fC, const Point3D &p, const Point3D &normal) -{ - - //This will check the magnitude of the incoming normal - ASSERT( fabs(sqrtf(normal.sqrMag()) - 1.0f) < 2.0* std::numeric_limits::epsilon()); - unsigned int pointDir[3]; - pointDir[0] = vectorPointDir(fA,fB,p,p); - pointDir[1] = vectorPointDir(fA,fC,p,p); - pointDir[2] = vectorPointDir(fB,fC,p,p); - - //They can never be "APART" if the - //vectors point to the same pt - ASSERT(pointDir[0] != POINTDIR_APART); - ASSERT(pointDir[1] != POINTDIR_APART); - ASSERT(pointDir[2] != POINTDIR_APART); - - //Check to see if any of them are "in common" - if(pointDir[0] > 0 || pointDir[1] >0 || pointDir[2] > 0) - { - //if so, we have to check each edge for its closest point - //then pick the best - float bestDist[3]; - bestDist[0] = distanceToSegment(fA,fB,p); - bestDist[1] = distanceToSegment(fA,fC,p); - bestDist[2] = distanceToSegment(fB,fC,p); - - - return std::min(bestDist[0],std::min(bestDist[1],bestDist[2])); - } - - float temp; - - temp = fabs((p-fA).dotProd(normal)); - - //check that the other points were not better than this! - ASSERT(sqrtf(fA.sqrDist(p)) >= temp - std::numeric_limits::epsilon()); - ASSERT(sqrtf(fB.sqrDist(p)) >= temp - std::numeric_limits::epsilon()); - ASSERT(sqrtf(fC.sqrDist(p)) >= temp - std::numeric_limits::epsilon()); - - //Point lies above/below facet, use plane formula - return temp; -} - - -//A bigger MAX_NN_DISTS is better because you will attempt to grab more ram -//however there is a chance that memory allocation can fail, which currently i do not grab safely -const unsigned int MAX_NN_DISTS = 0x8000000; //96 MB samples at a time - - - -//obtains all the input points from ions that lie inside the convex hull after -//it has been shrunk such that the closest distance from the hull to the original data -//is reductionDim -unsigned int GetReducedHullPts(const vector &points, float reductionDim, vector &pointResult) -{ - const int dim=3; - - //TODO: This could be made to use a fixed amount of ram, by - //partitioning the input points, and then - //computing multiple hulls. - //Take the resultant hull points, then hull again. This would be - //much more space efficient, and more easily parallellised - //Alternately, compute a for a randoms K set of points, and reject - //points that lie in the hull from further computation - - - //First we must construct the hull - double *buffer = new double[points.size()*3]; -#pragma omp parallel for - for(unsigned int ui=0; ui as needed - vertexT *vertex = qh vertex_list; - - //obtain convex hull points & mass centroid - Point3D midPoint(0.0f,0.0f,0.0f); - unsigned int numPoints=0; - while(vertex != qh vertex_tail) - { - //aggregate points - midPoint+=Point3D(vertex->point[0], - vertex->point[1], - vertex->point[2]); - vertex = vertex->next; - numPoints++; - } - - //do division to obtain average (midpoint) - midPoint *= 1.0f/(float)numPoints; -#ifdef DEBUG - cerr << "MidPoint " << midPoint << endl; -#endif - //Now we will find the mass/volume centroid of the hull - //by constructing sets of pyramids - //where the faces of the hull are the bases of - //pyramids, and the midpoint is the apex - Point3D hullCentroid(0.0f,0.0f,0.0f); - float massPyramids=0.0f; - //Run through the faced list - facetT *curFac = qh facet_list; - - while(curFac != qh facet_tail) - { - vertexT *vertex; - Point3D pyramidCentroid; - unsigned int ui; - Point3D ptArray[3]; - float vol; - - //find the pyramid volume + centroid - pyramidCentroid = midPoint; - ui=0; - - //This assertion fails, some more processing is needed to be done to break - //the facet into something simplical - ASSERT(curFac->simplicial); - vertex = (vertexT *)curFac->vertices->e[ui].p; - while(vertex) - { //copy the vertex info into the pt array - (ptArray[ui])[0] = vertex->point[0]; - (ptArray[ui])[1] = vertex->point[1]; - (ptArray[ui])[2] = vertex->point[2]; - - //aggregate pyramidal points - pyramidCentroid += ptArray[ui]; - - //increment before updating vertex - //to allow checking for NULL termination - ui++; - vertex = (vertexT *)curFac->vertices->e[ui].p; - - } - - //note that this counter has been post incremented. - ASSERT(ui ==3); - vol = pyramidVol(ptArray,midPoint); - - ASSERT(vol>=0); - - //Find the midpoint of the pyramid, this will be the - //same as its centre of mass. - pyramidCentroid*= 0.25f; - hullCentroid = hullCentroid + (pyramidCentroid*vol); - massPyramids+=vol; - - curFac=curFac->next; - } -#ifdef DEBUG - cerr << "Total \"Mass\" of pyramids:" << massPyramids << endl; -#endif - - hullCentroid *= 1.0f/massPyramids; -#ifdef DEBUG - cerr << "Mass Centroid :" << hullCentroid[0] << "," << hullCentroid[1] << "," << - hullCentroid[2] << endl; -#endif - float minDist=std::numeric_limits::max(); - //find the smallest distance between the centroid and the - //convex hull - curFac=qh facet_list; - while(curFac != qh facet_tail) - { - float temp; - vertexT *vertex; - Point3D vertexPt[3]; - - //The shortest distance from the plane to the point - //is the dot product of the UNIT normal with - //A-B, where B is on plane, A is point in question - for(unsigned int ui=0; ui<3; ui++) - { - //grab vertex - vertex = ((vertexT *)curFac->vertices->e[ui].p); - vertexPt[ui] = Point3D(vertex->point[0],vertex->point[1],vertex->point[2]); - } - - //Find the distance between hullcentroid and a given facet - temp = distanceToFacet(vertexPt[0],vertexPt[1],vertexPt[2],hullCentroid, - Point3D(curFac->normal[0],curFac->normal[1],curFac->normal[2])); - - if(temp < minDist) - minDist = temp; - - curFac=curFac->next; - } - - //shrink the convex hull such that it lies at - //least reductionDim from the original surface of - //the convex hull - float scaleFactor; - scaleFactor = 1 - reductionDim/ minDist; - - if(scaleFactor < 0.0f) - return RDF_ERR_NEGATIVE_SCALE_FACT; - - -#ifdef DEBUG - cerr << "Scale Factor : " << scaleFactor << endl; -#endif - - //now scan through the input points and see if they - //lie in the reduced convex hull - vertex = qh vertex_list; - - //find the bounding cube for the scaled convex hull such that we can quickly - //discount points without examining the entire hull - vector vecHullPts; - vecHullPts.resize(qh num_vertices); - unsigned int ui=0; - while(vertex !=qh vertex_tail) - { - //Translate around hullCentroid before scaling, - //then undo translation after scale - //Modify the vertex data such that it is scaled around the hullCentroid - vertex->point[0] = (vertex->point[0] - hullCentroid[0])*scaleFactor + hullCentroid[0]; - vertex->point[1] = (vertex->point[1] - hullCentroid[1])*scaleFactor + hullCentroid[1]; - vertex->point[2] = (vertex->point[2] - hullCentroid[2])*scaleFactor + hullCentroid[2]; - - vecHullPts[ui]=Point3D(vertex->point[0], - vertex->point[1], - vertex->point[2]); - - vertex = vertex->next; - ui++; - } - - vecHullPts.clear(); -#ifdef DEBUG - cerr << "Num Facets: " << qh num_facets << endl; -#endif - //if the dot product of the normal with the point vector of the - //considered point P, to any vertex on all of the facets of the - //convex hull F1, F2, ... , Fn is negative, - //then P does NOT lie inside the convex hull. - pointResult.reserve(points.size()/2); - curFac = qh facet_list; - - //minimum distance from centroid to convex hull - for(unsigned int ui=points.size(); ui--;) - { - float fX,fY,fZ; - double *ptArr,*normalArr; - fX =points[ui][0]; - fY = points[ui][1]; - fZ = points[ui][2]; - - //loop through the facets - curFac = qh facet_list; - while(curFac != qh facet_tail) - { - //Dont ask. It just grabs the first coords of the vertex - //associated with this facet - ptArr = ((vertexT *)curFac->vertices->e[0].p)->point; - - normalArr = curFac->normal; - //if the dotproduct is negative, then the point vector from the - //point in queston to the surface is in opposite to the outwards facing - //normal, which means the point lies outside the hull - if (dotProduct( (float)ptArr[0] - fX, - (float)ptArr[1] - fY, - (float)ptArr[2] - fZ, - normalArr[0], normalArr[1], - normalArr[2]) >= 0) - { - curFac=curFac->next; - continue; - } - goto reduced_loop_next; - } - //we passed all tests, point is inside convex hull - pointResult.push_back(points[ui]); - -reduced_loop_next: - ; - } - - return 0; -} - -//!Generate an NN histogram using NN-max cutoffs -unsigned int generateNNHist( const vector &pointList, - const K3DTree &tree,unsigned int nnMax, unsigned int numBins, - vector > &histogram, float *binWidth , unsigned int *progressPtr, - bool (*callback)(bool)) -{ - if(pointList.size() <=nnMax) - return RDF_ERR_INSUFFICIENT_INPUT_POINTS; - - //Disallow exact matching for NNs - float deadDistSqr; - deadDistSqr= std::numeric_limits::epsilon(); - - //calclate NNs - BoundCube cube; - cube.setBounds(pointList); - - //Allocate and assign the initial max distances - float *maxSqrDist= new float[nnMax]; - for(unsigned int ui=0; ui nnPoints; - tree.findKNearest(pointList[ui],cube, - nnMax,nnPoints,deadDistSqr); - - - - for(unsigned int uj=0; ujsqrDist(pointList[ui]); - if(temp > maxSqrDist[uj]) - maxSqrDist[uj] = temp; - } - - - //Callbacks to perform UI updates as needed - if(!(callbackReduce--)) - { -#ifdef _OPENMP - #pragma omp critical - { - numAnalysed+=CALLBACK_REDUCE; - *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); - if(!(*callback)(false)) - spin=true; - } -#else - *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*100.0f); - if(!(*callback)(false)) - { - delete[] maxSqrDist; - return RDF_ABORT_FAIL; - } -#endif - callbackReduce=CALLBACK_REDUCE; - } - - } -#ifdef _OPENMP - if(spin) - { - delete[] maxSqrDist; - return RDF_ABORT_FAIL; - } -#endif - - - float maxOfMaxDists=0; - float *maxDist=new float[nnMax]; - for(unsigned int ui=0; ui nnPoints; - unsigned int offsetTemp; - float temp; -#ifdef _OPENMP - if(spin) - continue; -#endif - - tree.findKNearest(pointList[ui],cube, - nnMax, nnPoints); - - for(unsigned int uj=0; ujsqrDist(pointList[ui])); - offsetTemp = (unsigned int)(temp/binWidth[uj]); - - //Prevent overflow due to temp/binWidth exceeding array dimension - //as (temp is <= binwidth, not < binWidth) - if(offsetTemp == numBins) - offsetTemp--; - ASSERT(offsetTemp < nnMax*numBins); - - (histogram[uj])[offsetTemp]++; - } - - - //Callbacks to perform UI updates as needed -#ifdef _OPENMP - if(!(callbackReduce--)) - { - #pragma omp critical - { - *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); - if(!(*callback)(false)) - spin=true; - numAnalysed+=CALLBACK_REDUCE; - } - callbackReduce=CALLBACK_REDUCE; - } -#else - if(!(callbackReduce--)) - { - *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*100.0f); - if(!(*callback)(false)) - { - delete[] maxSqrDist; - return RDF_ABORT_FAIL; - } - callbackReduce=CALLBACK_REDUCE; - } -#endif - } - - - delete[] maxSqrDist; - return 0; -} - - -//!Generate an NN histogram using distance max cutoffs. Input histogram must be zeroed, -unsigned int generateDistHist(const vector &pointList, const K3DTree &tree, - unsigned int *histogram, float distMax, - unsigned int numBins, unsigned int &warnBiasCount, - unsigned int *progressPtr,bool (*callback)(bool)) - -{ - - -#ifdef DEBUG - for(unsigned int ui=0;ui epsilon - deadDistSqr=std::numeric_limits::epsilon(); - sqrDist=0; - sourcePoint=pointList[ui]; - while(deadDistSqr < maxSqrDist) - { - - //Grab the nearest point - nearPt = tree.findNearest(sourcePoint, cube, - deadDistSqr); - - if(nearPt) - { - //Cacluate the sq of the distance to the point - sqrDist = nearPt->sqrDist(sourcePoint); - - //if sqrDist is = maxSqrdist then this will cause - //the histogram indexing to trash alternate memory - //- this is bad - prevent this please. - if(sqrDist < maxSqrDist) - { - //Add the point to the histogram -#ifdef _OPENMP - threadHist[(size_t) ((sqrtf(sqrDist/maxSqrDist)*(float)numBins))] [omp_get_thread_num()]++; -#else - histogram[(size_t)((sqrtf(sqrDist/maxSqrDist)*(float)numBins))]++; -#endif - } - - //increase the dead distance to the last distance - deadDistSqr = sqrDist+std::numeric_limits::epsilon(); - } - else - { - //Oh no, we had a problem, somehow we couldn't find enough -#pragma omp critical - warnBiasCount++; - break; - } - - - if(!(callbackReduce--)) - { -#ifdef _OPENMP - #pragma omp critical - { - numAnalysed+=numAnalysedThread; - *progressPtr= (unsigned int)((float)(numAnalysed)/((float)pointList.size())*100.0f); - if(!(*callback)(false)) - spin=true; - } - if(spin) - break; - numAnalysedThread=0; -#else - *progressPtr= (unsigned int)((float)(ui)/((float)pointList.size())*100.0f); - if(!(*callback)(false)) - return RDF_ABORT_FAIL; -#endif - callbackReduce=CALLBACK_REDUCE; - } - } -#ifdef _OPENMP - numAnalysedThread++; -#endif - } - -#ifdef _OPENMP - if(spin) - return RDF_ABORT_FAIL; - - for (size_t i = 0; i < numBins; i++) - { - for (size_t j = 0; j < omp_get_max_threads(); j++) - histogram[i] += threadHist[i][j]; - } -#endif - - //Calculations complete! - return 0; -} diff -Nru 3depict-0.0.12/src/rdf.h 3depict-0.0.13/src/rdf.h --- 3depict-0.0.12/src/rdf.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/rdf.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * rdf.h - Radial distribution function implementation header - * 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 - * 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 . - */ - -#ifndef RDF_H -#define RDF_H - -#include "K3DTree.h" - -#include -#include - -//RDF error codes -enum -{ - RDF_ERR_NEGATIVE_SCALE_FACT, - RDF_ERR_INSUFFICIENT_INPUT_POINTS, - RDF_FILE_OPEN_FAIL, - RDF_ABORT_FAIL -}; - -//!Generate the NN histogram specified up to a given NN -unsigned int generateNNHist( const std::vector &pointList, - const K3DTree &tree,unsigned int nnMax, unsigned int numBins, - std::vector > &histogram, float *binWidth, - unsigned int *progressPtr,bool (*callback)(bool)); - -//!Generate an NN histogram using distance max cutoffs. Input histogram must be zeroed, -//if a voxelsname is given, a 3D RDF will be recorded. in this case voxelBins must be nonzero -unsigned int generateDistHist(const std::vector &pointList, const K3DTree &tree, - unsigned int *histogram, float distMax, - unsigned int numBins, unsigned int &warnBiasCount, - unsigned int *progressPtr,bool (*callback)(bool)); - -//!Returns a subset of points guaranteed to lie at least reductionDim inside hull of input points -/*! Calculates the hull of the input ions and then scales the hull such that the - * smallest distance between the scaled hull and the original hull is exactly - * reductionDim - */ -unsigned int GetReducedHullPts(const std::vector &pts, float reductionDim,std::vector &returnIons ); - -#endif diff -Nru 3depict-0.0.12/src/scene.cpp 3depict-0.0.13/src/scene.cpp --- 3depict-0.0.12/src/scene.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/scene.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1015 +0,0 @@ -/* - * scene.cpp - OpenGL 3D static scene implementation - * Copyright (C) 2012, 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 . -*/ - -#include "scene.h" - -#include - - -using std::vector; - -Scene::Scene() : tempCam(0), activeCam(0), cameraSet(false), outWinAspect(1.0f), r(0.0f), g(0.0f), b(0.0f) -{ - lastHovered=lastSelected=(unsigned int)(-1); - lockInteract=false; - hoverMode=selectionMode=false; - viewRestrict=false; - useAlpha=true; - useLighting=true; - useEffects=false; - showAxis=true; - - //default to black - rBack=gBack=bBack=0.0f; - -} - -Scene::~Scene() -{ - clearAll(); -} - -unsigned int Scene::initDraw() -{ - glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT); - - if(useAlpha) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); - - glDisable(GL_LIGHTING); - //Set up the scene lights - //== - //Set up default lighting - const float light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; - const float light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; - const float light_specular[] = { 0.0, 0.0, 0.0, 0.0 }; - float light_position[] = { 1.0, 1.0, 1.0, 0.0 }; - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position); - - - - - glDisable(GL_LIGHTING); - //== - - //Use the active if set - if(cameraSet) - { - if(!boundCube.isValid()) - computeSceneLimits(); - - } - - - - //Let the effects objects know about the scene - Effect::setBoundingCube(boundCube); - - unsigned int passes=1; - - if(useEffects) - { - for(unsigned int ui=0;uinumPassesNeeded()); - } - - return passes; -} - -void Scene::updateCam(const Camera *camToUse) const -{ - Point3D lightNormal; - - - glLoadIdentity(); - //If viewport restriction is on, inform camera to - //shrink viewport to specified region - if(viewRestrict) - { - camToUse->apply(outWinAspect,boundCube,true, - viewRestrictStart[0],viewRestrictEnd[0], - viewRestrictStart[1],viewRestrictEnd[1]); - } - else - camToUse->apply(outWinAspect,boundCube); - - lightNormal=camToUse->getViewDirection(); - glNormal3f(lightNormal[0],lightNormal[1],lightNormal[2]); - -} - -void Scene::draw() -{ - - glPushMatrix(); - - - Camera *camToUse; - if(tempCam) - camToUse=tempCam; - else - { - ASSERT(activeCam < cameras.size()); - camToUse=cameras[activeCam]; - } - //Inform text about current camera, so it can billboard if needed - DrawableObj::setCurCamera(camToUse); - Effect::setCurCam(camToUse); - - - bool lightsOn=false; - unsigned int numberTotalPasses; - numberTotalPasses=initDraw(); - - unsigned int passNumber=0; - - if(cameraSet) - updateCam(camToUse); - - - - bool needCamUpdate=false; - while(passNumber < numberTotalPasses) - { - - if(useEffects) - { - for(unsigned int ui=0;uienable(passNumber); - needCamUpdate|=effects[ui]->needCamUpdate(); - } - - if(cameraSet && needCamUpdate) - { - glLoadIdentity(); - updateCam(camToUse); - } - } - - - if(showAxis) - { - if(useLighting) - glEnable(GL_LIGHTING); - DrawAxis a; - a.setStyle(AXIS_IN_SPACE); - a.setSize(boundCube.getLargestDim()); - a.setPosition(boundCube.getCentroid()); - - a.draw(); - if(useLighting) - glDisable(GL_LIGHTING); - } - - - //First sub-pass with opaque objects - //----------- - //Draw the referenced objects - drawObjectVector(refObjects,lightsOn,true); - //Draw normal objects - drawObjectVector(objects,lightsOn,true); - //----------- - - //Second pass with transparent objects - //----------- - //Draw the referenced objects - drawObjectVector(refObjects,lightsOn,false); - //Draw normal objects - drawObjectVector(objects,lightsOn,false); - //----------- - - - glFlush(); - passNumber++; - } - - - //Disable effects - if(useEffects) - { - //Disable them in reverse order to simulate a stack-type - //behaviour. - for(unsigned int ui=effects.size();ui!=0;) - { - ui--; - effects[ui]->disable(); - } - } - - - glPopMatrix(); - - //Now draw 2D overlays - if(!lockInteract&& lastHovered != (unsigned int)(-1) ) - drawHoverOverlay(); - drawOverlays(); - -} - -void Scene::drawObjectVector(const vector &drawObjs, bool &lightsOn, bool drawOpaques) const -{ - for(unsigned int ui=0; uineedsDepthSorting() == drawOpaques) - continue; - - //overlays need to be drawn later - if(drawObjs[ui]->isOverlay()) - continue; - - if(useLighting) - { - if(!drawObjs[ui]->wantsLight && lightsOn ) - { - //Object prefers doing its thing in the dark - glDisable(GL_LIGHTING); - lightsOn=false; - } - else if (drawObjs[ui]->wantsLight && !lightsOn) - { - glEnable(GL_LIGHTING); - lightsOn=true; - } - } - - //If we are in selection mode, draw the bounding box - //if the object is selected. - if(ui == lastSelected && selectionMode) - { - //May be required for selection box drawing - BoundCube bObject; - DrawRectPrism p; - //Get the bounding box for the object & draw it - drawObjs[ui]->getBoundingBox(bObject); - p.setAxisAligned(bObject); - p.setColour(0,0.2,1,0.5); //blue-greenish - if(lightsOn) - glDisable(GL_LIGHTING); - p.draw(); - if(lightsOn) - glEnable(GL_LIGHTING); - - } - - drawObjs[ui]->draw(); - } -} - -void Scene::drawOverlays() const -{ - - //Custom projection matrix - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glDisable(GL_LIGHTING); - //Set the opengl camera state back into modelview mode - if(viewRestrict) - { - - //FIXME: How does the aspect ratio fit in here? - gluOrtho2D(viewRestrictStart[0], - viewRestrictEnd[0], - viewRestrictStart[0], - viewRestrictStart[1]); - } - else - gluOrtho2D(0, outWinAspect, 1.0, 0); - - - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glDisable(GL_DEPTH_TEST); - - - for(unsigned int ui=0;uiisOverlay()) - refObjects[ui]->draw(); - } - - for(unsigned int ui=0;uiisOverlay()) - objects[ui]->draw(); - } - - - glEnable(GL_DEPTH_TEST); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); -} - -void Scene::drawHoverOverlay() -{ - - glEnable(GL_ALPHA_TEST); - glDisable(GL_DEPTH_TEST); - //Search for a binding - bool haveBinding; - haveBinding=false; - - //Prevent transparent areas from interactiing - //with the depth buffer - glAlphaFunc(GL_GREATER,0.01f); - - vector binder; - for(unsigned int uj=0;ujgetAvailBindings(objects[lastHovered],binder)) - { - haveBinding=true; - break; - } - } - - - if(haveBinding) - { - glPushAttrib(GL_LIGHTING); - glDisable(GL_LIGHTING); - - //Now draw some hints for the binding itself as a 2D overlay - // - //Draw the action type (translation, rotation etc) - //and the button it is bound to - DrawTexturedQuadOverlay binderIcons,mouseIcons,keyIcons; - - - 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; - for(unsigned int ui=0;uigetInteractionMode()) - { - case BIND_MODE_FLOAT_SCALE: - case BIND_MODE_FLOAT_TRANSLATE: - case BIND_MODE_POINT3D_SCALE: - foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_ENLARGE]); - break; - case BIND_MODE_POINT3D_TRANSLATE: - foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_TRANSLATE]); - break; - case BIND_MODE_POINT3D_ROTATE: - case BIND_MODE_POINT3D_ROTATE_LOCK: - foundIconTex=binderIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_ROTATE]); - default: - break; - } - - //Draw the mouse action - switch(binder[ui]->getMouseButtons()) - { - case SELECT_BUTTON_LEFT: - foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_LEFT_CLICK]); - break; - case SELECT_BUTTON_MIDDLE: - foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_MIDDLE_CLICK]); - break; - case SELECT_BUTTON_RIGHT: - foundMouseTex=mouseIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_RIGHT_CLICK]); - break; - default: - //The flags are or'd together, so we can get other combinations - break; - } - - bool foundKeyTex; - foundKeyTex=false; - //Draw the keyboard action, if any - switch(binder[ui]->getKeyFlags()) - { - case FLAG_CMD: -#ifdef __APPLE__ - foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_COMMAND]); -#else - foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_CTRL]); -#endif - break; - case FLAG_SHIFT: - foundKeyTex=keyIcons.setTexture(TEST_OVERLAY_PNG[TEXTURE_SHIFT]); - break; - default: - //The flags are or'd together, so we can get other combinations - break; - } - - if(foundIconTex && foundMouseTex ) - { - const float SPACING=0.75*ICON_SIZE; - if(foundKeyTex) - { - //Make room for keyTex - binderIcons.setPos((0.93+SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum)); - keyIcons.setPos(0.93*winX,ICON_SIZE*winY*(1+(float)iconNum)); - mouseIcons.setPos((0.93-SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum)); - } - else - { - binderIcons.setPos(0.95*winX,ICON_SIZE*winY*(1+(float)iconNum)); - mouseIcons.setPos(0.90*winX,ICON_SIZE*winY*(1+(float)iconNum)); - } - - binderIcons.draw(); - mouseIcons.draw(); - - if(foundKeyTex) - keyIcons.draw(); - - iconNum++; - } - - } - - glPopAttrib(); - - } - - - glDisable(GL_ALPHA_TEST); - glEnable(GL_DEPTH_TEST); -} - - -void Scene::commitTempCam() -{ - ASSERT(tempCam); - std::swap(cameras[activeCam], tempCam); - delete tempCam; - tempCam=0; -} - -void Scene::discardTempCam() -{ - delete tempCam; - tempCam=0; -} - -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(); - else - *tempCam=*cameras[activeCam]; -} - -void Scene::addDrawable(DrawableObj const *obj ) -{ - objects.push_back(obj); - BoundCube bc; - obj->getBoundingBox(bc); - - if(bc.isValid()) - boundCube.expand(bc); -} - -void Scene::addRefDrawable(const DrawableObj *obj) -{ - refObjects.push_back(obj); - BoundCube bc; - obj->getBoundingBox(bc); - - ASSERT(bc.isValid()); - boundCube.expand(bc); -} - -void Scene::clearAll() -{ - //Invalidate the bounding cube - boundCube.setInverseLimits(); - - clearObjs(); - clearRefObjs(); - clearBindings(); - clearCams(); -} - -void Scene::clearObjs() -{ - for(unsigned int ui=0; uiensureVisible(boundCube,direction); -} - -void Scene::computeSceneLimits() -{ - boundCube.setInverseLimits(); - - BoundCube b; - for(unsigned int ui=0; uigetBoundingBox(b); - - if(b.isValid()) - boundCube.expand(b); - } - - for(unsigned int ui=0; uigetBoundingBox(b); - - if(b.isValid()) - boundCube.expand(b); - } - - - if(!boundCube.isValid()) - { - //He's going to spend the rest of his life - //in a one by one unit box. - - //If there are no objects, then set the bounds - //to 1x1x1, centered around the origin - boundCube.setBounds(-0.5,-0.5,-0.5, - 0.5,0.5,0.5); - } - //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()); - - - //The scene bounds should be no less than 0.1 units - BoundCube unitCube; - Point3D centre; - - centre=boundCube.getCentroid(); - - unitCube.setBounds(centre+Point3D(0.05,0.05,0.05), - centre-Point3D(0.05,0.05,0.05)); - boundCube.expand(unitCube); -} - -void Scene::getCamProperties(unsigned int uniqueID, CameraProperties &p) const -{ - unsigned int position=camIDs.getPos(uniqueID); - cameras[position]->getProperties(p); -} - -void Scene::getCameraIDs(vector > &idVec) const -{ - std::vector ids; - camIDs.getIds(ids); - - idVec.resize(ids.size()); - for(unsigned int ui=0;uigetUserString()); - } -} - -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. -unsigned int Scene::glSelect(bool storeSelected) -{ - ASSERT(!lockInteract); - - glClear( GL_DEPTH_BUFFER_BIT ); - //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 - GLuint *selectionBuffer = new GLuint[512]; - glSelectBuffer(512, selectionBuffer); - glRenderMode(GL_SELECT); - glInitNames(); - - if(!boundCube.isValid()) - computeSceneLimits(); - - glPushMatrix(); - //Apply the camera, but do NOT load the identity matrix, as - //we have set the pick matrix - cameras[activeCam]->apply(outWinAspect,boundCube,false); - - //Set up the objects. Only NON DISPLAYLIST items can be selected. - for(unsigned int ui=0; uicanSelect) - objects[ui]->draw(); - glPopName(); - } - - //OpengGL Faq: - //The number of hit records is returned by the call to - //glRenderMode(GL_RENDER). Each hit record contains the following - //information stored as unsigned ints: - // - // * Number of names in the name stack for this hit record - // * Minimum depth value of primitives (range 0 to 2^32-1) - // * Maximum depth value of primitives (range 0 to 2^32-1) - // * Name stack contents (one name for each unsigned int). - // - //You can use the minimum and maximum Z values with the device - //coordinate X and Y if known (perhaps from a mouse click) - //to determine an object coordinate location of the picked - //primitive. You can scale the Z values to the range 0.0 to 1.0, - //for example, and use them in a call to gluUnProject(). - glFlush(); - GLint hits = glRenderMode(GL_RENDER); - - //The hit query records are stored in an odd manner - //as the name stack is returned with it. This depends - //upon how you have constructed your name stack during drawing - //(clearly). I didn't bother fully understanding this, as it does - //what I want. - GLuint *ptr = selectionBuffer; - GLuint *closestNames = 0; - GLuint minZ = 0xffffffff; - GLuint numClosestNames = 0; - for ( int i=0; itype()) - { - case CAM_LOOKAT: - ((CameraLookAt *)cameras[activeCam])->recomputeUpDirection(); - break; - } -} - -void Scene::addSelectionDevices(const vector *> &d) -{ - for(unsigned int ui=0;ui > tmp; - d[ui]->getModifiedBindings(tmp); - tmp.clear(); -#endif - selectionDevices.push_back(d[ui]); - } -} - -//Values are in the range [0 1]. -void Scene::applyDevice(float startX, float startY, float curX, float curY, - unsigned int keyFlags, unsigned int mouseFlags, bool permanent) -{ - - ASSERT(!lockInteract); - if(lastSelected == (unsigned int) (-1)) - return; - - - //Object should be in object array, and be selectable - ASSERT(lastSelected < objects.size()) - ASSERT(objects[lastSelected]->canSelect); - - //Grab basis vectors. (up, fowards and - //across from camera view.) - //--- - Point3D forwardsDir,upDir; - - forwardsDir=getActiveCam()->getViewDirection(); - upDir=getActiveCam()->getUpDirection(); - - forwardsDir.normalise(); - upDir.normalise(); - Point3D acrossDir; - acrossDir=forwardsDir.crossProd(upDir); - - acrossDir.normalise(); - //--- - - //Compute the distance between the selected object's - //centroid and the camera - //--- - float depth; - BoundCube b; - objects[lastSelected]->getBoundingBox(b); - //Camera-> object vector - Camera *cam=getActiveCam(); - - Point3D camToObject; - //Get the vector to the object - camToObject = b.getCentroid() - cam->getOrigin(); - depth = camToObject.dotProd(forwardsDir); - //--- - - //Compute the width of the camera view for the object at - //the plane that intersects the object's centroid, and is - //normal to the camera direction - float viewWidth; - switch(cam->type()) - { - case CAM_LOOKAT: - viewWidth=((CameraLookAt*)cam)->getViewWidth(depth); - break; - default: - ASSERT(false); - } - - - //We have the object number, but we don't know which binding - //corresponds to this object. Search all bindings. It may be that more than one - //binding is enabled for this object - SelectionBinding *binder; - - vector activeBindings; - for(unsigned int ui=0;uigetBinding( - objects[lastSelected],mouseFlags,keyFlags,binder)) - activeBindings.push_back(binder); - } - - for(unsigned int ui=0;uicomputeWorldVectorCoeffs(mouseFlags,keyFlags, - vectorCoeffs[0],vectorCoeffs[1]); - - //Apply vector coeffs, dependant upon binding - worldVec = acrossDir*vectorCoeffs[0][0]*(curX-startX)*outWinAspect - + upDir*vectorCoeffs[0][1]*(curX-startX)*outWinAspect - + forwardsDir*vectorCoeffs[0][2]*(curX-startX)*outWinAspect - + acrossDir*vectorCoeffs[1][0]*(curY-startY) - + upDir*vectorCoeffs[1][1]*(curY-startY) - + forwardsDir*vectorCoeffs[1][2]*(curY-startY); - worldVec*=viewWidth; - - activeBindings[ui]->applyTransform(worldVec,permanent); - } - - computeSceneLimits(); - //Inform viscontrol about updates, if we have applied any - if(activeBindings.size() && permanent) - { - visControl->setUpdates(); - //If the viscontrol is in the midddle of an update, - //tell it to abort. - if(visControl->isRefreshing()) - visControl->abort(); - } - -} - -unsigned int Scene::duplicateCameras(vector &cams) const -{ - cams.resize(cameras.size()); - - for(unsigned int ui=0;uiclone(); - - return activeCam; -} - -void Scene::getEffects(vector &eff) const -{ - eff.resize(effects.size()); - - for(unsigned int ui=0;ui > &bindings) const -{ - for(unsigned int ui=0;uigetModifiedBindings(bindings); -} - -void Scene::restrictView(float xS, float yS, float xFin, float yFin) -{ - viewRestrictStart[0]=xS; - viewRestrictStart[1]=yS; - - viewRestrictEnd[0]=xFin; - viewRestrictEnd[1]=yFin; - - viewRestrict=true; -} - -bool Scene::isDefaultCam() const -{ - return activeCam==0; -} - -bool Scene::camNameExists(const std::string &s) const -{ - for(unsigned int ui=0;uigetUserString() == s) - return true; - } - - return false; -} - - - -unsigned int Scene::addEffect(Effect *e) -{ - ASSERT(e); - ASSERT(effects.size() == effectIDs.size()); - effects.push_back(e); - - - return effectIDs.genId(effects.size()-1); -} - - -void Scene::removeEffect(unsigned int uniqueID) -{ - unsigned int position = effectIDs.getPos(uniqueID); - delete effects[position]; - effects.erase(effects.begin()+position); - effectIDs.killByPos(position); -} - -void Scene::clearEffects() -{ - for(size_t ui=0;ui. -*/ -#ifndef SCENE_H -#define SCENE_H - -#include -#include - -class Scene; - -//Custom includes -#include "drawables.h" -#include "select.h" -#include "basics.h" -#include "viscontrol.h" -//cameras.h uses libxml2. libxml2 conflicts with wx headers, and must go last -#include "cameras.h" - -#include "filter.h" -#include "textures.h" -#include "effect.h" - -//OpenGL debugging macro -#if DEBUG -#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; \ -} -#else -#define glError() -#endif - -#ifdef DEBUG - #define glStackDepths() { \ - int gldepthdebug[3];glGetIntegerv (GL_MODELVIEW_STACK_DEPTH, gldepthdebug);\ - glGetIntegerv (GL_PROJECTION_STACK_DEPTH, gldepthdebug+1);\ - glGetIntegerv (GL_TEXTURE_STACK_DEPTH, gldepthdebug+2);\ - std::cerr << "OpenGL Stack Depths: ModelV:" << gldepthdebug[0] << " Pr: "\ - << gldepthdebug[1] << " Tex:" << gldepthdebug[2] << std::endl;} -#else - #define glStackDepths() -#endif - -//!The scene class brings together elements such as objects, lights, and cameras -//to enable scene rendering -class Scene -{ - private: - //!Viscontroller. Needed for notification of updates during selection binding - VisController *visControl; - //!Objects that will be used for drawing - std::vector objects; - - //!Objects used for drawing that will not be destroyed - std::vector refObjects; - - - //!Bindings for interactive object properties - std::vector *> selectionDevices; - - //!Various OpenGL effects - std::vector effects; - - //!Vector of camera stats - std::vector cameras; - - //!Temporary override camera - Camera *tempCam; - - //!Texture pool - TexturePool texPool; - - //!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 - float outWinAspect; - - //!Blank canvas colour - float r,g,b; - - - //!Camera id storage and handling - UniqueIDHandler camIDs; - - //!Effect ID handler - UniqueIDHandler effectIDs; - - //!Cube that holds the scene bounds - BoundCube boundCube; - - - //!True if user interaction (selection/hovering) is forbidden - bool lockInteract; - //!Tells the scene if we are in selection mode or not - bool selectionMode; - - //!Tells us if we are in hover mode (should we draw hover overlays?) - bool hoverMode; - - //!Is the camera to be restricted to only draw a particular portion of the viewport? - bool viewRestrict; - - float viewRestrictStart[2], viewRestrictEnd[2]; - - //!Last selected object from call to glSelect(). -1 if last call failed to identify an item - unsigned int lastSelected; - - //!Last hoeverd object - unsigned int lastHovered; - - //!Should alpha belnding be used? - bool useAlpha; - //!Should lighting calculations be performed? - bool useLighting; - //!Should we be using effects? - bool useEffects; - - //!Should the world axis be drawn? - bool showAxis; - - //!Background colour - float rBack,gBack,bBack; - - - ///!Draw the hover overlays - void drawHoverOverlay(); - - //!Draw the normal overlays - void drawOverlays() const; - - //!initialise the drawing window - unsigned int initDraw(); - - void updateCam(const Camera *camToUse) const; - - - //!Draw a specified vector of objects - void drawObjectVector(const std::vector &objects, bool &lightsOn, bool drawOpaques=true) const; - - - public: - //!Constructor - Scene(); - //!Destructor - virtual ~Scene(); - - //!Set the vis control - void setViscontrol(VisController *v) { visControl=v;}; - //!Draw the objects in the active window. May adjust cameras and compute bounding as needed. - void draw(); - - - //!clear rendering vectors - void clearAll(); - //!Clear drawing objects vector - void clearObjs(); - //! Clear the reference object vector - 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 - float getAspect() const { return outWinAspect;}; - - //!Add a drawable object - /*!Pointer must be set to a valid (allocated) object. - *!Scene will delete upon call to clearAll, clearObjs or - *!upon destruction - */ - 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 - * 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); - - //!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); - - - //! set the active camera - void setActiveCam(unsigned int uniqueCamID); - - //! get the active camera - Camera *getActiveCam() { ASSERT(cameras.size()); return cameras[activeCam];}; - - //! get the active camera's location - Point3D getActiveCamLoc() const; - - //!Construct (or refresh) a temporary camera - /*! this temporary camera is discarded with - * either killTempCam or reset to the active - * camera with another call to setTempCam(). - * The temporary camera overrides the existing camera setup - */ - void setTempCam(); - - //!Return pointer to active camera. Must init a temporary camera first! (use setTempCam) - Camera *getTempCam() { ASSERT(tempCam); return tempCam;}; - - //!Make the temp camera permanent. - void commitTempCam(); - - //!Discard the temporary camera - void discardTempCam(); - - //!Are we using a temporary camera? - 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(); } ; - - //!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 > &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 - void setDefaultCam(); - - //!Call if user has stopped interacting with camera briefly. - void finaliseCam(); - - //!perform an openGL selection rendering pass. Return - //closest object in depth buffer under position - //if nothing, returns -1 - unsigned int glSelect(bool storeSelection=true); - - //!Add selection devices to the scene. - void addSelectionDevices(const std::vector *> &d); - - //!Clear the current selection devices - void clearDevices(); - - //!Apply the device given the following start and end - //viewport coordinates. - void applyDevice(float startX, float startY, - float curX, float curY,unsigned int keyFlags, - unsigned int mouseflags,bool permanent=true); - - // is interaction currently locked? - bool isInteractionLocked() const { return lockInteract;} - //!Prevent user interactoin - void lockInteraction(bool amLocking=true) { lockInteract=amLocking;}; - //!Set selection mode true=select on, false=select off. - //All this does internally is modify how drawing works. - void setSelectionMode(bool selMode) { selectionMode=selMode;}; - - //!Set the hover mode to control drawing - void setHoverMode(bool hMode) { hoverMode=hMode;}; - - //!Return the last object over whichthe cursor was hovered - void setLastHover(unsigned int hover) { lastHovered=hover;}; - //!Get the last selected object from call to glSelect() - unsigned int getLastSelected() const { return lastSelected;}; - - //!Return the last object over whichthe cursor was hovered - unsigned int getLastHover() const { return lastHovered;}; - //!Duplicates the internal camera vector. return value is active camera - //in returned vector - unsigned int duplicateCameras(std::vector &cams) const; - //!Get a copy of the effects pointers - void getEffects(std::vector &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 > &bindings) const; - - //!Restrict the openGL drawing view when using the camera - void restrictView(float xS,float yS, float xFin, float yFin); - //!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;}; - - //!Set whether to enable lighting - void setLighting(bool newLight) { useLighting=newLight;}; - - //!Set whether to enable the XYZ world axes - void setWorldAxisVisible(bool newAxis) { showAxis=newAxis;}; - //!Get whether the XYZ world axes are enabled - bool getWorldAxisVisible() const { return showAxis;}; - - //!Set window size - void setWinSize(unsigned int x, unsigned int y) {winX=x;winY=y;} - - //!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;}; - - void getBackgroundColour(float &newR,float &newG,float &newB) const { newR=rBack;newG=gBack;newB=bBack;}; - - //!Computes the bounding box for the scene. - //this is locked to a minimum of 0.1 unit box around the origin. - //this avoids nasty camera situations, where lookat cameras are sitting - //on their targets, and don't know where to look. - void computeSceneLimits(); - - //!Set whether to use effects or not - void setEffects(bool enable) {useEffects=enable;} - - //!Add an effect - unsigned int addEffect(Effect *e); - //!Remove a given effect - void removeEffect(unsigned int uniqueEffectID); - - //!Clear effects vector - void clearEffects(); -}; - -#endif diff -Nru 3depict-0.0.12/src/select.cpp 3depict-0.0.13/src/select.cpp --- 3depict-0.0.12/src/select.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/select.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -/* - * select.cpp - filter selection binding implementation - * Copyright (C) 2012, 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 . -*/ - -#include "select.h" - - -SelectionBinding::SelectionBinding() -{ - obj=0; - valModified=false; - bindingId=drawActionId=0; -} - -void SelectionBinding::setBinding(unsigned int button, unsigned int modifierFlags,unsigned int actionId, - unsigned int bindID, float initValue, DrawableObj * d) -{ - //Cache the current value - cachedValFloat = initValue; - drawActionId=actionId; - //Grab the object identifier itself - obj=d; - - bindKeys=modifierFlags; - bindButtons=button; - bindingId=bindID; - - fMin=-std::numeric_limits::max(); - fMax=std::numeric_limits::max(); - - dataType=BIND_TYPE_FLOAT; -} - -void SelectionBinding::setBinding(unsigned int button, unsigned int modifierFlags, unsigned int actionId, - unsigned int bindID, const Point3D &initValue, DrawableObj *d) -{ - - bindingId=bindID; - drawActionId=actionId; - obj=d; - - - bindKeys=modifierFlags; - bindButtons=button; - - cachedValPoint3D = initValue; - - dataType=BIND_TYPE_POINT3D; -} - -void SelectionBinding::setInteractionMode(unsigned int newBindMode) -{ - //Rotation cannot have associated key flags. These are reserved - //for changing the orientation of the rotation - bindMode=newBindMode; -} - -void SelectionBinding::setFloatLimits(float newMin,float newMax) -{ - fMin=newMin; - fMax=newMax; -} - -void SelectionBinding::applyTransform(const Point3D &worldVec, bool permanent) -{ - vector scalars; - vector vecs; - float fTmp; - switch(bindMode) - { - case BIND_MODE_FLOAT_SCALE: - { - //Compute the new scalar as the magnitude of the difference vector - fTmp = sqrtf(worldVec.sqrMag()); - fTmp = std::max(fMin,fTmp); - fTmp = std::min(fMax,fTmp); - - scalars.push_back(fTmp); - break; - } - case BIND_MODE_FLOAT_TRANSLATE: - { - //Compute the new scalar as an offset by the mag of the scalar - fTmp =0.5*cachedValFloat+sqrtf(worldVec.sqrMag()); - fTmp = std::max(fMin,fTmp); - fTmp = std::min(fMax,fTmp); - - scalars.push_back(fTmp); - cachedValFloat=fTmp; - break; - } - case BIND_MODE_POINT3D_TRANSLATE: - case BIND_MODE_POINT3D_SCALE: - { - vecs.push_back(cachedValPoint3D+worldVec); - - //Only apply if this is a permanent change, - //otherwise we will get an integrating effect - if(permanent) - cachedValPoint3D+=worldVec; - break; - } - case BIND_MODE_POINT3D_ROTATE: - { - if(worldVec.sqrMag() > sqrtf(std::numeric_limits::epsilon())) - { - vecs.push_back(worldVec); - cachedValPoint3D = worldVec; - } - - break; - } - case BIND_MODE_POINT3D_ROTATE_LOCK: - { - if(worldVec.sqrMag() > sqrtf(std::numeric_limits::epsilon())) - { - //Renormalise the vector back to the same scale as the cached value - vecs.push_back(worldVec*sqrtf(cachedValPoint3D.sqrMag()/worldVec.sqrMag())); - if(permanent) - cachedValPoint3D=vecs.back(); - } - - break; - } - default: - ASSERT(false); - } - - if(vecs.size() || scalars.size()) - { - //Force a recomputation of the internal parameters - //for the drawable object. Whatever they are. - obj->recomputeParams(vecs,scalars,drawActionId); - - valModified=true; - } -} - -void SelectionBinding::computeWorldVectorCoeffs(unsigned int buttonFlags, - unsigned int modifierFlags,Point3D &xCoeffs,Point3D &yCoeffs) const - -{ - switch(bindMode) - { - case BIND_MODE_FLOAT_TRANSLATE: - case BIND_MODE_FLOAT_SCALE: - //It is of no concern. we are going to pass this to sqrmag - //anyway during applyTransform. - xCoeffs=Point3D(1,0,0); - yCoeffs=Point3D(0,1,0); - break; - case BIND_MODE_POINT3D_TRANSLATE: - case BIND_MODE_POINT3D_SCALE: - case BIND_MODE_POINT3D_ROTATE: - case BIND_MODE_POINT3D_ROTATE_LOCK: - { - if(modifierFlags == FLAG_CMD && bindKeys!=FLAG_CMD) - { - //Mouse movement in x sends you forwards - //y movement sends you up down (wrt camera) - xCoeffs=Point3D(0,0,1); - yCoeffs=Point3D(0,1,0); - } - else if(modifierFlags == FLAG_SHIFT && bindKeys != FLAG_SHIFT) - { - //Mouse movement in x sends you across - //y movement sends you forwards (wrt camera) - xCoeffs=Point3D(1,0,0); - yCoeffs=Point3D(0,0,1); - } - else - { - //For example: FLAG_NONE - //IN plane with camera. - xCoeffs=Point3D(1,0,0); - yCoeffs=Point3D(0,1,0); - } - break; - } - default: - ASSERT(false); - } -} - - -void SelectionBinding::getValue(float &f) const -{ - f=cachedValFloat; -} - -void SelectionBinding::getValue(Point3D &f) const -{ - f=cachedValPoint3D; -} - -bool SelectionBinding::matchesDrawable(const DrawableObj *d, - unsigned int mouseFlags, unsigned int keyFlags) const -{ - //Object and mouseflags must match. keyflags must be nonzero after masking with bindKeys - if(bindKeys) - return (obj == d && mouseFlags == bindButtons && (keyFlags &bindKeys) == bindKeys); - else - return (obj == d && mouseFlags == bindButtons); -}; - - -bool SelectionBinding::matchesDrawable(const DrawableObj *d) const -{ - return (obj == d); -} - diff -Nru 3depict-0.0.12/src/select.h 3depict-0.0.13/src/select.h --- 3depict-0.0.12/src/select.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/select.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -/* - * select,h - Opengl interaction header. - * Copyright (C) 2012, 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 . -*/ - - -#ifndef SELECT_H -#define SELECT_H - -#include "drawables.h" - -#include - -//Mouse button flags -enum -{ - SELECT_BUTTON_LEFT=1, - SELECT_BUTTON_MIDDLE=2, - SELECT_BUTTON_RIGHT=4 -}; - -//!Keyboard keydown flags -enum -{ - FLAG_NONE=0, - FLAG_CMD=1, //control (non-mac) or "clover" key (mac) - FLAG_SHIFT=2, //Left or right shift key. -}; - -//!Allowable binding modes -enum -{ - BIND_MODE_FLOAT_SCALE, //Object scaling only (fp value) - BIND_MODE_FLOAT_TRANSLATE, //Floating point translation - BIND_MODE_POINT3D_TRANSLATE, //3D point translation in 2D plane perpendicular to camera - BIND_MODE_POINT3D_SCALE, //3D point translation in 2D plane perpendicular to camera; but indicate to user that this performs some kind of scaling operation - BIND_MODE_POINT3D_ROTATE, //3D rotation in 2D plane perpendicular to camera - BIND_MODE_POINT3D_ROTATE_LOCK, // 3D rotation in 2D plane perpendicular to camera, but with locked magnitude -}; - -//!Bindable data types (data types that SelectionBinding can work with) -enum -{ - BIND_TYPE_FLOAT, - BIND_TYPE_POINT3D -}; - -//!This class is used to pool together a graphical representation (via the drawable), of -//an object with its internal data structural representation. This allows the user -//to grapple with the drawable representation and feed this into the scene. -//This class binds ONE drawable object to a set of actions based upon key and button combinations. -class SelectionBinding -{ - private: - //Pointer to drawable that generates selection events. - //calls recomputeParams function - DrawableObj *obj; - - //ID number for parent to know which of its bindings this is - unsigned int bindingId; - - //ID number to bind the action for the drawable object - unsigned int drawActionId; - - //Binding type - unsigned int dataType; - - - //Binding button (ORed together) - unsigned int bindButtons; - - //Binding key (ORed together) - unsigned int bindKeys; - - //Binding mode - unsigned int bindMode; - - //Original value of data type (probably more mem efficient ot use a void*...) - float cachedValFloat; - Point3D cachedValPoint3D; - - bool valModified; - - //limits in floating point - float fMin,fMax; - - public: - SelectionBinding(); - - //!Returns true if this binding will be activated given the current flags - bool isActive(unsigned int button,unsigned int curModifierFlags); - - //!Set the binding for a float DO NOT CACHE THE DRAWABLEOBJ-> THAT IS BAD - void setBinding(unsigned int buttonFlags, unsigned int modifierFlags, - unsigned int drawActionId, unsigned int bindingID, - float initVal, DrawableObj *d); - - //!Set the binding for a Point3D. DO NOT CACHE THE DRAWABLEOBJ-> THAT IS BAD - void setBinding(unsigned int buttonFlags, unsigned int modifierFlags, - unsigned int drawActionId,unsigned int bindingID, - const Point3D &initVal, DrawableObj *d); - - //!Set the interaction method. (example translate, scale, rotate etc) - void setInteractionMode(unsigned int bindMode); - - //!Get the interaction mode - unsigned int getInteractionMode() const { return bindMode;}; - - //!Get the mouse button - unsigned int getMouseButtons() const { return bindButtons;}; - - //!Get the mouse button - unsigned int getKeyFlags() const { return bindKeys;}; - - //!Set the limits for a floating point data type - void setFloatLimits(float min,float max); - - //!Is this binding for the following object? - bool matchesDrawable(const DrawableObj *d, - unsigned int mouseFlags, unsigned int keyFlags) const; - //!Is this binding for the following object? - bool matchesDrawable(const DrawableObj *d) const; - - //!Apply the user ineraction specified. set permanent=true to - //make it such that this is not undone during the next transform, - //or call to reset() - //worldvec is the vector along which to transform the object (subject to - //interpretation by the "interaction mode" (bindmode) setting) - void applyTransform(const Point3D &worldVec,bool permanent=false); - - - //!Map the screen coords world coords, given the mouse and keyflags - //coeffs are 0: right 1: forwards 2: up ( right hand rule) - void computeWorldVectorCoeffs(unsigned int buttonFlags, - unsigned int modifierFlags,Point3D &xCoeffs,Point3D &yCoeffs) const; - - //!Retrieve the current value from the drawable representation - void getValue(float &f) const; - //!Retreive the current value from the drawable representation - void getValue(Point3D &p) const; - - unsigned int getID() const { return bindingId;}; - - //!True if the binding has modified the data - bool modified() const {return valModified;}; -}; - -template class SelectionDevice -{ - private: - std::vector bindingVec; - const T *target; -public: - //!Create a new selection device - SelectionDevice(const T *p); - - //!Copy constructor (not implemented) - SelectionDevice(const SelectionDevice ©Src); - - //!Bind a floating point type between the graphical and internal reps. - //note that it is a BUG to attempt to bind any object that uses a - //display list in its internal representation. - void addBinding(SelectionBinding b); - - bool getBinding(const DrawableObj *d, unsigned int mouseFlags, - unsigned int keyFlags, SelectionBinding* &b); - - bool getAvailBindings(const DrawableObj *d, vector &b) const; - void getModifiedBindings(vector > &bindings); -}; - -template -SelectionDevice::SelectionDevice(const T *p) : target(p) -{ -} - -template -void SelectionDevice::addBinding(SelectionBinding b) -{ - bindingVec.push_back(b); -} - -template -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;uigetKeyFlags(); - 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 -void SelectionDevice::getModifiedBindings(vector > &bindings) -{ - ASSERT(target); - for(unsigned int ui=0;ui -bool SelectionDevice::getAvailBindings(const DrawableObj *d,vector &b) const -{ - ASSERT(b.empty()); - for(unsigned int ui=0;ui. +*/ + + #include "testing.h" #ifdef DEBUG -#include #include #include -#include #include "wxcommon.h" -#include -#include "filters/allFilter.h" -#include "configFile.h" +#include "backend/filters/allFilter.h" +#include "backend/configFile.h" -#include "xmlHelper.h" +#include "common/stringFuncs.h" +#include "common/xmlHelper.h" -#include "filtertree.h" const char *TESTING_RESOURCE_DIRS[] = { "../test/", @@ -26,12 +42,6 @@ //!Try cloning the filter from itself, and checking the filter // clone is identical bool filterCloneTests(); -//!Try setting/unsetting all visible boolean properties -// in each filter -bool filterBoolToggleTests(); - -//!Check each visible property has help text -bool filterHelpStringTests(); //!Try loading each range file in the testing folder bool rangeFileLoadTests(); @@ -46,7 +56,7 @@ bool filterTreeTests(); -bool testFilterTree(FilterTree f) +bool testFilterTree(const FilterTree &f) { ASSERT(!f.hasHazardousContents()); std::list > > outData; @@ -93,103 +103,25 @@ bool basicFunctionTests() { - //Test getMaxVerStr - { - vector verStrs; - - verStrs.push_back("0.0.9"); - verStrs.push_back("0.0.10"); - - TEST(getMaxVerStr(verStrs) == "0.0.10","version string maximum testing"); - - verStrs.clear(); - - verStrs.push_back("0.0.9"); - verStrs.push_back("0.0.9"); - TEST(getMaxVerStr(verStrs) == "0.0.9","version string maximum testing"); - - - verStrs.push_back("0.0.9"); - verStrs.push_back("0.0.blah"); - TEST(getMaxVerStr(verStrs) == "0.0.9","version string maximum testing"); - } - - //Test singular value routines - { - - const unsigned int NUM_PTS=5000; - unsigned int numPts=0; - - vector curCluster; - curCluster.resize(NUM_PTS); - RandNumGen rng; - rng.initTimer(); - - //Build a ball of points - - WARN(false, "The ellipse test is wrong. It doesn't use an isotropic density!"); - IonHit h; - h.setMassToCharge(1); - do - { - Point3D p; - - p=Point3D(rng.genUniformDev() - 0.5f, - (rng.genUniformDev() -0.5f), - rng.genUniformDev() -0.5f); - - //only allow points inside the unit sphere - if(p.sqrMag() > 0.25) - continue; - - //make it elliptical by scaling along Y axis - p[1]*=0.5; - - h.setPos(p); - curCluster[numPts] = h; - numPts++; - - }while(numPts > clusters,dummy; - clusters.push_back(curCluster); - - vector > singularVals; - vector > > singularBases; - ClusterAnalysisFilter c; - - c.getSingularValues(clusters,dummy,singularVals,singularBases); - - TEST(singularVals.size() == 1,"Number of SVs should be same as input size"); - TEST(singularVals.size() == singularBases.size(), "SVs and bases count should be same"); - - //SV ratio of above ellipse should be roughly 1:2 (sorted, S1/S2 = 1, S2/S3 = 2) - // there will be some random fluctuations, depending upon exact initial seed - TEST( fabs(singularVals[0][0]/singularVals[0][1] -1.0f) < 0.2f,"Singular Value ratio 1:2"); - TEST( fabs(singularVals[0][1]/singularVals[0][2] -2.0f) < 0.2f,"Singular Value Ration 2:3"); - - TEST( singularBases[0].first.sqrMag() < 0.01, "Centroid somewhere near origin"); - - IonVectorToPos(curCluster,"TestCluster.pos"); - } + testStringFuncs(); //Test point parsing routines { std::string testStr; testStr="0.0,1.0,1"; Point3D p; - bool res=parsePointStr(testStr,p); + bool res=p.parse(testStr); ASSERT(res); ASSERT(p.sqrDist(Point3D(0,1,1)) < 0.1f); //test case causes segfault : found 30/9/12 testStr="0,0,,"; - res=parsePointStr(testStr,p); + res=p.parse(testStr); ASSERT(!res); testStr="(0,0,0)"; - res=parsePointStr(testStr,p); + res=p.parse(testStr); ASSERT(res); ASSERT(p.sqrDist(Point3D(0,0,0))<0.01f); @@ -207,17 +139,17 @@ TEST(!rangesOverlap(3,4,1,2),"Overlap test"); } + //Test the LFSR to a small extent (first 16 table entries) + // -test is brute-force so we can't test much more without being slow + LinearFeedbackShiftReg reg; + TEST(reg.verifyTable(16),"Check LFSR table integrity"); + return true; } bool runUnitTests() { - if(!filterBoolToggleTests()) - return false; - - if(!filterHelpStringTests()) - return false; if(!basicFunctionTests()) return false; @@ -237,6 +169,9 @@ if(!filterTreeTests()) return false; + if(!runVoxelTests()) + return false; + return true; } @@ -255,6 +190,12 @@ } cerr << "OK" <setUserString(s); } - //build a new tree arrangemnet + //build a new tree arrangement //0 // ->3 //1 @@ -652,102 +595,91 @@ //swap working back fTree.swap(fSpareTree); TEST(fTree.maxDepth() == fTmp.maxDepth(),"filtertree swap"); - return true; -} -//TODO: Refactor into filter base class. -bool filterBoolToggleTests() -{ - //Each filter should allow user to toggle any boolean value - // here we just test the default visible ones - for(unsigned int ui=0;uigetProperties(propGroupOrig); - - - for(size_t ui=0;ui" << endl; + //Dump tree contents into XML file + std::map dummyMap; + if(fTree.saveXML(tmpFile,dummyMap,false,true)) + { + tmpFile<< "" << endl; + } else { - ASSERT(false); + WARN(true,"Unable to write to random file in current folder. skipping test"); } - - - //set value to toggled version - bool needUp; - f->setProperty(p.key,p.data,needUp); - - //Re-get properties to find altered property - FilterPropGroup propGroup; - f->getProperties(propGroup); - - FilterProperty p2; - p2 = propGroup.getPropValue(p.key); - //Check the property values - TEST(p2.data == p.data,"displayed bool property can't be toggled"); - - //Toggle value back to original status - if(p2.data== "0") - p2.data= "1"; - else - p2.data= "0"; - //re-set value to toggled version - f->setProperty(p2.key,p2.data,needUp); - //Re-get properties to see if orginal value is restored - FilterPropGroup fp2; - f->getProperties(fp2); - p = fp2.getPropValue(p2.key); - TEST(p.data== p2.data,"failed trying to set bool value back to original after toggle"); - } - delete f; - } + //Reparse tree + //--- + xmlDocPtr doc; + xmlParserCtxtPtr context; - return true; -} + context =xmlNewParserCtxt(); -//TODO: Refactor into filter base class. -bool filterHelpStringTests() -{ - //Each filter should provide help text for each property - // here we just test the default visible ones - for(unsigned int ui=0;uigetProperties(propGroup); - for(size_t ui=0;uixmlChildrenNode; + if(!nodePtr) + throw false; + + //find filtertree data + if(XMLHelpFwdToElem(nodePtr,"filtertree")) + throw false; + + TEST(!fTree.loadXML(nodePtr,cerr,""),"Tree load test"); + //----- + } + catch(bool) { - FilterProperty p; - p=propGroup.getNthProp(ui); - TEST(p.helpText.size(),"Property help text must not be empty"); + WARN(false,"Couldn't run XML reparse of output file"); + wxRemoveFile(wxStr(tmpName)); + return false; } - delete f; + wxRemoveFile(wxStr(tmpName)); + } + else + { + WARN(true,"Unable to open random file in current folder. skipping a test"); } return true; } + + #endif diff -Nru 3depict-0.0.12/src/testing.h 3depict-0.0.13/src/testing.h --- 3depict-0.0.12/src/testing.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/testing.h 2013-03-22 18:31:39.000000000 +0000 @@ -1,15 +1,33 @@ +/* + * testing.cpp - unit testing framework + * 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 . +*/ + #ifndef TESTING_H #define TESTING_H #ifdef DEBUG -#include "filtertree.h" +#include "backend/filtertree.h" //Run all the built-in unit tests. bool runUnitTests(); //Run the particular specified filter tree -bool testFilterTree(FilterTree f); +bool testFilterTree(const FilterTree &f); #endif Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/tex-source/3Depict-icon.icns and /tmp/ZSARKCsiTI/3depict-0.0.13/src/tex-source/3Depict-icon.icns differ diff -Nru 3depict-0.0.12/src/tex-source/3Depict-icon.svg 3depict-0.0.13/src/tex-source/3Depict-icon.svg --- 3depict-0.0.12/src/tex-source/3Depict-icon.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/3Depict-icon.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,793 +0,0 @@ - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/Icons-licence.txt 3depict-0.0.13/src/tex-source/Icons-licence.txt --- 3depict-0.0.12/src/tex-source/Icons-licence.txt 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/Icons-licence.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -Files: - File:Left clicked mouse.svg - File:Right clicked mouse.svg -Origin: - Wikimedia Commons: -Uploader: - User:Darklama - -Licence: -Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". - -Or - -Tbjs file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported, 2.5 Generic, 2.0 Generic and 1.0 Generic license. - - You are free: - - * to share – to copy, distribute and transmit the work - * to remix – to adapt the work - - Under the following conditions: - - * attribution – You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). - * share alike – If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. - -------------------- - -Files: - File:Blue_Glass_Arrow.svg - -Uploader: - User:Everaldo Coelho and [www.yellowicon.com YellowIcon] - -Licence: -This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU Lesser General Public License for more details. - - ---------------------- -Files: - File:Preferences-desktop-keyboard-shortcuts-ctrl.svg (renamed to keyboard-alt.svg) -Author: - Tango Project: Freedesktop.org (http://tango.freedesktop.org/Tango_Desktop_Project) - -Licence: - Public domain - ---------------------- - - -Files: - File:Green_sphere.svg - File:Blue_Sphere.svg - - Work has been used in derivative work (program icon) -Author: - - User:Booyabazooka; recoloured by User:Stannered -Licence: - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation; either version - 2.1 of the License, or (at your option) any later version. This - library is distributed in the hope that it will be useful, - but without any warranty; without even the implied warranty of - merchantability or fitness for a particular purpose. See version - 2.1 and version 3 of the GNU Lesser General Public License for - more details. ----------------------- diff -Nru 3depict-0.0.12/src/tex-source/Left-Right-arrow.svg 3depict-0.0.13/src/tex-source/Left-Right-arrow.svg --- 3depict-0.0.12/src/tex-source/Left-Right-arrow.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/Left-Right-arrow.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,1102 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff -Nru 3depict-0.0.12/src/tex-source/Left_clicked_mouse.svg 3depict-0.0.13/src/tex-source/Left_clicked_mouse.svg --- 3depict-0.0.12/src/tex-source/Left_clicked_mouse.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/Left_clicked_mouse.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,238 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/Right-arrow.svg 3depict-0.0.13/src/tex-source/Right-arrow.svg --- 3depict-0.0.12/src/tex-source/Right-arrow.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/Right-arrow.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,553 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff -Nru 3depict-0.0.12/src/tex-source/Right_clicked_mouse.svg 3depict-0.0.13/src/tex-source/Right_clicked_mouse.svg --- 3depict-0.0.12/src/tex-source/Right_clicked_mouse.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/Right_clicked_mouse.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/enlarge.svg 3depict-0.0.13/src/tex-source/enlarge.svg --- 3depict-0.0.12/src/tex-source/enlarge.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/enlarge.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,1265 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/keyboard-alt.svg 3depict-0.0.13/src/tex-source/keyboard-alt.svg --- 3depict-0.0.12/src/tex-source/keyboard-alt.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/keyboard-alt.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,302 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Alt - - - diff -Nru 3depict-0.0.12/src/tex-source/keyboard-command.svg 3depict-0.0.13/src/tex-source/keyboard-command.svg --- 3depict-0.0.12/src/tex-source/keyboard-command.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/keyboard-command.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,302 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/keyboard-ctrl.svg 3depict-0.0.13/src/tex-source/keyboard-ctrl.svg --- 3depict-0.0.12/src/tex-source/keyboard-ctrl.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/keyboard-ctrl.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,301 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ctrl - - diff -Nru 3depict-0.0.12/src/tex-source/keyboard-shift.svg 3depict-0.0.13/src/tex-source/keyboard-shift.svg --- 3depict-0.0.12/src/tex-source/keyboard-shift.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/keyboard-shift.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,302 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/keyboard-tab.svg 3depict-0.0.13/src/tex-source/keyboard-tab.svg --- 3depict-0.0.12/src/tex-source/keyboard-tab.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/keyboard-tab.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Tab - - diff -Nru 3depict-0.0.12/src/tex-source/middle_clicked_mouse.svg 3depict-0.0.13/src/tex-source/middle_clicked_mouse.svg --- 3depict-0.0.12/src/tex-source/middle_clicked_mouse.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/middle_clicked_mouse.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,433 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru 3depict-0.0.12/src/tex-source/rotateArrow.svg 3depict-0.0.13/src/tex-source/rotateArrow.svg --- 3depict-0.0.12/src/tex-source/rotateArrow.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/rotateArrow.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,1703 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff -Nru 3depict-0.0.12/src/tex-source/scroll_wheel_mouse.svg 3depict-0.0.13/src/tex-source/scroll_wheel_mouse.svg --- 3depict-0.0.12/src/tex-source/scroll_wheel_mouse.svg 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tex-source/scroll_wheel_mouse.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,306 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/Left-Right-arrow.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/Left-Right-arrow.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/Left_clicked_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/Left_clicked_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/Right-arrow.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/Right-arrow.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/Right_clicked_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/Right_clicked_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/enlarge.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/enlarge.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/keyboard-alt.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/keyboard-alt.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/keyboard-command.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/keyboard-command.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/keyboard-ctrl.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/keyboard-ctrl.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/keyboard-shift.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/keyboard-shift.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/keyboard-tab.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/keyboard-tab.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/middle_clicked_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/middle_clicked_mouse.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/rotateArrow.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/rotateArrow.png differ Binary files /tmp/arveZAt5b_/3depict-0.0.12/src/textures/scroll_wheel_mouse.png and /tmp/ZSARKCsiTI/3depict-0.0.13/src/textures/scroll_wheel_mouse.png differ diff -Nru 3depict-0.0.12/src/textures.cpp 3depict-0.0.13/src/textures.cpp --- 3depict-0.0.12/src/textures.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/textures.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -/* - * textures.cpp - texture wrapper class implementation - * Copyright (C) 2012, 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 . -*/ - -#include "textures.h" - -#include "pngread.h" - -#include "wxcommon.h" - -const char *TEST_OVERLAY_PNG[] = { - "textures/Left_clicked_mouse.png", - "textures/Left-Right-arrow.png", - "textures/Right_clicked_mouse.png", - "textures/rotateArrow.png", - "textures/middle_clicked_mouse.png", - "textures/scroll_wheel_mouse.png", - "textures/enlarge.png", - - "textures/keyboard-ctrl.png", - "textures/keyboard-command.png", - "textures/keyboard-alt.png", - "textures/keyboard-tab.png", - "textures/keyboard-shift.png", - }; - -TexturePool::~TexturePool() -{ - closeAll(); -} - -bool TexturePool::openTexture(const char *texName,unsigned int &texID, unsigned int &uniqID) -{ - std::string texPath; - - texPath = locateDataFile(texName); - - //See if we already have this texture (use abs. name) - for(unsigned int ui=0;uiwidth = width; - dest->height = height; - dest->data = new unsigned char[4*width*height]; - for (y=0; ydata[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 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)); -} diff -Nru 3depict-0.0.12/src/textures.h 3depict-0.0.13/src/textures.h --- 3depict-0.0.12/src/textures.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/textures.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * textures.h - Texture control classes header - * Copyright (C) 2012, 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 . -*/ - - -#ifndef TEXTURES_H -#define TEXTURES_H - -#include "basics.h" - -#ifdef __APPLE__ -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include - - - -//Named Textures -enum -{ - TEXTURE_LEFT_CLICK=0, - TEXTURE_TRANSLATE, - TEXTURE_RIGHT_CLICK, - TEXTURE_ROTATE, - TEXTURE_MIDDLE_CLICK, - TEXTURE_SCROLL_WHEEL, - TEXTURE_ENLARGE, - - TEXTURE_CTRL, - TEXTURE_COMMAND, - TEXTURE_ALT, - TEXTURE_TAB, - TEXTURE_SHIFT -}; - -//Paths to named textures -extern const char *TEST_OVERLAY_PNG[]; - -typedef struct { -GLuint name; /* OpenGL name assigned by the thingy */ -GLuint width; -GLuint height; -unsigned char *data; -} texture; - -class TexturePool -{ -private: - UniqueIDHandler texUniqIds; - std::vector > openTextures; - - public: - TexturePool() {} ; - ~TexturePool(); - //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); - - //Close the specified texture, using its unique ID - void closeTexture(unsigned int texID); - - //Close all textures - void closeAll(); - -}; - -//!Type can be GL_TEXTURE_1D or GL_TEXTURE_2D -int pngTexture(texture* dest, const char* filename, GLenum type); -int pngTexture2D(texture*, const char*); -int pngTexture1D(texture*, const char*); - - -#endif diff -Nru 3depict-0.0.12/src/translation.h 3depict-0.0.13/src/translation.h --- 3depict-0.0.12/src/translation.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/translation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * translation.h - Program gettext translation macros - * 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 - * 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 . - */ - -#ifndef TRANSLATION_H -#define TRANSLATION_H - -#include - - -#if defined(__APPLE__) || defined(__WIN32__) || defined(__WIN64__) -#include -#endif - -//!Gettext translation macro -#define TRANS(x) (gettext(x)) - -//!Gettext null-translation macro (mark for translation, but do nothing) -#define NTRANS(x) (x) - -//!Wx friendly gettext translation macro -#define wxTRANS(x) (wxString(gettext(x),*wxConvCurrent)) - -#define wxNTRANS(x) wxT(x) - -#endif diff -Nru 3depict-0.0.12/src/tree.hh 3depict-0.0.13/src/tree.hh --- 3depict-0.0.12/src/tree.hh 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/src/tree.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,2704 +0,0 @@ - -// STL-like templated tree class. -// -// Copyright (C) 2001-2009 Kasper Peeters -// Distributed under the GNU General Public License version 3, -// (eventually to be changed to the Boost Software License). - -/** The tree.hh library for C++ provides an STL-like container class - for n-ary trees, templated over the data stored at the - nodes. Various types of iterators are provided (post-order, - pre-order, and others). Where possible the access methods are - compatible with the STL or alternative algorithms are - available. -*/ - - -#ifndef tree_hh_ -#define tree_hh_ - -#include -#include -#include -#include -#include -#include -#include -#include - -// HP-style construct/destroy have gone from the standard, -// so here is a copy. - -namespace kp { - -template -void constructor(T1* p, T2& val) - { - new ((void *) p) T1(val); - } - -template -void constructor(T1* p) - { - new ((void *) p) T1; - } - -template -void destructor(T1* p) - { - p->~T1(); - } - -} - -/// A node in the tree, combining links to other nodes as well as the actual data. -template -class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. - public: - tree_node_ *parent; - tree_node_ *first_child, *last_child; - tree_node_ *prev_sibling, *next_sibling; - T data; -}; // __attribute__((packed)); - -template > > -class tree { - protected: - typedef tree_node_ tree_node; - public: - /// Value of the data stored at a node. - typedef T value_type; - - class iterator_base; - class pre_order_iterator; - class post_order_iterator; - class sibling_iterator; - class leaf_iterator; - - tree(); - tree(const T&); - tree(const iterator_base&); - tree(const tree&); - ~tree(); - void operator=(const tree&); - - /// Base class for iterators, only pointers stored, no traversal logic. -#ifdef __SGI_STL_PORT - class iterator_base : public stlport::bidirectional_iterator { -#else - class iterator_base { -#endif - public: - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - iterator_base(); - iterator_base(tree_node *); - - T& operator*() const; - T* operator->() const; - - /// When called, the next increment/decrement skips children of this node. - void skip_children(); - void skip_children(bool skip); - /// Number of children of the node pointed to by the iterator. - unsigned int number_of_children() const; - - sibling_iterator begin() const; - sibling_iterator end() const; - - tree_node *node; - protected: - bool skip_current_children_; - }; - - /// Depth-first iterator, first accessing the node, then its children. - class pre_order_iterator : public iterator_base { - public: - pre_order_iterator(); - pre_order_iterator(tree_node *); - pre_order_iterator(const iterator_base&); - pre_order_iterator(const sibling_iterator&); - - bool operator==(const pre_order_iterator&) const; - bool operator!=(const pre_order_iterator&) const; - pre_order_iterator& operator++(); - pre_order_iterator& operator--(); - pre_order_iterator operator++(int); - pre_order_iterator operator--(int); - pre_order_iterator& operator+=(unsigned int); - pre_order_iterator& operator-=(unsigned int); - }; - - /// Depth-first iterator, first accessing the children, then the node itself. - class post_order_iterator : public iterator_base { - public: - post_order_iterator(); - post_order_iterator(tree_node *); - post_order_iterator(const iterator_base&); - post_order_iterator(const sibling_iterator&); - - bool operator==(const post_order_iterator&) const; - bool operator!=(const post_order_iterator&) const; - post_order_iterator& operator++(); - post_order_iterator& operator--(); - post_order_iterator operator++(int); - post_order_iterator operator--(int); - post_order_iterator& operator+=(unsigned int); - post_order_iterator& operator-=(unsigned int); - - /// Set iterator to the first child as deep as possible down the tree. - void descend_all(); - }; - - /// Breadth-first iterator, using a queue - class breadth_first_queued_iterator : public iterator_base { - public: - breadth_first_queued_iterator(); - breadth_first_queued_iterator(tree_node *); - breadth_first_queued_iterator(const iterator_base&); - - bool operator==(const breadth_first_queued_iterator&) const; - bool operator!=(const breadth_first_queued_iterator&) const; - breadth_first_queued_iterator& operator++(); - breadth_first_queued_iterator operator++(int); - breadth_first_queued_iterator& operator+=(unsigned int); - - private: - std::queue traversal_queue; - }; - - /// The default iterator types throughout the tree class. - typedef pre_order_iterator iterator; - typedef breadth_first_queued_iterator breadth_first_iterator; - - /// Iterator which traverses only the nodes at a given depth from the root. - class fixed_depth_iterator : public iterator_base { - public: - fixed_depth_iterator(); - fixed_depth_iterator(tree_node *); - fixed_depth_iterator(const iterator_base&); - fixed_depth_iterator(const sibling_iterator&); - fixed_depth_iterator(const fixed_depth_iterator&); - - bool operator==(const fixed_depth_iterator&) const; - bool operator!=(const fixed_depth_iterator&) const; - fixed_depth_iterator& operator++(); - fixed_depth_iterator& operator--(); - fixed_depth_iterator operator++(int); - fixed_depth_iterator operator--(int); - fixed_depth_iterator& operator+=(unsigned int); - fixed_depth_iterator& operator-=(unsigned int); - - tree_node *top_node; - }; - - /// Iterator which traverses only the nodes which are siblings of each other. - class sibling_iterator : public iterator_base { - public: - sibling_iterator(); - sibling_iterator(tree_node *); - sibling_iterator(const sibling_iterator&); - sibling_iterator(const iterator_base&); - - bool operator==(const sibling_iterator&) const; - bool operator!=(const sibling_iterator&) const; - sibling_iterator& operator++(); - sibling_iterator& operator--(); - sibling_iterator operator++(int); - sibling_iterator operator--(int); - sibling_iterator& operator+=(unsigned int); - sibling_iterator& operator-=(unsigned int); - - tree_node *range_first() const; - tree_node *range_last() const; - tree_node *parent_; - private: - void set_parent_(); - }; - - /// Iterator which traverses only the leaves. - class leaf_iterator : public iterator_base { - public: - leaf_iterator(); - leaf_iterator(tree_node *, tree_node *top=0); - leaf_iterator(const sibling_iterator&); - leaf_iterator(const iterator_base&); - - bool operator==(const leaf_iterator&) const; - bool operator!=(const leaf_iterator&) const; - leaf_iterator& operator++(); - leaf_iterator& operator--(); - leaf_iterator operator++(int); - leaf_iterator operator--(int); - leaf_iterator& operator+=(unsigned int); - leaf_iterator& operator-=(unsigned int); - private: - tree_node *top_node; - }; - - /// Return iterator to the beginning of the tree. - inline pre_order_iterator begin() const; - /// Return iterator to the end of the tree. - inline pre_order_iterator end() const; - /// Return post-order iterator to the beginning of the tree. - post_order_iterator begin_post() const; - /// Return post-order end iterator of the tree. - post_order_iterator end_post() const; - /// Return fixed-depth iterator to the first node at a given depth from the given iterator. - fixed_depth_iterator begin_fixed(const iterator_base&, unsigned int) const; - /// Return fixed-depth end iterator. - fixed_depth_iterator end_fixed(const iterator_base&, unsigned int) const; - /// Return breadth-first iterator to the first node at a given depth. - breadth_first_queued_iterator begin_breadth_first() const; - /// Return breadth-first end iterator. - breadth_first_queued_iterator end_breadth_first() const; - /// Return sibling iterator to the first child of given node. - sibling_iterator begin(const iterator_base&) const; - /// Return sibling end iterator for children of given node. - sibling_iterator end(const iterator_base&) const; - /// Return leaf iterator to the first leaf of the tree. - leaf_iterator begin_leaf() const; - /// Return leaf end iterator for entire tree. - leaf_iterator end_leaf() const; - /// Return leaf iterator to the first leaf of the subtree at the given node. - leaf_iterator begin_leaf(const iterator_base& top) const; - /// Return leaf end iterator for the subtree at the given node. - leaf_iterator end_leaf(const iterator_base& top) const; - - /// Return iterator to the parent of a node. - template static iter parent(iter); - /// Return iterator to the previous sibling of a node. - template iter previous_sibling(iter) const; - /// Return iterator to the next sibling of a node. - template iter next_sibling(iter) const; - /// Return iterator to the next node at a given depth. - template iter next_at_same_depth(iter) const; - - /// Erase all nodes of the tree. - void clear(); - /// Erase element at position pointed to by iterator, return incremented iterator. - template iter erase(iter); - /// Erase all children of the node pointed to by iterator. - void erase_children(const iterator_base&); - - /// Insert empty node as last/first child of node pointed to by position. - template iter append_child(iter position); - template iter prepend_child(iter position); - /// Insert node as last/first child of node pointed to by position. - template iter append_child(iter position, const T& x); - template iter prepend_child(iter position, const T& x); - /// Append the node (plus its children) at other_position as last/first child of position. - template iter append_child(iter position, iter other_position); - template iter prepend_child(iter position, iter other_position); - /// Append the nodes in the from-to range (plus their children) as last/first children of position. - template iter append_children(iter position, sibling_iterator from, sibling_iterator to); - template iter prepend_children(iter position, sibling_iterator from, sibling_iterator to); - - /// Short-hand to insert topmost node in otherwise empty tree. - pre_order_iterator set_head(const T& x); - /// Insert node as previous sibling of node pointed to by position. - template iter insert(iter position, const T& x); - /// Specialisation of previous member. - sibling_iterator insert(sibling_iterator position, const T& x); - /// Insert node (with children) pointed to by subtree as previous sibling of node pointed to by position. - template iter insert_subtree(iter position, const iterator_base& subtree); - /// Insert node as next sibling of node pointed to by position. - template iter insert_after(iter position, const T& x); - /// Insert node (with children) pointed to by subtree as next sibling of node pointed to by position. - template iter insert_subtree_after(iter position, const iterator_base& subtree); - - /// Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. - template iter replace(iter position, const T& x); - /// Replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above. - template iter replace(iter position, const iterator_base& from); - /// Replace string of siblings (plus their children) with copy of a new string (with children); see above - sibling_iterator replace(sibling_iterator orig_begin, sibling_iterator orig_end, - sibling_iterator new_begin, sibling_iterator new_end); - - /// Move all children of node at 'position' to be siblings, returns position. - template iter flatten(iter position); - /// Move nodes in range to be children of 'position'. - template iter reparent(iter position, sibling_iterator begin, sibling_iterator end); - /// Move all child nodes of 'from' to be children of 'position'. - template iter reparent(iter position, iter from); - - /// Replace node with a new node, making the old node a child of the new node. - template iter wrap(iter position, const T& x); - - /// Move 'source' node (plus its children) to become the next sibling of 'target'. - template iter move_after(iter target, iter source); - /// Move 'source' node (plus its children) to become the previous sibling of 'target'. - template iter move_before(iter target, iter source); - sibling_iterator move_before(sibling_iterator target, sibling_iterator source); - /// Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target'). - template iter move_ontop(iter target, iter source); - - /// Merge with other tree, creating new branches and leaves only if they are not already present. - void merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, - bool duplicate_leaves=false); - /// Sort (std::sort only moves values of nodes, this one moves children as well). - void sort(sibling_iterator from, sibling_iterator to, bool deep=false); - template - void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); - /// Compare two ranges of nodes (compares nodes as well as tree structure). - template - bool equal(const iter& one, const iter& two, const iter& three) const; - template - bool equal(const iter& one, const iter& two, const iter& three, BinaryPredicate) const; - template - bool equal_subtree(const iter& one, const iter& two) const; - template - bool equal_subtree(const iter& one, const iter& two, BinaryPredicate) const; - /// Extract a new tree formed by the range of siblings plus all their children. - tree subtree(sibling_iterator from, sibling_iterator to) const; - void subtree(tree&, sibling_iterator from, sibling_iterator to) const; - /// Exchange the node (plus subtree) with its sibling node (do nothing if no sibling present). - void swap(sibling_iterator it); - /// Exchange two nodes (plus subtrees) - void swap(iterator, iterator); - - /// Count the total number of nodes. - size_t size() const; - /// Count the total number of nodes below the indicated node (plus one). - size_t size(const iterator_base&) const; - /// Check if tree is empty. - bool empty() const; - /// Compute the depth to the root or to a fixed other iterator. - static int depth(const iterator_base&); - static int depth(const iterator_base&, const iterator_base&); - /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. - int max_depth() const; - /// Determine the maximal depth of the tree with top node at the given position. - int max_depth(const iterator_base&) const; - /// Count the number of children of node at position. - static unsigned int number_of_children(const iterator_base&); - /// Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1. - unsigned int number_of_siblings(const iterator_base&) const; - /// Determine whether node at position is in the subtrees with root in the range. - bool is_in_subtree(const iterator_base& position, const iterator_base& begin, - const iterator_base& end) const; - /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. - bool is_valid(const iterator_base&) const; - - /// Determine the index of a node in the range of siblings to which it belongs. - unsigned int index(sibling_iterator it) const; - /// Inverse of 'index': return the n-th child of the node at position. - static sibling_iterator child(const iterator_base& position, unsigned int); - /// Return iterator to the sibling indicated by index - sibling_iterator sibling(const iterator_base& position, unsigned int); - - /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) - class iterator_base_less { - public: - bool operator()(const typename tree::iterator_base& one, - const typename tree::iterator_base& two) const - { - return one.node < two.node; - } - }; - tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid - private: - tree_node_allocator alloc_; - void head_initialise_(); - void copy_(const tree& other); - - /// Comparator class for two nodes of a tree (used for sorting and searching). - template - class compare_nodes { - public: - compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; - - bool operator()(const tree_node *a, const tree_node *b) - { - return comp_(a->data, b->data); - } - private: - StrictWeakOrdering comp_; - }; -}; - -//template -//class iterator_base_less { -// public: -// bool operator()(const typename tree::iterator_base& one, -// const typename tree::iterator_base& two) const -// { -// txtout << "operatorclass<" << one.node < two.node << std::endl; -// return one.node < two.node; -// } -//}; - -// template -// bool operator<(const typename tree::iterator& one, -// const typename tree::iterator& two) -// { -// txtout << "operator< " << one.node < two.node << std::endl; -// if(one.node < two.node) return true; -// return false; -// } -// -// template -// bool operator==(const typename tree::iterator& one, -// const typename tree::iterator& two) -// { -// txtout << "operator== " << one.node == two.node << std::endl; -// if(one.node == two.node) return true; -// return false; -// } -// -// template -// bool operator>(const typename tree::iterator_base& one, -// const typename tree::iterator_base& two) -// { -// txtout << "operator> " << one.node < two.node << std::endl; -// if(one.node > two.node) return true; -// return false; -// } - - - -// Tree - -template -tree::tree() - { - head_initialise_(); - } - -template -tree::tree(const T& x) - { - head_initialise_(); - set_head(x); - } - -template -tree::tree(const iterator_base& other) - { - head_initialise_(); - set_head((*other)); - replace(begin(), other); - } - -template -tree::~tree() - { - clear(); - alloc_.deallocate(head,1); - alloc_.deallocate(feet,1); - } - -template -void tree::head_initialise_() - { - head = alloc_.allocate(1,0); // MSVC does not have default second argument - feet = alloc_.allocate(1,0); - - head->parent=0; - head->first_child=0; - head->last_child=0; - head->prev_sibling=0; //head; - head->next_sibling=feet; //head; - - feet->parent=0; - feet->first_child=0; - feet->last_child=0; - feet->prev_sibling=head; - feet->next_sibling=0; - } - -template -void tree::operator=(const tree& other) - { - copy_(other); - } - -template -tree::tree(const tree& other) - { - head_initialise_(); - copy_(other); - } - -template -void tree::copy_(const tree& other) - { - clear(); - pre_order_iterator it=other.begin(), to=begin(); - while(it!=other.end()) { - to=insert(to, (*it)); - it.skip_children(); - ++it; - } - to=begin(); - it=other.begin(); - while(it!=other.end()) { - to=replace(to, it); - to.skip_children(); - it.skip_children(); - ++to; - ++it; - } - } - -template -void tree::clear() - { - if(head) - while(head->next_sibling!=feet) - erase(pre_order_iterator(head->next_sibling)); - } - -template -void tree::erase_children(const iterator_base& it) - { -// std::cout << "erase_children " << it.node << std::endl; - if(it.node==0) return; - - tree_node *cur=it.node->first_child; - tree_node *prev=0; - - while(cur!=0) { - prev=cur; - cur=cur->next_sibling; - erase_children(pre_order_iterator(prev)); - kp::destructor(&prev->data); - alloc_.deallocate(prev,1); - } - it.node->first_child=0; - it.node->last_child=0; -// std::cout << "exit" << std::endl; - } - -template -template -iter tree::erase(iter it) - { - tree_node *cur=it.node; - assert(cur!=head); - iter ret=it; - ret.skip_children(); - ++ret; - erase_children(it); - if(cur->prev_sibling==0) { - cur->parent->first_child=cur->next_sibling; - } - else { - cur->prev_sibling->next_sibling=cur->next_sibling; - } - if(cur->next_sibling==0) { - cur->parent->last_child=cur->prev_sibling; - } - else { - cur->next_sibling->prev_sibling=cur->prev_sibling; - } - - kp::destructor(&cur->data); - alloc_.deallocate(cur,1); - return ret; - } - -template -typename tree::pre_order_iterator tree::begin() const - { - return pre_order_iterator(head->next_sibling); - } - -template -typename tree::pre_order_iterator tree::end() const - { - return pre_order_iterator(feet); - } - -template -typename tree::breadth_first_queued_iterator tree::begin_breadth_first() const - { - return breadth_first_queued_iterator(head->next_sibling); - } - -template -typename tree::breadth_first_queued_iterator tree::end_breadth_first() const - { - return breadth_first_queued_iterator(); - } - -template -typename tree::post_order_iterator tree::begin_post() const - { - tree_node *tmp=head->next_sibling; - if(tmp!=feet) { - while(tmp->first_child) - tmp=tmp->first_child; - } - return post_order_iterator(tmp); - } - -template -typename tree::post_order_iterator tree::end_post() const - { - return post_order_iterator(feet); - } - -template -typename tree::fixed_depth_iterator tree::begin_fixed(const iterator_base& pos, unsigned int dp) const - { - typename tree::fixed_depth_iterator ret; - ret.top_node=pos.node; - - tree_node *tmp=pos.node; - unsigned int curdepth=0; - while(curdepthfirst_child==0) { - if(tmp->next_sibling==0) { - // try to walk up and then right again - do { - if(tmp==ret.top_node) - throw std::range_error("tree: begin_fixed out of range"); - tmp=tmp->parent; - if(tmp==0) - throw std::range_error("tree: begin_fixed out of range"); - --curdepth; - } while(tmp->next_sibling==0); - } - tmp=tmp->next_sibling; - } - tmp=tmp->first_child; - ++curdepth; - } - - ret.node=tmp; - return ret; - } - -template -typename tree::fixed_depth_iterator tree::end_fixed(const iterator_base& pos, unsigned int dp) const - { - assert(1==0); // FIXME: not correct yet: use is_valid() as a temporary workaround - tree_node *tmp=pos.node; - unsigned int curdepth=1; - while(curdepthfirst_child==0) { - tmp=tmp->next_sibling; - if(tmp==0) - throw std::range_error("tree: end_fixed out of range"); - } - tmp=tmp->first_child; - ++curdepth; - } - return tmp; - } - -template -typename tree::sibling_iterator tree::begin(const iterator_base& pos) const - { - assert(pos.node!=0); - if(pos.node->first_child==0) { - return end(pos); - } - return pos.node->first_child; - } - -template -typename tree::sibling_iterator tree::end(const iterator_base& pos) const - { - sibling_iterator ret(0); - ret.parent_=pos.node; - return ret; - } - -template -typename tree::leaf_iterator tree::begin_leaf() const - { - tree_node *tmp=head->next_sibling; - if(tmp!=feet) { - while(tmp->first_child) - tmp=tmp->first_child; - } - return leaf_iterator(tmp); - } - -template -typename tree::leaf_iterator tree::end_leaf() const - { - return leaf_iterator(feet); - } - -template -typename tree::leaf_iterator tree::begin_leaf(const iterator_base& top) const - { - tree_node *tmp=top.node; - while(tmp->first_child) - tmp=tmp->first_child; - return leaf_iterator(tmp, top.node); - } - -template -typename tree::leaf_iterator tree::end_leaf(const iterator_base& top) const - { - return leaf_iterator(top.node, top.node); - } - -template -template -iter tree::parent(iter position) - { - assert(position.node!=0); - return iter(position.node->parent); - } - -template -template -iter tree::previous_sibling(iter position) const - { - assert(position.node!=0); - iter ret(position); - ret.node=position.node->prev_sibling; - return ret; - } - -template -template -iter tree::next_sibling(iter position) const - { - assert(position.node!=0); - iter ret(position); - ret.node=position.node->next_sibling; - return ret; - } - -template -template -iter tree::next_at_same_depth(iter position) const - { - // We make use of a temporary fixed_depth iterator to implement this. - - typename tree::fixed_depth_iterator tmp(position.node); - - ++tmp; - return iter(tmp); - -// assert(position.node!=0); -// iter ret(position); -// -// if(position.node->next_sibling) { -// ret.node=position.node->next_sibling; -// } -// else { -// int relative_depth=0; -// upper: -// do { -// ret.node=ret.node->parent; -// if(ret.node==0) return ret; -// --relative_depth; -// } while(ret.node->next_sibling==0); -// lower: -// ret.node=ret.node->next_sibling; -// while(ret.node->first_child==0) { -// if(ret.node->next_sibling==0) -// goto upper; -// ret.node=ret.node->next_sibling; -// if(ret.node==0) return ret; -// } -// while(relative_depth<0 && ret.node->first_child!=0) { -// ret.node=ret.node->first_child; -// ++relative_depth; -// } -// if(relative_depth<0) { -// if(ret.node->next_sibling==0) goto upper; -// else goto lower; -// } -// } -// return ret; - } - -template -template -iter tree::append_child(iter position) - { - assert(position.node!=head); - assert(position.node); - - tree_node *tmp=alloc_.allocate(1,0); - kp::constructor(&tmp->data); - tmp->first_child=0; - tmp->last_child=0; - - tmp->parent=position.node; - if(position.node->last_child!=0) { - position.node->last_child->next_sibling=tmp; - } - else { - position.node->first_child=tmp; - } - tmp->prev_sibling=position.node->last_child; - position.node->last_child=tmp; - tmp->next_sibling=0; - return tmp; - } - -template -template -iter tree::prepend_child(iter position) - { - assert(position.node!=head); - assert(position.node); - - tree_node *tmp=alloc_.allocate(1,0); - kp::constructor(&tmp->data); - tmp->first_child=0; - tmp->last_child=0; - - tmp->parent=position.node; - if(position.node->first_child!=0) { - position.node->first_child->prev_sibling=tmp; - } - else { - position.node->last_child=tmp; - } - tmp->next_sibling=position.node->first_child; - position.node->prev_child=tmp; - tmp->prev_sibling=0; - return tmp; - } - -template -template -iter tree::append_child(iter position, const T& x) - { - // If your program fails here you probably used 'append_child' to add the top - // node to an empty tree. From version 1.45 the top element should be added - // using 'insert'. See the documentation for further information, and sorry about - // the API change. - assert(position.node!=head); - assert(position.node); - - tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); - tmp->first_child=0; - tmp->last_child=0; - - tmp->parent=position.node; - if(position.node->last_child!=0) { - position.node->last_child->next_sibling=tmp; - } - else { - position.node->first_child=tmp; - } - tmp->prev_sibling=position.node->last_child; - position.node->last_child=tmp; - tmp->next_sibling=0; - return tmp; - } - -template -template -iter tree::prepend_child(iter position, const T& x) - { - assert(position.node!=head); - assert(position.node); - - tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); - tmp->first_child=0; - tmp->last_child=0; - - tmp->parent=position.node; - if(position.node->first_child!=0) { - position.node->first_child->prev_sibling=tmp; - } - else { - position.node->last_child=tmp; - } - tmp->next_sibling=position.node->first_child; - position.node->first_child=tmp; - tmp->prev_sibling=0; - return tmp; - } - -template -template -iter tree::append_child(iter position, iter other) - { - assert(position.node!=head); - assert(position.node); - - sibling_iterator aargh=append_child(position, value_type()); - return replace(aargh, other); - } - -template -template -iter tree::prepend_child(iter position, iter other) - { - assert(position.node!=head); - assert(position.node); - - sibling_iterator aargh=prepend_child(position, value_type()); - return replace(aargh, other); - } - -template -template -iter tree::append_children(iter position, sibling_iterator from, sibling_iterator to) - { - assert(position.node!=head); - assert(position.node); - - iter ret=from; - - while(from!=to) { - insert_subtree(position.end(), from); - ++from; - } - return ret; - } - -template -template -iter tree::prepend_children(iter position, sibling_iterator from, sibling_iterator to) - { - assert(position.node!=head); - assert(position.node); - - iter ret=from; - - while(from!=to) { - insert_subtree(position.begin(), from); - ++from; - } - return ret; - } - -template -typename tree::pre_order_iterator tree::set_head(const T& x) - { - assert(head->next_sibling==feet); - return insert(iterator(feet), x); - } - -template -template -iter tree::insert(iter position, const T& x) - { - if(position.node==0) { - position.node=feet; // Backward compatibility: when calling insert on a null node, - // insert before the feet. - } - tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); - tmp->first_child=0; - tmp->last_child=0; - - tmp->parent=position.node->parent; - tmp->next_sibling=position.node; - tmp->prev_sibling=position.node->prev_sibling; - position.node->prev_sibling=tmp; - - if(tmp->prev_sibling==0) { - if(tmp->parent) // when inserting nodes at the head, there is no parent - tmp->parent->first_child=tmp; - } - else - tmp->prev_sibling->next_sibling=tmp; - return tmp; - } - -template -typename tree::sibling_iterator tree::insert(sibling_iterator position, const T& x) - { - tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); - tmp->first_child=0; - tmp->last_child=0; - - tmp->next_sibling=position.node; - if(position.node==0) { // iterator points to end of a subtree - tmp->parent=position.parent_; - tmp->prev_sibling=position.range_last(); - tmp->parent->last_child=tmp; - } - else { - tmp->parent=position.node->parent; - tmp->prev_sibling=position.node->prev_sibling; - position.node->prev_sibling=tmp; - } - - if(tmp->prev_sibling==0) { - if(tmp->parent) // when inserting nodes at the head, there is no parent - tmp->parent->first_child=tmp; - } - else - tmp->prev_sibling->next_sibling=tmp; - return tmp; - } - -template -template -iter tree::insert_after(iter position, const T& x) - { - tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, x); - tmp->first_child=0; - tmp->last_child=0; - - tmp->parent=position.node->parent; - tmp->prev_sibling=position.node; - tmp->next_sibling=position.node->next_sibling; - position.node->next_sibling=tmp; - - if(tmp->next_sibling==0) { - if(tmp->parent) // when inserting nodes at the head, there is no parent - tmp->parent->last_child=tmp; - } - else { - tmp->next_sibling->prev_sibling=tmp; - } - return tmp; - } - -template -template -iter tree::insert_subtree(iter position, const iterator_base& subtree) - { - // insert dummy - iter it=insert(position, value_type()); - // replace dummy with subtree - return replace(it, subtree); - } - -template -template -iter tree::insert_subtree_after(iter position, const iterator_base& subtree) - { - // insert dummy - iter it=insert_after(position, value_type()); - // replace dummy with subtree - return replace(it, subtree); - } - -// template -// template -// iter tree::insert_subtree(sibling_iterator position, iter subtree) -// { -// // insert dummy -// iter it(insert(position, value_type())); -// // replace dummy with subtree -// return replace(it, subtree); -// } - -template -template -iter tree::replace(iter position, const T& x) - { - kp::destructor(&position.node->data); - kp::constructor(&position.node->data, x); - return position; - } - -template -template -iter tree::replace(iter position, const iterator_base& from) - { - assert(position.node!=head); - tree_node *current_from=from.node; - tree_node *start_from=from.node; - tree_node *current_to =position.node; - - // replace the node at position with head of the replacement tree at from -// std::cout << "warning!" << position.node << std::endl; - erase_children(position); -// std::cout << "no warning!" << std::endl; - tree_node* tmp = alloc_.allocate(1,0); - kp::constructor(&tmp->data, (*from)); - tmp->first_child=0; - tmp->last_child=0; - if(current_to->prev_sibling==0) { - if(current_to->parent!=0) - current_to->parent->first_child=tmp; - } - else { - current_to->prev_sibling->next_sibling=tmp; - } - tmp->prev_sibling=current_to->prev_sibling; - if(current_to->next_sibling==0) { - if(current_to->parent!=0) - current_to->parent->last_child=tmp; - } - else { - current_to->next_sibling->prev_sibling=tmp; - } - tmp->next_sibling=current_to->next_sibling; - tmp->parent=current_to->parent; - kp::destructor(¤t_to->data); - alloc_.deallocate(current_to,1); - current_to=tmp; - - // only at this stage can we fix 'last' - tree_node *last=from.node->next_sibling; - - pre_order_iterator toit=tmp; - // copy all children - do { - assert(current_from!=0); - if(current_from->first_child != 0) { - current_from=current_from->first_child; - toit=append_child(toit, current_from->data); - } - else { - while(current_from->next_sibling==0 && current_from!=start_from) { - current_from=current_from->parent; - toit=parent(toit); - assert(current_from!=0); - } - current_from=current_from->next_sibling; - if(current_from!=last) { - toit=append_child(parent(toit), current_from->data); - } - } - } while(current_from!=last); - - return current_to; - } - -template -typename tree::sibling_iterator tree::replace( - sibling_iterator orig_begin, - sibling_iterator orig_end, - sibling_iterator new_begin, - sibling_iterator new_end) - { - tree_node *orig_first=orig_begin.node; - tree_node *new_first=new_begin.node; - tree_node *orig_last=orig_first; - while((++orig_begin)!=orig_end) - orig_last=orig_last->next_sibling; - tree_node *new_last=new_first; - while((++new_begin)!=new_end) - new_last=new_last->next_sibling; - - // insert all siblings in new_first..new_last before orig_first - bool first=true; - pre_order_iterator ret; - while(1==1) { - pre_order_iterator tt=insert_subtree(pre_order_iterator(orig_first), pre_order_iterator(new_first)); - if(first) { - ret=tt; - first=false; - } - if(new_first==new_last) - break; - new_first=new_first->next_sibling; - } - - // erase old range of siblings - bool last=false; - tree_node *next=orig_first; - while(1==1) { - if(next==orig_last) - last=true; - next=next->next_sibling; - erase((pre_order_iterator)orig_first); - if(last) - break; - orig_first=next; - } - return ret; - } - -template -template -iter tree::flatten(iter position) - { - if(position.node->first_child==0) - return position; - - tree_node *tmp=position.node->first_child; - while(tmp) { - tmp->parent=position.node->parent; - tmp=tmp->next_sibling; - } - if(position.node->next_sibling) { - position.node->last_child->next_sibling=position.node->next_sibling; - position.node->next_sibling->prev_sibling=position.node->last_child; - } - else { - position.node->parent->last_child=position.node->last_child; - } - position.node->next_sibling=position.node->first_child; - position.node->next_sibling->prev_sibling=position.node; - position.node->first_child=0; - position.node->last_child=0; - - return position; - } - - -template -template -iter tree::reparent(iter position, sibling_iterator begin, sibling_iterator end) - { - tree_node *first=begin.node; - tree_node *last=first; - - assert(first!=position.node); - - if(begin==end) return begin; - // determine last node - while((++begin)!=end) { - last=last->next_sibling; - } - // move subtree - if(first->prev_sibling==0) { - first->parent->first_child=last->next_sibling; - } - else { - first->prev_sibling->next_sibling=last->next_sibling; - } - if(last->next_sibling==0) { - last->parent->last_child=first->prev_sibling; - } - else { - last->next_sibling->prev_sibling=first->prev_sibling; - } - if(position.node->first_child==0) { - position.node->first_child=first; - position.node->last_child=last; - first->prev_sibling=0; - } - else { - position.node->last_child->next_sibling=first; - first->prev_sibling=position.node->last_child; - position.node->last_child=last; - } - last->next_sibling=0; - - tree_node *pos=first; - for(;;) { - pos->parent=position.node; - if(pos==last) break; - pos=pos->next_sibling; - } - - return first; - } - -template -template iter tree::reparent(iter position, iter from) - { - if(from.node->first_child==0) return position; - return reparent(position, from.node->first_child, end(from)); - } - -template -template iter tree::wrap(iter position, const T& x) - { - assert(position.node!=0); - sibling_iterator fr=position, to=position; - ++to; - iter ret = insert(position, x); - reparent(ret, fr, to); - return ret; - } - -template -template iter tree::move_after(iter target, iter source) - { - tree_node *dst=target.node; - tree_node *src=source.node; - assert(dst); - assert(src); - - if(dst==src) return source; - if(dst->next_sibling) - if(dst->next_sibling==src) // already in the right spot - return source; - - // take src out of the tree - if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; - else src->parent->first_child=src->next_sibling; - if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; - else src->parent->last_child=src->prev_sibling; - - // connect it to the new point - if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; - else dst->parent->last_child=src; - src->next_sibling=dst->next_sibling; - dst->next_sibling=src; - src->prev_sibling=dst; - src->parent=dst->parent; - return src; - } - -template -template iter tree::move_before(iter target, iter source) - { - tree_node *dst=target.node; - tree_node *src=source.node; - assert(dst); - assert(src); - - if(dst==src) return source; - if(dst->prev_sibling) - if(dst->prev_sibling==src) // already in the right spot - return source; - - // take src out of the tree - if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; - else src->parent->first_child=src->next_sibling; - if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; - else src->parent->last_child=src->prev_sibling; - - // connect it to the new point - if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; - else dst->parent->first_child=src; - src->prev_sibling=dst->prev_sibling; - dst->prev_sibling=src; - src->next_sibling=dst; - src->parent=dst->parent; - return src; - } - -// specialisation for sibling_iterators -template -typename tree::sibling_iterator tree::move_before(sibling_iterator target, - sibling_iterator source) - { - tree_node *dst=target.node; - tree_node *src=source.node; - tree_node *dst_prev_sibling; - if(dst==0) { // must then be an end iterator - dst_prev_sibling=target.parent_->last_child; - assert(dst_prev_sibling); - } - else dst_prev_sibling=dst->prev_sibling; - assert(src); - - if(dst==src) return source; - if(dst_prev_sibling) - if(dst_prev_sibling==src) // already in the right spot - return source; - - // take src out of the tree - if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; - else src->parent->first_child=src->next_sibling; - if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; - else src->parent->last_child=src->prev_sibling; - - // connect it to the new point - if(dst_prev_sibling!=0) dst_prev_sibling->next_sibling=src; - else target.parent_->first_child=src; - src->prev_sibling=dst_prev_sibling; - if(dst) { - dst->prev_sibling=src; - src->parent=dst->parent; - } - src->next_sibling=dst; - return src; - } - -template -template iter tree::move_ontop(iter target, iter source) - { - tree_node *dst=target.node; - tree_node *src=source.node; - assert(dst); - assert(src); - - if(dst==src) return source; - - // remember connection points - tree_node *b_prev_sibling=dst->prev_sibling; - tree_node *b_next_sibling=dst->next_sibling; - tree_node *b_parent=dst->parent; - - // remove target - erase(target); - - // take src out of the tree - if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; - else src->parent->first_child=src->next_sibling; - if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; - else src->parent->last_child=src->prev_sibling; - - // connect it to the new point - if(b_prev_sibling!=0) b_prev_sibling->next_sibling=src; - else b_parent->first_child=src; - if(b_next_sibling!=0) b_next_sibling->prev_sibling=src; - else b_parent->last_child=src; - src->prev_sibling=b_prev_sibling; - src->next_sibling=b_next_sibling; - src->parent=b_parent; - return src; - } - -template -void tree::merge(sibling_iterator to1, sibling_iterator to2, - sibling_iterator from1, sibling_iterator from2, - bool duplicate_leaves) - { - sibling_iterator fnd; - while(from1!=from2) { - if((fnd=std::find(to1, to2, (*from1))) != to2) { // element found - if(from1.begin()==from1.end()) { // full depth reached - if(duplicate_leaves) - append_child(parent(to1), (*from1)); - } - else { // descend further - merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(), duplicate_leaves); - } - } - else { // element missing - insert_subtree(to2, from1); - } - ++from1; - } - } - - -template -void tree::sort(sibling_iterator from, sibling_iterator to, bool deep) - { - std::less comp; - sort(from, to, comp, deep); - } - -template -template -void tree::sort(sibling_iterator from, sibling_iterator to, - StrictWeakOrdering comp, bool deep) - { - if(from==to) return; - // make list of sorted nodes - // CHECK: if multiset stores equivalent nodes in the order in which they - // are inserted, then this routine should be called 'stable_sort'. - std::multiset > nodes(comp); - sibling_iterator it=from, it2=to; - while(it != to) { - nodes.insert(it.node); - ++it; - } - // reassemble - --it2; - - // prev and next are the nodes before and after the sorted range - tree_node *prev=from.node->prev_sibling; - tree_node *next=it2.node->next_sibling; - typename std::multiset >::iterator nit=nodes.begin(), eit=nodes.end(); - if(prev==0) { - if((*nit)->parent!=0) // to catch "sorting the head" situations, when there is no parent - (*nit)->parent->first_child=(*nit); - } - else prev->next_sibling=(*nit); - - --eit; - while(nit!=eit) { - (*nit)->prev_sibling=prev; - if(prev) - prev->next_sibling=(*nit); - prev=(*nit); - ++nit; - } - // prev now points to the last-but-one node in the sorted range - if(prev) - prev->next_sibling=(*eit); - - // eit points to the last node in the sorted range. - (*eit)->next_sibling=next; - (*eit)->prev_sibling=prev; // missed in the loop above - if(next==0) { - if((*eit)->parent!=0) // to catch "sorting the head" situations, when there is no parent - (*eit)->parent->last_child=(*eit); - } - else next->prev_sibling=(*eit); - - if(deep) { // sort the children of each node too - sibling_iterator bcs(*nodes.begin()); - sibling_iterator ecs(*eit); - ++ecs; - while(bcs!=ecs) { - sort(begin(bcs), end(bcs), comp, deep); - ++bcs; - } - } - } - -template -template -bool tree::equal(const iter& one_, const iter& two, const iter& three_) const - { - std::equal_to comp; - return equal(one_, two, three_, comp); - } - -template -template -bool tree::equal_subtree(const iter& one_, const iter& two_) const - { - std::equal_to comp; - return equal_subtree(one_, two_, comp); - } - -template -template -bool tree::equal(const iter& one_, const iter& two, const iter& three_, BinaryPredicate fun) const - { - pre_order_iterator one(one_), three(three_); - -// if(one==two && is_valid(three) && three.number_of_children()!=0) -// return false; - while(one!=two && is_valid(three)) { - if(!fun(*one,*three)) - return false; - if(one.number_of_children()!=three.number_of_children()) - return false; - ++one; - ++three; - } - return true; - } - -template -template -bool tree::equal_subtree(const iter& one_, const iter& two_, BinaryPredicate fun) const - { - pre_order_iterator one(one_), two(two_); - - if(!fun(*one,*two)) return false; - if(number_of_children(one)!=number_of_children(two)) return false; - return equal(begin(one),end(one),begin(two),fun); - } - -template -tree tree::subtree(sibling_iterator from, sibling_iterator to) const - { - tree tmp; - tmp.set_head(value_type()); - tmp.replace(tmp.begin(), tmp.end(), from, to); - return tmp; - } - -template -void tree::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const - { - tmp.set_head(value_type()); - tmp.replace(tmp.begin(), tmp.end(), from, to); - } - -template -size_t tree::size() const - { - size_t i=0; - pre_order_iterator it=begin(), eit=end(); - while(it!=eit) { - ++i; - ++it; - } - return i; - } - -template -size_t tree::size(const iterator_base& top) const - { - size_t i=0; - pre_order_iterator it=top, eit=top; - eit.skip_children(); - ++eit; - while(it!=eit) { - ++i; - ++it; - } - return i; - } - -template -bool tree::empty() const - { - pre_order_iterator it=begin(), eit=end(); - return (it==eit); - } - -template -int tree::depth(const iterator_base& it) - { - tree_node* pos=it.node; - assert(pos!=0); - int ret=0; - while(pos->parent!=0) { - pos=pos->parent; - ++ret; - } - return ret; - } - -template -int tree::depth(const iterator_base& it, const iterator_base& root) - { - tree_node* pos=it.node; - assert(pos!=0); - int ret=0; - while(pos->parent!=0 && pos!=root.node) { - pos=pos->parent; - ++ret; - } - return ret; - } - -template -int tree::max_depth() const - { - int maxd=-1; - for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) - maxd=std::max(maxd, max_depth(it)); - - return maxd; - } - - -template -int tree::max_depth(const iterator_base& pos) const - { - tree_node *tmp=pos.node; - - if(tmp==0 || tmp==head || tmp==feet) return -1; - - int curdepth=0, maxdepth=0; - while(true) { // try to walk the bottom of the tree - while(tmp->first_child==0) { - if(tmp==pos.node) return maxdepth; - if(tmp->next_sibling==0) { - // try to walk up and then right again - do { - tmp=tmp->parent; - if(tmp==0) return maxdepth; - --curdepth; - } while(tmp->next_sibling==0); - } - if(tmp==pos.node) return maxdepth; - tmp=tmp->next_sibling; - } - tmp=tmp->first_child; - ++curdepth; - maxdepth=std::max(curdepth, maxdepth); - } - } - -template -unsigned int tree::number_of_children(const iterator_base& it) - { - tree_node *pos=it.node->first_child; - if(pos==0) return 0; - - unsigned int ret=1; -// while(pos!=it.node->last_child) { -// ++ret; -// pos=pos->next_sibling; -// } - while((pos=pos->next_sibling)) - ++ret; - return ret; - } - -template -unsigned int tree::number_of_siblings(const iterator_base& it) const - { - tree_node *pos=it.node; - unsigned int ret=0; - // count forward - while(pos->next_sibling && - pos->next_sibling!=head && - pos->next_sibling!=feet) { - ++ret; - pos=pos->next_sibling; - } - // count backward - pos=it.node; - while(pos->prev_sibling && - pos->prev_sibling!=head && - pos->prev_sibling!=feet) { - ++ret; - pos=pos->prev_sibling; - } - - return ret; - } - -template -void tree::swap(sibling_iterator it) - { - tree_node *nxt=it.node->next_sibling; - if(nxt) { - if(it.node->prev_sibling) - it.node->prev_sibling->next_sibling=nxt; - else - it.node->parent->first_child=nxt; - nxt->prev_sibling=it.node->prev_sibling; - tree_node *nxtnxt=nxt->next_sibling; - if(nxtnxt) - nxtnxt->prev_sibling=it.node; - else - it.node->parent->last_child=it.node; - nxt->next_sibling=it.node; - it.node->prev_sibling=nxt; - it.node->next_sibling=nxtnxt; - } - } - -template -void tree::swap(iterator one, iterator two) - { - // if one and two are adjacent siblings, use the sibling swap - if(one.node->next_sibling==two.node) swap(one); - else if(two.node->next_sibling==one.node) swap(two); - else { - tree_node *nxt1=one.node->next_sibling; - tree_node *nxt2=two.node->next_sibling; - tree_node *pre1=one.node->prev_sibling; - tree_node *pre2=two.node->prev_sibling; - tree_node *par1=one.node->parent; - tree_node *par2=two.node->parent; - - // reconnect - one.node->parent=par2; - one.node->next_sibling=nxt2; - if(nxt2) nxt2->prev_sibling=one.node; - else par2->last_child=one.node; - one.node->prev_sibling=pre2; - if(pre2) pre2->next_sibling=one.node; - else par2->first_child=one.node; - - two.node->parent=par1; - two.node->next_sibling=nxt1; - if(nxt1) nxt1->prev_sibling=two.node; - else par1->last_child=two.node; - two.node->prev_sibling=pre1; - if(pre1) pre1->next_sibling=two.node; - else par1->first_child=two.node; - } - } - -// template -// tree::iterator tree::find_subtree( -// sibling_iterator subfrom, sibling_iterator subto, iterator from, iterator to, -// BinaryPredicate fun) const -// { -// assert(1==0); // this routine is not finished yet. -// while(from!=to) { -// if(fun(*subfrom, *from)) { -// -// } -// } -// return to; -// } - -template -bool tree::is_in_subtree(const iterator_base& it, const iterator_base& begin, - const iterator_base& end) const - { - // FIXME: this should be optimised. - pre_order_iterator tmp=begin; - while(tmp!=end) { - if(tmp==it) return true; - ++tmp; - } - return false; - } - -template -bool tree::is_valid(const iterator_base& it) const - { - if(it.node==0 || it.node==feet || it.node==head) return false; - else return true; - } - -template -unsigned int tree::index(sibling_iterator it) const - { - unsigned int ind=0; - if(it.node->parent==0) { - while(it.node->prev_sibling!=head) { - it.node=it.node->prev_sibling; - ++ind; - } - } - else { - while(it.node->prev_sibling!=0) { - it.node=it.node->prev_sibling; - ++ind; - } - } - return ind; - } - -template -typename tree::sibling_iterator tree::sibling(const iterator_base& it, unsigned int num) - { - tree_node *tmp; - if(it.node->parent==0) { - tmp=head->next_sibling; - while(num) { - tmp = tmp->next_sibling; - --num; - } - } - else { - tmp=it.node->parent->first_child; - while(num) { - assert(tmp!=0); - tmp = tmp->next_sibling; - --num; - } - } - return tmp; - } - - -template -typename tree::sibling_iterator tree::child(const iterator_base& it, unsigned int num) - { - tree_node *tmp=it.node->first_child; - while(num--) { - assert(tmp!=0); - tmp=tmp->next_sibling; - } - return tmp; - } - - - - -// Iterator base - -template -tree::iterator_base::iterator_base() - : node(0), skip_current_children_(false) - { - } - -template -tree::iterator_base::iterator_base(tree_node *tn) - : node(tn), skip_current_children_(false) - { - } - -template -T& tree::iterator_base::operator*() const - { - return node->data; - } - -template -T* tree::iterator_base::operator->() const - { - return &(node->data); - } - -template -bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const - { - if(other.node!=this->node) return true; - else return false; - } - -template -bool tree::post_order_iterator::operator==(const post_order_iterator& other) const - { - if(other.node==this->node) return true; - else return false; - } - -template -bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const - { - if(other.node!=this->node) return true; - else return false; - } - -template -bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const - { - if(other.node==this->node) return true; - else return false; - } - -template -bool tree::sibling_iterator::operator!=(const sibling_iterator& other) const - { - if(other.node!=this->node) return true; - else return false; - } - -template -bool tree::sibling_iterator::operator==(const sibling_iterator& other) const - { - if(other.node==this->node) return true; - else return false; - } - -template -bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const - { - if(other.node!=this->node) return true; - else return false; - } - -template -bool tree::leaf_iterator::operator==(const leaf_iterator& other) const - { - if(other.node==this->node && other.top_node==this->top_node) return true; - else return false; - } - -template -typename tree::sibling_iterator tree::iterator_base::begin() const - { - if(node->first_child==0) - return end(); - - sibling_iterator ret(node->first_child); - ret.parent_=this->node; - return ret; - } - -template -typename tree::sibling_iterator tree::iterator_base::end() const - { - sibling_iterator ret(0); - ret.parent_=node; - return ret; - } - -template -void tree::iterator_base::skip_children() - { - skip_current_children_=true; - } - -template -void tree::iterator_base::skip_children(bool skip) - { - skip_current_children_=skip; - } - -template -unsigned int tree::iterator_base::number_of_children() const - { - tree_node *pos=node->first_child; - if(pos==0) return 0; - - unsigned int ret=1; - while(pos!=node->last_child) { - ++ret; - pos=pos->next_sibling; - } - return ret; - } - - - -// Pre-order iterator - -template -tree::pre_order_iterator::pre_order_iterator() - : iterator_base(0) - { - } - -template -tree::pre_order_iterator::pre_order_iterator(tree_node *tn) - : iterator_base(tn) - { - } - -template -tree::pre_order_iterator::pre_order_iterator(const iterator_base &other) - : iterator_base(other.node) - { - } - -template -tree::pre_order_iterator::pre_order_iterator(const sibling_iterator& other) - : iterator_base(other.node) - { - if(this->node==0) { - if(other.range_last()!=0) - this->node=other.range_last(); - else - this->node=other.parent_; - this->skip_children(); - ++(*this); - } - } - -template -typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() - { - assert(this->node!=0); - if(!this->skip_current_children_ && this->node->first_child != 0) { - this->node=this->node->first_child; - } - else { - this->skip_current_children_=false; - while(this->node->next_sibling==0) { - this->node=this->node->parent; - if(this->node==0) - return *this; - } - this->node=this->node->next_sibling; - } - return *this; - } - -template -typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() - { - assert(this->node!=0); - if(this->node->prev_sibling) { - this->node=this->node->prev_sibling; - while(this->node->last_child) - this->node=this->node->last_child; - } - else { - this->node=this->node->parent; - if(this->node==0) - return *this; - } - return *this; -} - -template -typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) - { - pre_order_iterator copy = *this; - ++(*this); - return copy; - } - -template -typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) -{ - pre_order_iterator copy = *this; - --(*this); - return copy; -} - -template -typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) - { - while(num>0) { - ++(*this); - --num; - } - return (*this); - } - -template -typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) - { - while(num>0) { - --(*this); - --num; - } - return (*this); - } - - - -// Post-order iterator - -template -tree::post_order_iterator::post_order_iterator() - : iterator_base(0) - { - } - -template -tree::post_order_iterator::post_order_iterator(tree_node *tn) - : iterator_base(tn) - { - } - -template -tree::post_order_iterator::post_order_iterator(const iterator_base &other) - : iterator_base(other.node) - { - } - -template -tree::post_order_iterator::post_order_iterator(const sibling_iterator& other) - : iterator_base(other.node) - { - if(this->node==0) { - if(other.range_last()!=0) - this->node=other.range_last(); - else - this->node=other.parent_; - this->skip_children(); - ++(*this); - } - } - -template -typename tree::post_order_iterator& tree::post_order_iterator::operator++() - { - assert(this->node!=0); - if(this->node->next_sibling==0) { - this->node=this->node->parent; - this->skip_current_children_=false; - } - else { - this->node=this->node->next_sibling; - if(this->skip_current_children_) { - this->skip_current_children_=false; - } - else { - while(this->node->first_child) - this->node=this->node->first_child; - } - } - return *this; - } - -template -typename tree::post_order_iterator& tree::post_order_iterator::operator--() - { - assert(this->node!=0); - if(this->skip_current_children_ || this->node->last_child==0) { - this->skip_current_children_=false; - while(this->node->prev_sibling==0) - this->node=this->node->parent; - this->node=this->node->prev_sibling; - } - else { - this->node=this->node->last_child; - } - return *this; - } - -template -typename tree::post_order_iterator tree::post_order_iterator::operator++(int) - { - post_order_iterator copy = *this; - ++(*this); - return copy; - } - -template -typename tree::post_order_iterator tree::post_order_iterator::operator--(int) - { - post_order_iterator copy = *this; - --(*this); - return copy; - } - - -template -typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) - { - while(num>0) { - ++(*this); - --num; - } - return (*this); - } - -template -typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) - { - while(num>0) { - --(*this); - --num; - } - return (*this); - } - -template -void tree::post_order_iterator::descend_all() - { - assert(this->node!=0); - while(this->node->first_child) - this->node=this->node->first_child; - } - - -// Breadth-first iterator - -template -tree::breadth_first_queued_iterator::breadth_first_queued_iterator() - : iterator_base() - { - } - -template -tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) - : iterator_base(tn) - { - traversal_queue.push(tn); - } - -template -tree::breadth_first_queued_iterator::breadth_first_queued_iterator(const iterator_base& other) - : iterator_base(other.node) - { - traversal_queue.push(other.node); - } - -template -bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const - { - if(other.node!=this->node) return true; - else return false; - } - -template -bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const - { - if(other.node==this->node) return true; - else return false; - } - -template -typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() - { - assert(this->node!=0); - - // Add child nodes and pop current node - sibling_iterator sib=this->begin(); - while(sib!=this->end()) { - traversal_queue.push(sib.node); - ++sib; - } - traversal_queue.pop(); - if(traversal_queue.size()>0) - this->node=traversal_queue.front(); - else - this->node=0; - return (*this); - } - -template -typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) - { - breadth_first_queued_iterator copy = *this; - ++(*this); - return copy; - } - -template -typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) - { - while(num>0) { - ++(*this); - --num; - } - return (*this); - } - - - -// Fixed depth iterator - -template -tree::fixed_depth_iterator::fixed_depth_iterator() - : iterator_base() - { - } - -template -tree::fixed_depth_iterator::fixed_depth_iterator(tree_node *tn) - : iterator_base(tn), top_node(0) - { - } - -template -tree::fixed_depth_iterator::fixed_depth_iterator(const iterator_base& other) - : iterator_base(other.node), top_node(0) - { - } - -template -tree::fixed_depth_iterator::fixed_depth_iterator(const sibling_iterator& other) - : iterator_base(other.node), top_node(0) - { - } - -template -tree::fixed_depth_iterator::fixed_depth_iterator(const fixed_depth_iterator& other) - : iterator_base(other.node), top_node(other.top_node) - { - } - -template -bool tree::fixed_depth_iterator::operator==(const fixed_depth_iterator& other) const - { - if(other.node==this->node && other.top_node==top_node) return true; - else return false; - } - -template -bool tree::fixed_depth_iterator::operator!=(const fixed_depth_iterator& other) const - { - if(other.node!=this->node || other.top_node!=top_node) return true; - else return false; - } - -template -typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator++() - { - assert(this->node!=0); - - if(this->node->next_sibling) { - this->node=this->node->next_sibling; - } - else { - int relative_depth=0; - upper: - do { - if(this->node==this->top_node) { - this->node=0; // FIXME: return a proper fixed_depth end iterator once implemented - return *this; - } - this->node=this->node->parent; - if(this->node==0) return *this; - --relative_depth; - } while(this->node->next_sibling==0); - lower: - this->node=this->node->next_sibling; - while(this->node->first_child==0) { - if(this->node->next_sibling==0) - goto upper; - this->node=this->node->next_sibling; - if(this->node==0) return *this; - } - while(relative_depth<0 && this->node->first_child!=0) { - this->node=this->node->first_child; - ++relative_depth; - } - if(relative_depth<0) { - if(this->node->next_sibling==0) goto upper; - else goto lower; - } - } - return *this; - } - -template -typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator--() - { - assert(this->node!=0); - - if(this->node->prev_sibling) { - this->node=this->node->prev_sibling; - } - else { - int relative_depth=0; - upper: - do { - if(this->node==this->top_node) { - this->node=0; - return *this; - } - this->node=this->node->parent; - if(this->node==0) return *this; - --relative_depth; - } while(this->node->prev_sibling==0); - lower: - this->node=this->node->prev_sibling; - while(this->node->last_child==0) { - if(this->node->prev_sibling==0) - goto upper; - this->node=this->node->prev_sibling; - if(this->node==0) return *this; - } - while(relative_depth<0 && this->node->last_child!=0) { - this->node=this->node->last_child; - ++relative_depth; - } - if(relative_depth<0) { - if(this->node->prev_sibling==0) goto upper; - else goto lower; - } - } - return *this; - -// -// -// assert(this->node!=0); -// if(this->node->prev_sibling!=0) { -// this->node=this->node->prev_sibling; -// assert(this->node!=0); -// if(this->node->parent==0 && this->node->prev_sibling==0) // head element -// this->node=0; -// } -// else { -// tree_node *par=this->node->parent; -// do { -// par=par->prev_sibling; -// if(par==0) { // FIXME: need to keep track of this! -// this->node=0; -// return *this; -// } -// } while(par->last_child==0); -// this->node=par->last_child; -// } -// return *this; - } - -template -typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator++(int) - { - fixed_depth_iterator copy = *this; - ++(*this); - return copy; - } - -template -typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator--(int) - { - fixed_depth_iterator copy = *this; - --(*this); - return copy; - } - -template -typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator-=(unsigned int num) - { - while(num>0) { - --(*this); - --(num); - } - return (*this); - } - -template -typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator+=(unsigned int num) - { - while(num>0) { - ++(*this); - --(num); - } - return *this; - } - - -// Sibling iterator - -template -tree::sibling_iterator::sibling_iterator() - : iterator_base() - { - set_parent_(); - } - -template -tree::sibling_iterator::sibling_iterator(tree_node *tn) - : iterator_base(tn) - { - set_parent_(); - } - -template -tree::sibling_iterator::sibling_iterator(const iterator_base& other) - : iterator_base(other.node) - { - set_parent_(); - } - -template -tree::sibling_iterator::sibling_iterator(const sibling_iterator& other) - : iterator_base(other), parent_(other.parent_) - { - } - -template -void tree::sibling_iterator::set_parent_() - { - parent_=0; - if(this->node==0) return; - if(this->node->parent!=0) - parent_=this->node->parent; - } - -template -typename tree::sibling_iterator& tree::sibling_iterator::operator++() - { - if(this->node) - this->node=this->node->next_sibling; - return *this; - } - -template -typename tree::sibling_iterator& tree::sibling_iterator::operator--() - { - if(this->node) this->node=this->node->prev_sibling; - else { - assert(parent_); - this->node=parent_->last_child; - } - return *this; -} - -template -typename tree::sibling_iterator tree::sibling_iterator::operator++(int) - { - sibling_iterator copy = *this; - ++(*this); - return copy; - } - -template -typename tree::sibling_iterator tree::sibling_iterator::operator--(int) - { - sibling_iterator copy = *this; - --(*this); - return copy; - } - -template -typename tree::sibling_iterator& tree::sibling_iterator::operator+=(unsigned int num) - { - while(num>0) { - ++(*this); - --num; - } - return (*this); - } - -template -typename tree::sibling_iterator& tree::sibling_iterator::operator-=(unsigned int num) - { - while(num>0) { - --(*this); - --num; - } - return (*this); - } - -template -typename tree::tree_node *tree::sibling_iterator::range_first() const - { - tree_node *tmp=parent_->first_child; - return tmp; - } - -template -typename tree::tree_node *tree::sibling_iterator::range_last() const - { - return parent_->last_child; - } - -// Leaf iterator - -template -tree::leaf_iterator::leaf_iterator() - : iterator_base(0), top_node(0) - { - } - -template -tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) - : iterator_base(tn), top_node(top) - { - } - -template -tree::leaf_iterator::leaf_iterator(const iterator_base &other) - : iterator_base(other.node), top_node(0) - { - } - -template -tree::leaf_iterator::leaf_iterator(const sibling_iterator& other) - : iterator_base(other.node), top_node(0) - { - if(this->node==0) { - if(other.range_last()!=0) - this->node=other.range_last(); - else - this->node=other.parent_; - ++(*this); - } - } - -template -typename tree::leaf_iterator& tree::leaf_iterator::operator++() - { - assert(this->node!=0); - if(this->node->first_child!=0) { // current node is no longer leaf (children got added) - while(this->node->first_child) - this->node=this->node->first_child; - } - else { - while(this->node->next_sibling==0) { - if (this->node->parent==0) return *this; - this->node=this->node->parent; - if (top_node != 0 && this->node==top_node) return *this; - } - this->node=this->node->next_sibling; - while(this->node->first_child) - this->node=this->node->first_child; - } - return *this; - } - -template -typename tree::leaf_iterator& tree::leaf_iterator::operator--() - { - assert(this->node!=0); - while (this->node->prev_sibling==0) { - if (this->node->parent==0) return *this; - this->node=this->node->parent; - if (top_node !=0 && this->node==top_node) return *this; - } - this->node=this->node->prev_sibling; - while(this->node->last_child) - this->node=this->node->last_child; - return *this; - } - -template -typename tree::leaf_iterator tree::leaf_iterator::operator++(int) - { - leaf_iterator copy = *this; - ++(*this); - return copy; - } - -template -typename tree::leaf_iterator tree::leaf_iterator::operator--(int) - { - leaf_iterator copy = *this; - --(*this); - return copy; - } - - -template -typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) - { - while(num>0) { - ++(*this); - --num; - } - return (*this); - } - -template -typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) - { - while(num>0) { - --(*this); - --num; - } - return (*this); - } - -#endif - -// Local variables: -// default-tab-width: 3 -// End: diff -Nru 3depict-0.0.12/src/viscontrol.cpp 3depict-0.0.13/src/viscontrol.cpp --- 3depict-0.0.12/src/viscontrol.cpp 2012-11-17 23:27:53.000000000 +0000 +++ 3depict-0.0.13/src/viscontrol.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1930 +0,0 @@ -/* - * viscontrol.cpp - visualation-user interface glue code - * Copyright (C) 2012, 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 . -*/ - -#include "wxcommon.h" -#include "xmlHelper.h" -#include "viscontrol.h" - -#include -#include - -#ifdef DEBUG -//Only needed for assertion check -#include -#endif - -#include "scene.h" -#include "drawables.h" - -#include "translation.h" - - -using std::list; -using std::stack; - -//oh no! global. window to safeYield/ needs to be set -wxWindow *yieldWindow=0; - -wxStopWatch* delayTime=0; -//Another global - whether to abort the vis control -// operation, or not -bool *abortVisCtlOp=0; - -void upWxTreeCtrl(const FilterTree &filterTree, wxTreeCtrl *t, - std::map &filterMap,vector &persistentFilters, - const Filter *visibleFilt) -{ - //Remove any filters that don't exist any more - for(unsigned int ui=persistentFilters.size();ui--;) - { - if(!filterTree.contains(persistentFilters[ui])) - { - std::swap(persistentFilters[ui],persistentFilters.back()); - persistentFilters.pop_back(); - } - } - - stack treeIDs; - //Warning: this generates an event, - //most of the time (some windows versions do not according to documentation) - t->DeleteAllItems(); - - //Clear the mapping - filterMap.clear(); - size_t nextID=0; - - size_t lastDepth=0; - //Add dummy root node. This will be invisible to wxTR_HIDE_ROOT controls - wxTreeItemId tid; - tid=t->AddRoot(wxT("TreeBase")); - t->SetItemData(tid,new wxTreeUint(nextID)); - - // Push on stack to prevent underflow, but don't keep a copy, - // as we will never insert or delete this from the UI - treeIDs.push(tid); - - nextID++; - std::map reverseFilterMap; - //Depth first add - for(tree::pre_order_iterator filtIt=filterTree.depthBegin(); - filtIt!=filterTree.depthEnd(); ++filtIt) - { - //Push or pop the stack to make it match the iterator position - if( lastDepth > filterTree.depth(filtIt)) - { - while(filterTree.depth(filtIt) +1 < treeIDs.size()) - treeIDs.pop(); - } - else if( lastDepth < filterTree.depth(filtIt)) - { - treeIDs.push(tid); - } - - - lastDepth=filterTree.depth(filtIt); - - //This will use the user label or the type string. - tid=t->AppendItem(treeIDs.top(), - wxStr((*filtIt)->getUserString())); - t->SetItemData(tid,new wxTreeUint(nextID)); - - - //Record mapping to filter for later reference - filterMap[nextID]=*filtIt; - //Remember the reverse mapping for later in - // this function when we reset visibility - reverseFilterMap[*filtIt] = tid; - - nextID++; - } - - //Try to restore the selection in a user friendly manner - // - Try restoring all requested filter's visibility - // - then restore either the first requested filter as the selection - // or the specified parameter filter as the selection. - if(persistentFilters.size()) - { - for(unsigned int ui=0;uiEnsureVisible(reverseFilterMap[persistentFilters[ui]]); - - if(!visibleFilt) - t->SelectItem(reverseFilterMap[persistentFilters[0]]); - else - t->SelectItem(reverseFilterMap[visibleFilt]); - - persistentFilters.clear(); - } - else if(visibleFilt) - { - t->SelectItem(reverseFilterMap[visibleFilt]); - } - t->GetParent()->Layout(); - -} - - -//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 whtehr or not to allow for overriding of the timer -bool wxYieldCallback(bool forceYield) -{ - const unsigned int YIELD_MS=75; - - ASSERT(delayTime); - //Rate limit the updates - if(delayTime->Time() > YIELD_MS || forceYield) - { - wxSafeYield(yieldWindow); - delayTime->Start(); - } - - ASSERT(abortVisCtlOp); - return !(*abortVisCtlOp); -} - - -VisController::VisController() -{ - targetScene=0; - targetPlots=0; - targetRawGrid=0; - doProgressAbort=false; - ASSERT(!abortVisCtlOp); - abortVisCtlOp=&doProgressAbort; - amRefreshing=false; - pendingUpdates=false; - useRelativePathsForSave=false; - curProg.reset(); - //Assign global variable its init value - ASSERT(!delayTime); //Should not have been inited 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; - delayTime=0; -} - - -void VisController::addFilter(Filter *f, bool isBase,size_t parentId) -{ - if(!isBase) - filterTree.addFilter(f,filterMap[parentId]); - else - filterTree.addFilter(f,0); - - //the filter map is now invalid, as we added an element to the tree, - //and dont' have a unique value for it. we need to relayout. - filterMap.clear(); -} - -void VisController::addFilterTree(FilterTree &f, bool isBase,size_t parentId) -{ - ASSERT(!(isBase && parentId==(unsigned int)-1)); - - if(isBase) - filterTree.addFilterTree(f,0); - else - filterTree.addFilterTree(f,filterMap[parentId]); - - //the filter map is now invalid, as we added an element to the tree, - //and dont' have a unique value for it. we need to relayout. - filterMap.clear(); -} - -void VisController::switchoutFilterTree(FilterTree &f) -{ - //Create a clone of the internal tree - f=filterTree; - - //Fix up the internal filterMap to reflect the contents of the new tree - //--- - // - //Build a map from old filter*->new filter * - tree::pre_order_iterator itB; - itB=filterTree.depthBegin(); - std::map filterRemap; - for(tree::pre_order_iterator itA=f.depthBegin(); itA!=f.depthEnd(); ++itA) - { - filterRemap[*itA]=*itB; - ++itB; - } - - //Overwrite the internal map - for(map::iterator it=filterMap.begin();it!=filterMap.end();++it) - it->second=filterRemap[it->second]; - - - //Swap the internal tree with our clone - f.swap(filterTree); -} - -//!Duplicate a branch of the tree to a new position. Do not copy cache, -bool VisController::copyFilter(size_t toCopy, size_t newParent,bool copyToRoot) -{ - bool ret; - if(copyToRoot) - ret=filterTree.copyFilter(filterMap[toCopy],0); - else - - ret=filterTree.copyFilter(filterMap[toCopy],filterMap[newParent]); - - if(ret) - { - //Delete the filtermap, as the current data is not valid anymore - filterMap.clear(); - } - - return ret; -} - - -const Filter* VisController::getFilterById(size_t filterId) const -{ - //If triggering this assertion, check that - //::updateWxTreeCtrl called after calling addFilterTree. - ASSERT(filterMap.size()); - - //Check that the mapping exists - ASSERT(filterMap.find(filterId)!=filterMap.end()); - return filterMap.at(filterId); -} - -size_t VisController::getIdByFilter(const Filter *f) const -{ - for(map::const_iterator it=filterMap.begin();it!=filterMap.end();++it) - { - if(it->second == f) - return it->first; - - } - - ASSERT(false); - return -1; //keep gcc quiet -} - -void VisController::getFiltersByType(std::vector &filters, unsigned int type) const -{ - filterTree.getFiltersByType(filters,type); -} - - -void VisController::removeFilterSubtree(size_t filterId) -{ - //Save current filter state to undo stack - pushUndoStack(); - filterTree.removeSubtree(filterMap[filterId]); - //Delete the filtermap, as the current data is not valid anymore - filterMap.clear(); -} - - -bool VisController::setFilterProperty(size_t filterId, - unsigned int key, const std::string &value, bool &needUpdate) -{ - //Save current filter state to undo stack - //for the case where the property change is good - pushUndoStack(); - bool setOK; - setOK=filterTree.setFilterProperty(filterMap[filterId],key,value,needUpdate); - - if(!setOK) - { - //Didn't work, so we need to discard the undo - //Pop the undo stack, but don't restore it - - // restoring would destroy the cache - popUndoStack(false); - } - - return setOK; -} - -unsigned int VisController::refreshFilterTree(bool doUpdateScene) -{ - ASSERT(!amRefreshing); - - //Analyse the fitler tree structure for any errors - //-- - fta.clear(); - fta.analyse(filterTree); - //-- - - doProgressAbort=false; - amRefreshing=true; - delayTime->Start(); - - curProg.reset(); - - typedef std::pair > filterOutputData; - list refreshData; - - - //Apply any remaining updates if we have them - if(pendingUpdates) - getFilterUpdates(); - targetScene->clearBindings(); - - //Run the tree refresh system. - unsigned int errCode; - vector *> devices; - vector > consoleMessages; - errCode=filterTree.refreshFilterTree(refreshData,devices, - consoleMessages,curProg,wxYieldCallback); - - - const Filter *lastFilt=0; - for(size_t ui=0;uiAppendText(wxStr(lastFilt->getUserString())); - textConsole->AppendText(wxT("\n------------\n")); - } - textConsole->AppendText(wxStr(consoleMessages[ui].second)); - textConsole->AppendText(wxT("\n")); - } - - if(consoleMessages.size()) - textConsole->AppendText(wxT("\n")); - - - if(errCode) - { - amRefreshing=false; - return errCode; - } - - //strip off the source filter information for - //convenience in this routine - list > outData; - for(list::iterator it=refreshData.begin(); it!=refreshData.end(); ++it) - { - ASSERT(it->second.size()); - - outData.push_back(it->second); - } - - - targetScene->clearObjs(); - targetScene->addSelectionDevices(devices); - - if(doUpdateScene) - updateScene(outData); - //Stop timer - delayTime->Pause(); - amRefreshing=false; - - return 0; -} - -unsigned int VisController::refreshFilterTree( - list > > &outData) -{ - vector *> devices; - vector > consoleStrs; - return filterTree.refreshFilterTree(outData,devices, - consoleStrs,curProg,wxYieldCallback); -} - -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); -} - -void VisController::setYieldWindow(wxWindow *newYield) -{ - yieldWindow=newYield; -} - -void VisController::setWxTreeFilterViewPersistence(size_t filterId) -{ - persistentFilters.push_back(filterMap[filterId]); -} - -void VisController::updateWxTreeCtrl(wxTreeCtrl *t, const Filter *visibleFilt) -{ - upWxTreeCtrl(filterTree,t,filterMap,persistentFilters,visibleFilt); -} - -void VisController::updateFilterPropGrid(wxPropertyGrid *g,size_t filterId) const -{ - //The filterID can never be set to zero, - //except for the root item, as set by - //upWxTreeCtrl - ASSERT(filterId); - ASSERT(filterMap.size() == filterTree.size()); - - Filter *targetFilter; - targetFilter=filterMap.at(filterId); - - ASSERT(targetFilter); - - updateFilterPropertyGrid(g,targetFilter); -} - - -bool VisController::setCamProperties(size_t camUniqueID,unsigned int key, const std::string &value) -{ - return targetScene->setCamProperty(camUniqueID,key,value); -} - - - - - -bool VisController::hasUpdates() const -{ - if(pendingUpdates) - return true; - - return filterTree.hasUpdates(); - -} - -void VisController::getFilterUpdates() -{ - vector > bindings; - targetScene->getModifiedBindings(bindings); - - if(bindings.size()) - pushUndoStack(); - - for(unsigned int ui=0;ui::iterator it=filterTree.depthBegin(); - it!=filterTree.depthEnd();++it) - { - if(*it == bindings[ui].first) - { - //We are modifying the contents of - //the filter, this could make a change that - //modifies output so we need to clear - //all subtree caches to force reprocessing - filterTree.clearCache(*it); - - (*it)->setPropFromBinding(bindings[ui].second); -#ifdef DEBUG - haveBind=true; -#endif - break; - } - } - - ASSERT(haveBind); - - } - - //we have retrieved the updates. - pendingUpdates=false; -} - -//public interface to updateScene -unsigned int VisController::doUpdateScene(list > &sceneData, - bool releaseData) -{ - amRefreshing=true; - unsigned int errCode=updateScene(sceneData,releaseData); - amRefreshing=false; - return errCode; - -} -unsigned int VisController::updateScene(list > &sceneData, - bool releaseData) -{ - //Plot wrapper should be set - ASSERT(targetPlots); - //Plot window should be set - ASSERT(plotSelList) - - //Should be called from a viscontrol refresh - ASSERT(amRefreshing); - - //Lock the opengl scene interaction, - // to prevent user interaction (eg devices) during callbacks - targetScene->lockInteraction(); - targetPlots->lockInteraction(); - - //Buffer to transfer to scene - vector sceneDrawables; - - //erase the contents of each plot - targetPlots->clear(true); //Clear, but preserve selection information. - - vector > plotLabels; - - //-- Build buffer of new objects to send to scene - - for(list > ::iterator it=sceneData.begin(); - it!=sceneData.end(); ++it) - { - - ASSERT(it->size()); - for(unsigned int ui=0;uisize(); ui++) - { - //Filter must specify whether it is cached or not. other values - //are inadmissible, but useful to catch uninitialised values - ASSERT((*it)[ui]->cached == 0 || (*it)[ui]->cached == 1); - - switch((*it)[ui]->getStreamType()) - { - case STREAM_TYPE_IONS: - { - //Create a new group for this stream. - // We have to have individual groups - // because of colouring/sizing concerns. - DrawManyPoints *curIonDraw; - curIonDraw=new DrawManyPoints; - - - //Obtain the ion data pointer - const IonStreamData *ionData; - ionData=((const IonStreamData *)((*it)[ui])); - - - curIonDraw->resize(ionData->data.size()); - //Slice out just the coordinate data for the - // ion pointer, run callback immediately - // after, as its a long operation - #pragma omp parallel for shared(curIonDraw,ionData) - for(size_t ui=0;uidata.size();ui++) - curIonDraw->setPoint(ui,ionData->data[ui].getPosRef()); - (*wxYieldCallback)(true); - - //Set the colour from the ionstream data - curIonDraw->setColour(ionData->r, - ionData->g, - ionData->b, - ionData->a); - //set the size from the ionstream data - curIonDraw->setSize(ionData->ionSize); - //Randomly shuffle the ion data before we draw it - curIonDraw->shuffle(); - //Run callback to update as needed, as shuffle is slow. - (*wxYieldCallback)(true); - - //place in special holder for ions, - // as we need to accumulate for display-listing - // later. - sceneDrawables.push_back(curIonDraw); - break; - } - case STREAM_TYPE_PLOT: - { - const PlotStreamData *plotData; - plotData=((PlotStreamData *)((*it)[ui])); - - //The plot should have some data in it. - ASSERT(plotData->getNumBasicObjects()); - //The plot should have a parent filter - ASSERT(plotData->parent); - //The plot should have an index, so we can keep - //filter choices between refreshes (where possible) - ASSERT(plotData->index !=(unsigned int)-1); - //Construct a new plot - unsigned int plotID; - - switch(plotData->plotMode) - { - case PLOT_MODE_1D: - { - //Create a 1D plot - Plot1D *plotNew= new Plot1D; - - plotNew->setData(plotData->xyData); - plotNew->setLogarithmic(plotData->logarithmic); - plotNew->titleAsRawDataLabel=plotData->useDataLabelAsYDescriptor; - - //Construct any regions that the plot may have - for(unsigned int ui=0;uiregions.size();ui++) - { - //add a region to the plot, - //using the region data stored - //in the plot stream - plotNew->addRegion(plotID, - plotData->regionID[ui], - plotData->regions[ui].first, - plotData->regions[ui].second, - plotData->regionR[ui], - plotData->regionG[ui], - plotData->regionB[ui],plotData->regionParent); - } - - plotID=targetPlots->addPlot(plotNew); - break; - } - default: - ASSERT(false); - } - - - //set the appearance of the plot - // ----- - targetPlots->setTraceStyle(plotID,plotData->plotStyle); - targetPlots->setColours(plotID,plotData->r, - plotData->g,plotData->b); - - std::wstring xL,yL,titleW; - std::string x,y,t; - - xL=stlStrToStlWStr(plotData->xLabel); - yL=stlStrToStlWStr(plotData->yLabel); - titleW=stlStrToStlWStr(plotData->dataLabel); - - x=stlWStrToStlStr(xL); - y=stlWStrToStlStr(yL); - t=stlWStrToStlStr(titleW); - - targetPlots->setStrings(plotID,x,y,t); - // ----- - - //set the data origin - targetPlots->setParentData(plotID,plotData->parent, - plotData->index); - - plotLabels.push_back(make_pair(plotID,plotData->dataLabel)); - - break; - } - case STREAM_TYPE_DRAW: - { - DrawStreamData *drawData; - drawData=((DrawStreamData *)((*it)[ui])); - - //Retrieve vector - const std::vector *drawObjs; - drawObjs = &(drawData->drawables); - //Loop through vector, Adding each object to the scene - if(drawData->cached) - { - ASSERT(false); - //FIXME: IMPLEMENT ME - //Create a *copy* for scene. Filter still holds - //originals, and will dispose of the pointers accordingly - //for(unsigned int ui=0;uisize();ui++) - // sceneDrawables.push_back((*drawObjs)[ui]->clone()); - } - else - { - //Place the *pointers* to the drawables in the scene - // list, to avoid copying - for(unsigned int ui=0;uisize();ui++) - sceneDrawables.push_back((*drawObjs)[ui]); - - //Although we do not delete the drawable objects - //themselves, we do delete the container - - //Zero-size the internal vector to - //prevent vector destructor from deleting pointers - //we have transferrred ownership of to scene - drawData->drawables.clear(); - } - break; - } - case STREAM_TYPE_RANGE: - //silently drop rangestreams - break; - case STREAM_TYPE_VOXEL: - { - //Technically, we are violating const-ness - VoxelStreamData *vSrc = (VoxelStreamData *)((*it)[ui]); - //Create a new Field3D - Voxels *v = new Voxels; - - //Make a copy if cached; otherwise just steal it. - if(vSrc->cached) - vSrc->data.clone(*v); - else - v->swap(vSrc->data); - - switch(vSrc->representationType) - { - case VOXEL_REPRESENT_POINTCLOUD: - { - DrawField3D *d = new DrawField3D; - d->setField(v); - d->setColourMapID(0); - d->setColourMinMax(); - d->setBoxColours(vSrc->r,vSrc->g,vSrc->b,vSrc->a); - d->setPointSize(vSrc->splatSize); - d->setAlpha(vSrc->a); - d->wantsLight=false; - - sceneDrawables.push_back(d); - break; - } - case VOXEL_REPRESENT_ISOSURF: - { - DrawIsoSurface *d = new DrawIsoSurface; - - d->swapVoxels(v); - d->setColour(vSrc->r,vSrc->g, - vSrc->b,vSrc->a); - d->setScalarThresh(vSrc->isoLevel); - - d->wantsLight=true; - - sceneDrawables.push_back(d); - break; - } - default: - ASSERT(false); - ; - } - - break; - } - } - - //delete drawables as needed - if(!(*it)[ui]->cached && releaseData) - { - delete (*it)[ui]; - (*it)[ui]=0; - } - - //Run the callback to update the window as needed - (*wxYieldCallback)(true); - - } - - } - //--- - - //Construct an OpenGL display list from the dataset - - //Check how many points we have. Too many can cause the display list to crash - size_t totalIonCount=0; - for(unsigned int ui=0;uigetType() == DRAW_TYPE_MANYPOINT) - totalIonCount+=((const DrawManyPoints*)(sceneDrawables[ui]))->getNumPts(); - } - - - //Must lock UI controls, or not run callback from here on in! - //========== - - //Update the plotting UI contols - //----------- - plotSelList->Clear(); // erase wx list - - for(size_t ui=0;uiAppend(wxStr(plotLabels[ui].second),l); - } - plotLabels.clear(); - - //If there is only one spectrum, select it - if(plotSelList->GetCount() == 1 ) - plotSelList->SetSelection(0); - else if( plotSelList->GetCount() > 1) - { - //Otherwise try to use the last visibility information - //to set the selection - targetPlots->bestEffortRestoreVisibility(); - -#if defined(__WIN32__) || defined(__WIN64__) - //Bug under windows. SetSelection(wxNOT_FOUND) does not work for multiseletion list boxes - plotSelList->SetSelection(-1, false); -#else - plotSelList->SetSelection(wxNOT_FOUND); //Clear selection -#endif - for(unsigned int ui=0; uiGetCount();ui++) - { - wxListUint *l; - unsigned int plotID; - - //Retreive the uniqueID - l=(wxListUint*)plotSelList->GetClientObject(ui); - plotID = l->value; - if(targetPlots->isPlotVisible(plotID)) - plotSelList->SetSelection(ui); - } - } - targetPlots->lockInteraction(false); - //----------- - - - - 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) - vector drawIons; - for(size_t ui=0;uigetType() == DRAW_TYPE_MANYPOINT) - drawIons.push_back((DrawManyPoints*)sceneDrawables[ui]); - } - - if(totalIonCount < MAX_NUM_DRAWABLE_POINTS && drawIons.size() >1) - { - //Try to use a display list where we can. - //note that the display list requires a valid bounding box, - //so single point entities, or overlapped points can - //produce an invalid bounding box - DrawDispList *displayList; - displayList = new DrawDispList(); - - bool listStarted=false; - for(unsigned int ui=0;uigetBoundingBox(b); - if(b.isValid()) - { - - if(!listStarted) - { - displayList->startList(false); - listStarted=true; - } - displayList->addDrawable(drawIons[ui]); - delete drawIons[ui]; - } - else - targetScene->addDrawable(drawIons[ui]); - } - - if(listStarted) - { - displayList->endList(); - targetScene->addDrawable(displayList); - } - } - else - { - for(unsigned int ui=0;uiaddDrawable(drawIons[ui]); - } - - for(size_t ui=0;uigetType() != STREAM_TYPE_IONS) - targetScene->addDrawable(sceneDrawables[ui]); - } - - sceneDrawables.clear(); - targetScene->computeSceneLimits(); - targetScene->lockInteraction(false); - //=============== - - - return 0; -} - - - - -unsigned int VisController::addCam(const std::string &camName) -{ - Camera *c=targetScene->cloneActiveCam(); - c->setUserString(camName); - //Store the camera - unsigned int id = targetScene->addCam(c); - targetScene->setActiveCam(0); - return id; -} - -bool VisController::removeCam(unsigned int uniqueID) -{ - targetScene->removeCam(uniqueID); - targetScene->setDefaultCam(); - return true; -} - -bool VisController::setCam(unsigned int uniqueID) -{ - targetScene->setActiveCam(uniqueID); - return true; -} - -void VisController::updateCamPropertyGrid(wxPropertyGrid *g,unsigned int camID) const -{ - - g->clearKeys(); - if(targetScene->isDefaultCam()) - return; - - CameraProperties p; - - targetScene->getCamProperties(camID,p); - - g->setNumGroups(p.data.size()); - //Create the keys for the property grid to do its thing - for(unsigned int ui=0;uiaddKey(p.data[ui][uj].first, ui,p.keys[ui][uj], - p.types[ui][uj],p.data[ui][uj].second,string("")); - } - } - - //Let the property grid layout what it needs to - g->propertyLayout(); -} - -bool VisController::reparentFilter(size_t filter, size_t newParent) -{ - //Save current filter state to undo stack - pushUndoStack(); - - //Try to reparent this filter. It might not work, if, for example - // the new parent is actually a child of the filter we are trying to - // assign the parent to. - if(!filterTree.reparentFilter(filterMap[filter],filterMap[newParent])) - { - //Pop the undo stack, to reverse our - //push, but don't restore it, - // as this would cost us our filter caches - popUndoStack(false); - return false; - } - - 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()) - { - p->setUserString(s); - return true; - } - - return false; -} - -unsigned int VisController::numCams() const -{ - return targetScene->getNumCams(); -} - -void VisController::ensureSceneVisible(unsigned int direction) -{ - targetScene->ensureVisible(direction); -} - -bool VisController::saveState(const char *cpFilename, std::map &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 << "" <" << endl; - f<" << endl; - //write general settings - //--------------- - float backR,backG,backB; - - targetScene->getBackgroundColour(backR,backG,backB); - f << tabs(1) << "" << endl; - - f << tabs(1) << "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) << ""<< 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) << ""<< endl; - } - } - - //--------------- - - - //Write filter tree - //--------------- - if(!filterTree.saveXML(f,fileMapping,writePackage,useRelativePathsForSave)) - return false; - //--------------- - - vector camVec; - - unsigned int active=targetScene->duplicateCameras(camVec); - - //First camera is hidden "working" camera. do not record - if(camVec.size() > 1) - { - f <" << endl; - //subtract 1 to eliminate "hidden" camera offset - f << tabs(2) << "" << endl; - - for(unsigned int ui=1;uiwriteState(f,STATE_FORMAT_XML,2); - delete camVec[ui]; - } - f <" << endl; - } - - if(camVec.size()) - delete camVec[0]; - camVec.clear(); - - if(stashedFilters.size()) - { - f << tabs(1) << "" << endl; - - for(unsigned int ui=0;ui" << endl; - } - - //Save any effects - vector effectVec; - targetScene->getEffects(effectVec); - - if(effectVec.size()) - { - f <" << endl; - for(unsigned int ui=0;uiwriteState(f,STATE_FORMAT_XML,1); - f <" << endl; - - } - - - - //Close XMl tag. - f<< "" << endl; - - //Debug check to ensure we have written a valid xml file - ASSERT(isValidXML(cpFilename)); - - return true; -} - -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(); - - - 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 newCameraVec; - vector newEffectVec; - vector > newStashes; - - std::string stateDir=onlyDir(cpFilename); - unsigned int activeCam; - try - { - std::stack 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 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); - - - 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 visibilty - 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)) - return false; - } - else - { - errStream << TRANS("Unable to interpret the camera type") << endl; - throw 1; - } - - ASSERT(thisCam); - newCameraVec.push_back(thisCam); - } - - 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(); - - //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;uigetType()== 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;uiclearCams(); - - //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); - } - - for(unsigned int ui=0;uicamNameExists(newCameraVec[ui]->getUserString()) && --maxCount) - { - newCameraVec[ui]->setUserString(newCameraVec[ui]->getUserString()+"-merge"); - } - - if(maxCount) - { - 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); - } - } - - if(newEffectVec.size()) - { - targetScene->clearEffects(); - for(unsigned int ui=0;uiaddEffect(newEffectVec[ui]); - } - } - - //Perform sanitisation on results - return true; -} - - -void VisController::clear() -{ - filterMap.clear(); - - filterTree.clear(); - - undoFilterStack.clear(); -} - -void VisController::getCamData(std::vector > &camData) const -{ - targetScene->getCameraIDs(camData); -} - -unsigned int VisController::getActiveCamId() const -{ - return targetScene->getActiveCamId(); -} - -unsigned int VisController::exportIonStreams(const std::vector &selectedStreams, - const std::string &outFile, unsigned int format) -{ - - //test file open, and truncate file to zero bytes - ofstream f(outFile.c_str(),ios::trunc); - - if(!f) - return 1; - - f.close(); - - for(unsigned int ui=0; uigetStreamType()) - { - case STREAM_TYPE_IONS: - { - const IonStreamData *ionData; - ionData=((const IonStreamData *)(selectedStreams[ui])); - switch(format) - { - case IONFORMAT_POS: - { - //Append this ion stream to the posfile - appendPos(ionData->data,outFile.c_str()); - - break; - } - default: - ASSERT(false); - break; - } - } - } - } - - return 0; -} - - -void VisController::addStashedToFilters(const Filter *parent, unsigned int stashId) -{ - ASSERT(stashId > &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 > > plotData; - vector > labels; - //grab the data for the currently visible plots - targetPlots->getRawData(plotData,labels); - - - unsigned int curCol=0; - unsigned int startCol; - - //Clear the grid - if(targetRawGrid->GetNumberCols()) - targetRawGrid->DeleteCols(0,targetRawGrid->GetNumberCols()); - if(targetRawGrid->GetNumberRows()) - targetRawGrid->DeleteRows(0,targetRawGrid->GetNumberRows()); - - for(unsigned int ui=0;uiAppendCols(plotData[ui].size()); - ASSERT(labels[ui].size() == plotData[ui].size()); - - - startCol=curCol; - for(unsigned int uj=0;ujSetColLabelValue(curCol,wxStr(s)); - curCol++; - } - - //set the data - for(unsigned int uj=0;uj targetRawGrid->GetNumberRows()) - targetRawGrid->AppendRows(plotData[ui][uj].size()-targetRawGrid->GetNumberRows()); - - for(unsigned int uk=0;ukSetCellValue(uk,startCol,wxStr(tmpStr)); - } - startCol++; - } - - } -} - -void VisController::setCachePercent(unsigned int newCache) -{ - filterTree.setCachePercent(newCache); -} - - -void VisController::pushUndoStack() -{ - FilterTree newTree; - newTree = filterTree; - if(undoFilterStack.size() > MAX_UNDO_SIZE) - undoFilterStack.pop_front(); - - undoFilterStack.push_back(newTree); - redoFilterStack.clear(); -} - -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(); - - if(restorePopped) - { - //Swap the current filter cache out with the undo stack result - std::swap(filterTree,undoFilterStack.back()); - - //Filter topology has changed. Update - 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()); - - //Pop the redo stack - redoFilterStack.pop_back(); - - //Filter topology has changed. Update - filterTree.initFilterTree(); -} - -void VisController::updateConsole(const std::vector &v, const Filter *f) const -{ - for(unsigned int ui=0; uigetUserString() + string(" : ") + v[ui]; - textConsole->AppendText(wxStr(s)); - textConsole->AppendText(_("\n")); - - } -} - - -bool VisController::getAxisVisible() const -{ - return targetScene->getWorldAxisVisible(); -} - - -void VisController::setStrongRandom(bool strongRand) -{ - Filter::setStrongRandom(strongRand); - - //Invalidate every filter cache. - filterTree.clearCache(0); - -} - - -void VisController::setEffects(bool enable) -{ - targetScene->setEffects(enable); -} - - -bool VisController::hasHazardousContents() const -{ - for(size_t ui=0;uiisPureDataSource(); - -} - -void VisController:: safeDeleteFilterList(std::list > > &outData, - size_t typeMask, bool maskPrevents) const -{ - filterTree.safeDeleteFilterList(outData,typeMask,maskPrevents); -} -//--------------- - diff -Nru 3depict-0.0.12/src/viscontrol.h 3depict-0.0.13/src/viscontrol.h --- 3depict-0.0.12/src/viscontrol.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/viscontrol.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,436 +0,0 @@ -/* - * viscontrol.h - Visualisation control header; "glue" between user interface and scene - * Copyright (C) 2012, 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 . -*/ - -#ifndef VISCONTROL_H -#define VISCONTROL_H - -#include "wxcomponents.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - - - -class VisController; -#include "scene.h" - -#include "filtertree.h" -#include "filtertreeAnalyse.h" -#include "plot.h" - -const unsigned int MAX_UNDO_SIZE=10; - - -//TODO: Find a better home sourcefile for this function? -//!Update a wxTree control to layout according to the specified filter tree -void upWxTreeCtrl(const FilterTree &filterTree, wxTreeCtrl *t, - std::map &filterMap,vector &persistentFilters, - const Filter *visibleFilt); - - -//!Visualisation controller -/*! - * Keeps track of what visualisation controls the user has available - * such as cameras, filters and data groups. - * This is essentially responsible for interfacing between program - * data structures and the user interface. - * - * Only one of these should be instantiated at any time (such as due to abort mechanisms). - */ -class VisController -{ - private: - //!Target scene - Scene *targetScene; - //!Target Plot wrapper system - PlotWrapper *targetPlots; - //!Target raw grid - wxGrid *targetRawGrid; - - //!UI element for console output - wxTextCtrl *textConsole; - - //!UI element for selecting plots from a list (for enable/disable) - wxListBox *plotSelList; - - - //--- Data storage ---- - //!Primary data storage for filter tree - FilterTree filterTree; - - //!Analysis results for last filter tree refresh - FilterTreeAnalyse fta; - - //!Undo filter tree stack - std::deque undoFilterStack,redoFilterStack; - - //!Named, stored trees that can be put aside for secondary use - std::vector > stashedFilters; - - //!Unique IDs for stash - UniqueIDHandler stashUniqueIDs; - //-------------------- - - //!True if viscontrol should abort current operation - bool doProgressAbort; - - //!True if viscontrol is in the middle of a refresh operation - bool amRefreshing; - - //!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; - - - void clear(); - - - //!Retreive the updates to the filter tree from the scene - void getFilterUpdates(); - - - - //!Push the current filter tree onto the undo stack - void pushUndoStack(); - - - //!Erase the redo stack - void clearRedoStack(); - - - - //!Update the console strings - void updateConsole(const std::vector &v, const Filter *f) const; - - //!Force an update to the scene. - unsigned int updateScene(std::list > &outputData,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 - std::map filterMap; - - //Filters that should be able to be seen next time we show - // the wxTree control - std::vector persistentFilters; - - //Working directory for filter tree file operations - std::string workingDir; - - public: - VisController(); - ~VisController(); - - //Filter tree access functions - //----------------- - //!Run a refresh of the underlying tree. Returns 0 on success - // iff return value == 0, then scene update has been initiated - unsigned int refreshFilterTree(bool doUpdateScene=true); - - - - //!Force an update to the scene. - unsigned int doUpdateScene(std::list > &outputData, bool releaseData=true); - - //obtain the outputs from the filter tree's refresh. - // The outputs *must* be deleted with safeDeleteFilterList - unsigned int refreshFilterTree( - std::list > > &outputData); - - //Obtain a clone of the active filter tree - void cloneFilterTree(FilterTree &f) const{f=filterTree;}; - - //!Safely delete data generated by refreshFilterTree(...). - //a mask can be used to *prevent* STREAM_TYPE_blah from being deleted. Deleted items are removed from the list. - void safeDeleteFilterList(std::list > > &outData, - size_t typeMask=0, bool maskPrevents=true) const; - - - //!Add a new filter to the tree. set isbase=false and parentID for not - //setting a parent (ie making filter base) - void addFilter(Filter *f, bool isBase, size_t parentId); - - - //!Add a new subtree to the tree. Note that the tree will be cleared - // as a result of this operation. Control of all pointers will be handled internally. - // If you wish to use ::getFilterById you *must* rebuild the tree control with - // ::updateWxTreeCtrl - void addFilterTree(FilterTree &f,bool isBase=true, - size_t parentId=(unsigned int)-1); - - //!Grab the filter tree from the internal one, and swap the - // internal with a cloned copy. Can be used eg, to steal the cache - // Note that the passed filter tree will be destroyed. - // -> This implies the tree comes *OUT* of viscontrol, - // and a tree cannot be inserted in via this function - void switchoutFilterTree(FilterTree &f); - - //Perform a swap operation on the filter tree. - // - *must* have same topology, or you must call updateWxTreeCtrl - // - can be used to *insert* a tree into this function - void swapFilterTree(FilterTree &f) { f.swap(filterTree);} - - //!Duplicate a branch of the tree to a new position. Do not copy cache, - bool copyFilter(size_t toCopy, size_t newParent,bool copyToRoot=false) ; - - //TODO: Deprecate me - filter information should not be leaking like this! - //Get the ID of the filter from its actual pointer - size_t getIdByFilter(const Filter* f) const; - - const Filter* getFilterById(size_t filterId) const; - - //!Return all of a given type of filter from the filter tree - void getFiltersByType(std::vector &filters, unsigned int type) const; - - //!Returns true if the tree contains any state overrides (external entity referrals) - bool hasStateOverrides() const - {return filterTree.hasStateOverrides();}; - - //!Make the filters safe for the end user, assuming the filter tree could have had - // its data initialised from anywhere - void stripHazardousContents() { filterTree.stripHazardousContents();}; - - //!Get the analysis results for the last refresh - void getAnalysisResults(vector &res) const { fta.getAnalysisResults(res);} - - //!Return the number of filters currently in the main tree - size_t numFilters() const { return filterTree.size();}; - - //!Clear the cache for the filters - void purgeFilterCache() { filterTree.purgeCache();}; - - //!Delete a filter and all its children - void removeFilterSubtree(size_t filterId); - - //Move a filter from one part of the tree to another - bool reparentFilter(size_t filterID, size_t newParentID); - - //!Set the properties using a key-value result (as obtained from updatewxPropertyGrid) - /* - * The return code tells whether to reject or accept the change. - * need update tells us if the change to the filter resulted in a change to the scene - */ - bool setFilterProperty(size_t filterId,unsigned int key, - const std::string &value, bool &needUpdate); - - //!Set the filter's string - bool setFilterString(size_t id, const std::string &s); - - //!Clear all caches - void clearCache(); - - //!Clear all caches - void clearCacheByType(unsigned int type) { filterTree.clearCacheByType(type);}; - - //----------------- - - - - - - //!Call to get viscontrol to abort current operation. Call once per abort. - void abort() {ASSERT(!doProgressAbort);doProgressAbort=true;} - - //!Call to set window to be partially excluded (wx dependant) from blocking during scene updates - void setYieldWindow(wxWindow *win); - - //!Set the text console - void setConsole(wxTextCtrl *t) { textConsole = t;} - //!Set the backend scene - void setScene(Scene *theScene); - //!Set the backend plot - void setPlotWrapper(PlotWrapper *thePlots){targetPlots=thePlots;}; - //!Set the listbox for plot selection - void setPlotList(wxListBox *box){plotSelList=box;}; - - - //!Set the backend grid control for raw data - void setRawGrid(wxGrid *theRawGrid){targetRawGrid=theRawGrid;}; - - - //!Write out the filters into a wxtreecontrol. - void updateWxTreeCtrl(wxTreeCtrl *t,const Filter *f=0); - //!Update a wxtGrid with the properties for a given filter - void updateFilterPropGrid(wxPropertyGrid *g,size_t filterId) const; - - - - - //!Set the camera to use in the scene - bool setCam(unsigned int uniqueID) ; - - //!Remove a camera from the scene - bool removeCam(unsigned int uniqueID); - - //!Add a new camera to the scene - 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; - - //!Return the number of cameras - unsigned int numCams() const ; - - //!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, - unsigned int key, const std::string &value); - - - //!Ensure visible - void ensureSceneVisible(unsigned int direction); - - - - //!Return the current working directory for when loading/saving state file contents - std::string getWorkDir() const { return workingDir;}; - - //!Set current working dir used when saving state files - void setWorkDir(const std::string &wd) { workingDir=wd;}; - - - //!Save the viscontrol state: writes an XML file containing the viscontrol state - bool saveState(const char *filename, std::map &fileMapping, - bool writePackage=false) 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; - - //!Load the viscontrol state, optionally merging this tree with the currently loaded tree. Also, as an option, we can bypass updating any UI data, for debug purposes - 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;}; - - //!Set whether to use relative paths when saving - void setUseRelPaths(bool useRelPaths){ useRelativePathsForSave=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 > &camData) const; - - //!Get the active camera ID - unsigned int getActiveCamId() const; - - //!export given filterstream data pointers - static unsigned int exportIonStreams(const std::vector &selected, - const std::string &outFile, unsigned int format=IONFORMAT_POS); - - //!Returns true if the filter is in the midst of a refresh - bool isRefreshing() const {return amRefreshing; } - - //!Inform viscontrol that it has new updates to filters from external sources (eg bindings) - void setUpdates() { pendingUpdates=true;}; - - //!Returns true if the scene has updates that need to be processed - bool hasUpdates() const; - - - //"Stash" operations - // - The stashes are secondary trees that are not part of the update - // but can be stored for reference (eg to recall common tree sequences) - //---- - //!Create a new stash. Returns ID for stash - unsigned int stashFilters(unsigned int filterID, const char *stashName); - - //!Add a stash as a subtree for the specified parent filter - void addStashedToFilters(const Filter *parentFilter, unsigned int stashID); - - //!Delete a stash using its uniqueID - void deleteStash(unsigned int stashID); - - //!Retreive the stash filters - void getStashes(std::vector > &stashes) const; - - //!Retreive a given stash tree by ID - void getStashTree(unsigned int stashId, FilterTree &) const; - - //!Get the number of stashes - unsigned int getNumStashes() const { return stashedFilters.size();} - - //---- - - void updateRawGrid() const; - - //!Set the percentage of ram to use for cache. 0 to disable - void setCachePercent(unsigned int percent); - - - //!restore top filter tree from undo stack - void popUndoStack(bool restorePopped=true); - - //!restore top filter tree from redo stack - void popRedoStack(); - - //!Get the size of the undo stack - unsigned int getUndoSize() const { return undoFilterStack.size();}; - //!Get the size of the redo stack - unsigned int getRedoSize() const { return redoFilterStack.size();}; - - //!Get the current progress - ProgressData getProgress() const { return curProg;} - - //!reset the progress data - void resetProgress() { curProg.reset();}; - - //!Return the scene's world axis visibility - bool getAxisVisible() const; - - //!Set whether filter should use strong or weak randomisation - void setStrongRandom(bool strongRand); - - //!Set whether to use effects or not - void setEffects(bool enable); - - - //!return true if the primary tree contains hazardous filters - bool hasHazardousContents() const ; - - //!Ask that next time we build the tree, this filter is kept visible/selected. - // may be used repeatedly to make more items visible, - // prior to calling updateWxTreeCtrl. - // filterId must exist during call. - void setWxTreeFilterViewPersistence(size_t filterId); - - - //!Ask if a given filter is a pure data source - bool filterIsPureDataSource(size_t filterId) const ; - -#ifdef DEBUG - //Check that the tree conrol is synced up to the filter map correctly - void checkTree(wxTreeCtrl *t); -#endif -}; - - -#endif diff -Nru 3depict-0.0.12/src/voxels.h 3depict-0.0.13/src/voxels.h --- 3depict-0.0.12/src/voxels.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/voxels.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2526 +0,0 @@ - /* - * voxels.h - Voxelised data manipulation class - * 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 - * 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 . - */ - -#ifndef VOXELS_H -#define VOXELS_H - - -const unsigned int MAX_CALLBACK=500; - -#include "basics.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#ifdef _OPENMP - #include -#endif - -//!Boundary clipping mode -/*! These constants defines the behaviour of the routines when presented with a - * boundary value problem, such as in convolution. - */ -enum{ - BOUND_CLIP=1, - BOUND_HOLD, - BOUND_DERIV_HOLD, - BOUND_MIRROR, - BOUND_ZERO -}; - - -enum{ - ADJ_ALL, - ADJ_PLUS -}; - -//Error codes -enum{ - VOXELS_BAD_FILE_READ=1, - VOXELS_BAD_FILE_OPEN, - VOXELS_BAD_FILE_SIZE, - VOXELS_OUT_OF_MEMORY -}; - -//Must be power of two (buffer size when loading files, in sizeof(T)s) -const unsigned int ITEM_BUFFER_SIZE=65536; - -//!Clipping direction constants -/*! Controls the clipping direction when performing clipping operations - */ -enum { - CLIP_NONE=0, - CLIP_LOWER_SOUTH_WEST, - CLIP_UPPER_NORTH_EAST -}; - - -enum { - VOXEL_ABORT_ERR, - VOXEL_MEMORY_ERR, - VOXEL_BOUNDS_INVALID_ERR -}; - -#ifdef _OPENMP -//Auto-detect the openMP iterator type. -#if ( __GNUC__ > 4 && __GNUC_MINOR__ > 3 ) - #define MP_INT_TYPE size_t -#else - #define MP_INT_TYPE long long -#endif -#else - #define MP_INT_TYPE size_t -#endif - - -//!Template class that stores 3D voxel data -/*! To instantiate this class, objects must have - * basic mathematical operators, such as * + - and = - */ -template class Voxels -{ - private: - //!Number of bins in data set (X,Y,Z) - size_t binCount[3]; - - //!Voxel array - std::vector voxels; - - //!Scaling value for furthest bound of the dataset. - //Dataset is assumed to sit in a rectilinear volume from minBound - //to maxBound - Point3D minBound, maxBound; - - bool (*callback)(bool); - - public: - //!Constructor. - Voxels(); - //!Destructor - ~Voxels(); - - //!Swap object contents with other voxel object - void swap(Voxels &v); - - //!Clone this into another object - void clone(Voxels &newClone) const; - - //!Set the value of a point in the dataset - void setPoint(const Point3D &pt, const T &val); - //!Retrieve the value of a datapoint - T getPointData(const Point3D &pt) const; - - - //!Retrieve the XYZ voxel location associated with a given position - void getIndex(size_t &x, size_t &y, - size_t &z, const Point3D &p) const; - - //!Retrieve the XYZ voxel location associated with a given position, - // including upper borders - void getIndexWithUpper(size_t &x, size_t &y, - size_t &z, const Point3D &p) const; - - //!Get the position associated with an XYZ voxel - Point3D getPoint(size_t x, - size_t y, size_t z) const; - //!Retrieve the value of a specific voxel - inline T getData(size_t x, size_t y, size_t z) const; - //!Retrieve value of the nth voxel - inline T getData(size_t i) const { return voxels[i];} - //Return a padded version of the data. Valid pads are BOUND_* - T getPaddedData(long long x, long long y, long long z, - unsigned int padMode) const; - - - void setEntry(size_t n, const T &val) { voxels[n] = val;}; - //!Retrieve a reference to the data ata given position - //const T &getDataRef(size_t x, size_t y, size_t z) const; - //!Set the value of a point in the dataset - 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 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();}; - - //!Resize the data field - /*! This will destroy any data that was already in place - * If the data needs to be preserved use "resizeKeepData" - * Data will *not* be initialised - */ - size_t resize(size_t newX, size_t newY, size_t newZ, const Point3D &newMinBound=Point3D(0.0f,0.0f,0.0f), const Point3D &newMaxBound=Point3D(1.0f,1.0f,1.0f)); - - size_t resize(const Voxels &v); - - //!Resize the data field, maintaining data as best as possible - /*! This will preserve data by resizing as much as possible - * about the origin. If the bounds are extended, the "fill" value is used - * by default iff doFill is set to true. - */ - size_t resizeKeepData(size_t &newX, size_t &newY, size_t &newZ, - unsigned int direction=CLIP_LOWER_SOUTH_WEST, const Point3D &newMinBound=Point3D(0.0f,0.0f,0.0f), const Point3D &newMaxBound=Point3D(1.0f,1.0f,1.0f), const T &fill=T(0),bool doFill=false); - - - - //!Get a unique integer that corresponds to the edge index for the voxel; where edges are shared between voxels - /*! Each voxel has 12 edges. These are shared (except - * voxels that on zero or positive boundary). Return a - * unique index that corresponds to a specified edge (0->11) - */ - size_t getEdgeIndex(size_t x,size_t y, size_t z, unsigned int edge) const; - - - //!Convert the edge index (as generated by getEdgeIndex) into a cenre position - // returns the axis value so you know edge vector too. - // NOte that the value to pass as the edge index is (getEdgeIndex>>2)<<2 to - // make the ownership of the voxel correct - void getEdgeEnds(size_t edgeIndex,Point3D &a, Point3D &b) const; - - - - //TODO: there is duplicate code between this and getEdgeEnds. Refactor. - //!Return the values that are associated with the edge ends, as returned by getEdgeEnds - void getEdgeEndApproxVals(size_t edgeUniqId, float &a, float &b ) const; - - - //!Rebin the data by a given rate - /*! This will perform a quick and dirty rebin operation, where groups of datablocks - * are binned into a single cell. Number of blocks binned is rate^3. Field must be larger than rate - * in all directions. Currently only CLIP_NONE is supported. - */ - void rebin(Voxels &dest, size_t rate, size_t clipMode=CLIP_NONE) const; - - //!Get the total value of the data field. - /*! An "initial value" is provided to provide the definition of a zero value - */ - T getSum(const T &initialVal=T(0.0)) const; - - //!count the number of cells with at least this intensity - size_t count(const T &minIntensity) const; - - //!Fill all voxels with a given value - void fill(const T &val); - //!Get the bounding size - Point3D getMinBounds() const; - Point3D getMaxBounds() const; - ///! Get the spacing for a unit cell - Point3D getPitch() const; - //!Set the bounding size - void setBounds(const Point3D &pMin, const Point3D &pMax); - - //!Initialise the voxel storage - size_t init(size_t nX,size_t nY,size_t nZ, const BoundCube &bound); - //!Initialise the voxel storage - size_t init(size_t nX,size_t nY, size_t nZ); - //!Load the voxels from file - /*! Format is flat size_ts in column major - * return codes: - * 1: File open error - * 2: Data size error - */ - size_t loadFile(const char *cpFilename, size_t nX, - size_t nY, size_t nZ, bool silent=false); - //!Write the voxel objects in column major written out to file - /*! Format is flat objects ("T"s) in column major format. - * Returns nonzero on failure - */ - size_t writeFile(const char *cpFilename) const; - - //!Run convolution over this data, placing the correlation data into "result" - /*! - * Datasets MUST have the same pitch (spacing) for the result to be defined - * template type must have a T(0.0) constructor that intialises it to some "zero" - */ - size_t convolve(const Voxels &templateVec, Voxels &result, - size_t boundMode=BOUND_CLIP) const; - - - //!Similar to convolve, but faster -- only works with separable kernels. - //Destroys original data in process. - /*! - * Datasets MUST have the same pitch (spacing) for the result to be defined - * template type must have a T(0.0) constructor that intialises it to some "zero" - */ - size_t separableConvolve(const Voxels &templateVec, Voxels &result, - size_t boundMode=BOUND_CLIP); - - //!Set this object to a normalised gaussian kernel, centered around the middle of the dataset - void setGaussianKernelCube(float stdDev, float bound, size_t sideLen); - - //!Second derivative by difference approximation - /*! Returns the first order central difference approximation to the - * second derivative. Bound mode can (when implemented) bye used to compute - * appropriate differences. - */ - void secondDifference(Voxels &result, size_t boundMode=BOUND_CLIP) const; - - - //!Find the positions of the voxels that are above or below a given value - /*! Returns the positions of the voxels' centroids for voxels that have, by default, - * a value greater than that of thresh. This behaviour can by reversed to "lesser than" - * by setting lowerEq to false - */ - void thresholdForPosition(std::vector &p, const T &thresh, bool lowerEq=false) const; - - - - //!Construct a spherical kernel - /* The spherical result is located at the centre of the voxel set - * sideLen -The side length is the diameter of the sphere - * bound -the bounding value that the voxels contain themselves within - * val - the value that the voxels take on for a full sphere. - * antialiasingLevel - the number of times to subdivide the voxels into 8 parts - * and test these voxels for internal/external. The resultant fraction of inside/outside voxels is summed. - */ - void makeSphericalKernel(size_t sideLen, float bound, const T &val, unsigned int antialiasLevel=0); - - //!Return the sizeof value for the T type - /*! Maybe there is a better way to do this, I don't know - */ - static size_t sizeofType() { return sizeof(T);}; - - - //!Binarise the data into a result vector - /* On thresholding (val > thresh), set the value to "onThresh". - * Otherwise set to "offthresh" - */ - void binarise(Voxels &result,const T &thresh, const T &onThresh, - const T &offThresh) const; - - - //!Empty the data - /*Remove the data from the voxel set - */ - void clear() { voxels.clear();}; - - //!Find minimum in dataset - T min() const; - - //!Find maximum in dataset - T max() const; - - //!Find both min and max in dataset in the same loop - void minMax(T &min, T &max) const; - - //!Given some coordinates and radii, generate a voxel dataset of solid spheres superimposed - /*! The radius specified is in the bounding units - * clear value optionally wipes the dataset before continuing - */ - void fillSpheresByPosition( const std::vector &spherePos, float rad, const T &value, bool doErase=true); - - - //!Generate a histogram of data values. / operator must be defined for target type - /*! Data bins are evenly spaced between min and max. Formula for binning is (val-min())/(max()-min())*histBinCount - */ - int histogram(std::vector &v, size_t histBinCount) const; - - //!Find the largest or smallest n objects - void findSorted(std::vector &x, std::vector &y, std::vector &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 - * are set by calling ::setBounds() with the - * appropriate parameters for your data. - * Disabling nowrap allows you to "saturate" your - * data field in the case of dense regions, rather - * than let wrap-around errors occur - */ - int countPoints( const std::vector &points, bool noWrap=true, bool doErase=false); - - //! Convert voxel intensity into voxel density - // this is done by dividing each voxel by its volume - void calculateDensity(); - - float getBinVolume() const; - //!increment the position specified - inline void increment(size_t x, size_t y, size_t z){ - //Typecast everything to at least 64 bit uints. - voxels[(size_t)z*(size_t)binCount[1]*(size_t)binCount[0] - +(size_t)y*(size_t)binCount[0] + (size_t)x]++;} - - void setCallbackMethod(bool (*cb)(bool)) {callback = cb;} - - //!Element wise division - void operator/=(const Voxels &v); - - void operator/=(const T &v); - -}; - -//!Convert one type of voxel into another by assignment operator -template -void castVoxels(const Voxels &src, Voxels &dest) -{ - size_t x,y,z; - - //Resize the dest - src.getSize(x,y,z); - - dest.resize(x,y,z,src.getBounds()); - - size_t numEntries=x*y*z; -#pragma omp parallel for - for(MP_INT_TYPE ui=0; ui <(MP_INT_TYPE)numEntries; ui++) - { - dest.setEntry(ui,src.getData(ui)); - } - -} - -//!Use one counting type to sum counts in a voxel of given type -template -void sumVoxels(const Voxels &src, U &counter) -{ - size_t nx,ny,nz; - - src.getSize(nx,ny,nz); - - counter=0; - for(size_t ui=0; ui -Voxels::Voxels() : voxels(), minBound(Point3D(0,0,0)), maxBound(Point3D(1,1,1)) -{ -} - -template -Voxels::~Voxels() -{ -} - - -template -void Voxels::clone(Voxels &newVox) const -{ - newVox.binCount[0]=binCount[0]; - newVox.binCount[1]=binCount[1]; - newVox.binCount[2]=binCount[2]; - - newVox.voxels.resize(voxels.size()); - newVox.minBound=minBound; - newVox.maxBound=maxBound; - - std::copy(voxels.begin(),voxels.end(),newVox.voxels.begin()); - -} - -template -void Voxels::setPoint(const Point3D &point,const T &val) -{ - ASSERT(voxels.size()); - size_t pos[3]; - for(size_t ui=0;ui<3;ui++) - pos[ui] = (size_t)round(point[ui]*(float)binCount[ui]); - - - voxels[pos[2]*binCount[1]*binCount[0] + pos[1]*binCount[0] + pos[0]]=val; -} - -template -void Voxels::setData(size_t x, size_t y, - size_t z, const T &val) -{ - ASSERT(voxels.size()); - - ASSERT( x < binCount[0] && y < binCount[1] && z < binCount[2]); - voxels[z*binCount[1]*binCount[0] + y*binCount[0] + x]=val; -} - -template -inline void Voxels::setData(size_t n, const T &val) -{ - ASSERT(voxels.size()); - ASSERT(n -T Voxels::getPointData(const Point3D &point) const -{ - ASSERT(voxels.size()); - size_t pos[3]; - for(size_t ui=0;ui<3;ui++) - pos[ui] = (size_t)round(point[ui]*(float)binCount[ui]); - - return voxels[pos[2]*binCount[1]*binCount[0] + pos[1]*binCount[0] + pos[0]]; -} - -template -Point3D Voxels::getPoint(size_t x, size_t y, size_t z) const -{ - ASSERT(x < binCount[0] && y -Point3D Voxels::getPitch() const -{ - return Point3D((float)1.0/(float)binCount[0]*(maxBound[0]-minBound[0]), - (float)1.0/(float)binCount[1]*(maxBound[1]-minBound[1]), - (float)1.0/(float)binCount[2]*(maxBound[2]-minBound[2])); -} - -template -void Voxels::getSize(size_t &x, size_t &y, size_t &z) const -{ - ASSERT(voxels.size()); - x=binCount[0]; - y=binCount[1]; - z=binCount[2]; -} - - -template -size_t Voxels::getEdgeIndex(size_t x,size_t y, size_t z, unsigned int index) const -{ - //This provides a reversable mapping of x,y,z - //X aligned edges are first - //Y second - //Z third - - - //Consider each parallel set of edges (eg all the X aligned edges) - //to be the dual grid of the actual grid. From this you can visualise the - //cell centres moving -1/2 -/12 units in the direction normal to the edge direction - //to produce the centres of the edge. An additional vertex needs to be created at - //the end of each dimension not equal to the alignement dim. - - - // ->ASCII ART TIME<- - // In each individual cube, the offsets look like this: - // ------------7----------- - // \ |\ . - // |\ | \ . - // | 10 | 11 - // | \ | \ . - // | \ | \ . - // | \ --------6-------------| - // | | | | - // 2 | 3 | | - // | | | | - // | | | | - // | | | | - // | 0 | 1 - // \-----|----5----------- | - // \ | \ | - // 8 | 9 | - // \ | \ | - // \ |---------4------------ - // - // ^x - // z|\ | - // \ | - // \-->y - // - - switch(index) - { - //X axis aligned - //-- - case 0: - break; - case 1: - y++; // one across in Y - break; - case 2: - z++;//One across in Z - break; - case 3: - y++; - z++; - break; - //-- - - //Y Axis aligned - //-- - case 4: - break; - case 5: - z++; - break; - case 6: - x++; - break; - case 7: - z++; - x++; - break; - //-- - - //Z Axis aligned - //-- - case 8: - break; - case 9: - y++; - break; - case 10: - x++; - break; - case 11: - x++; - y++; - break; - //-- - } - - - size_t result = 12*(z + y*(binCount[2]+1) + x*(binCount[2]+1)*(binCount[1]+1)) + - index; - - return result; - -} - -template -void Voxels::getEdgeEnds(size_t edgeUniqId, Point3D &a, Point3D &b ) const -{ - //Invert the mapping generated by the edgeUniqId function - //to retrieve the XYZ and axis values - size_t x,y,z; - - int index; // Per voxel edge number. See ascii art in getEdgeidx - index=edgeUniqId %12; - - //Drop the non-owner part of the voxel - index/=4; - index*=4; - - size_t tmp; - tmp=edgeUniqId; - tmp/=12; // shift out the index multiplier - - x = tmp/((binCount[2]+1)*(binCount[1]+1)); - tmp-=x*((binCount[2]+1)*(binCount[1]+1)); - - y=tmp/(binCount[2]+1); - tmp-=y*(binCount[2]+1); - - z=tmp; - - - - - ASSERT(x< binCount[0]+1 && y::epsilon())); - ASSERT(bc.containsPt(a) && bc.containsPt(b)); -#endif -} - -template -void Voxels::getEdgeEndApproxVals(size_t edgeUniqId, float &a, float &b ) const -{ - //Invert the mapping generated by the edgeUniqId function - //to retrieve the XYZ and axis values - size_t x,y,z; - - int index; // Per voxel edge number. See ascii art in getEdgeidx - index=edgeUniqId %12; - - size_t tmp; - tmp=edgeUniqId; - tmp/=12; // shift out the index multiplier - - x = tmp/((binCount[2]+1)*(binCount[1]+1)); - tmp-=x*((binCount[2]+1)*(binCount[1]+1)); - - y=tmp/(binCount[2]+1); - tmp-=y*(binCount[2]+1); - - z=tmp; - - - ASSERT(x< binCount[0]+1 && y -size_t Voxels::resize(size_t x, size_t y, size_t z, const Point3D &newMinBound, const Point3D &newMaxBound) -{ - voxels.clear(); - - binCount[0] = x; - binCount[1] = y; - binCount[2] = z; - - - minBound=newMinBound; - maxBound=newMaxBound; - - size_t binCountMax = binCount[0]*binCount[1]*binCount[2]; - try - { - voxels.resize(binCountMax); - } - catch(...) - { - return 1; - } - - return 0; -} - -template -size_t Voxels::resize(const Voxels &oth) -{ - return resize(oth.binCount[0],oth.binCount[1],oth.binCount[2],oth.minBound,oth.maxBound); -} - -template -size_t Voxels::resizeKeepData(size_t &newX, size_t &newY, size_t &newZ, - unsigned int direction, const Point3D &newMinBound, const Point3D &newMaxBound, const T &fill,bool doFill) -{ - - ASSERT(doFill); - ASSERT(direction==CLIP_LOWER_SOUTH_WEST); - - Voxels v; - - if(v.resize(newX,newY,newZ)) - return 1; - - switch(direction) - { - case CLIP_LOWER_SOUTH_WEST: - { - minBound=newMinBound; - maxBound=newMaxBound; - size_t itStop[3]; - itStop[0]=std::min(newX,binCount[0]); - itStop[1]=std::min(newY,binCount[1]); - itStop[2]=std::min(newZ,binCount[2]); - - size_t itMax[3]; - itMax[0]=std::max(newX,binCount[0]); - itMax[1]=std::max(newY,binCount[1]); - itMax[2]=std::max(newZ,binCount[2]); - - if(doFill) - { - //Duplicate into new value, if currently inside bounding box - //This logic will be a bit slow, owing to repeated "if"ing, but - //it is easy to understand. Other logics would have many more - //corner cases - bool spin=false; -#pragma omp parallel for - for(size_t ui=0;ui -Point3D Voxels::getMinBounds() const -{ - ASSERT(voxels.size()); - return minBound; -} - -template -Point3D Voxels::getMaxBounds() const -{ - ASSERT(voxels.size()); - return maxBound; -} - -template -void Voxels::setBounds(const Point3D &pMin, const Point3D &pMax) -{ - ASSERT(voxels.size()); - minBound=pMin; - maxBound=pMax; -} - -template -size_t Voxels::init(size_t nX, size_t nY, - size_t nZ, const BoundCube &bound) -{ - binCount[0]=nX; - binCount[1]=nY; - binCount[2]=nZ; - - typedef size_t ull; - ull binCountMax; - - ASSERT(bound.isValid()) - bound.getBounds(minBound, maxBound); - binCountMax= (ull)binCount[0]*(ull)binCount[1]*(ull)binCount[2]; - - voxels.resize(binCountMax); - -#pragma omp parallel for - for(size_t ui=0; ui -size_t Voxels::init(size_t nX, size_t nY, size_t nZ) - -{ - Point3D pMin(0,0,0), pMax(nX,nY,nZ); - - return init(nX,nY,nZ,pMin,pMax); -} - -template -size_t Voxels::loadFile(const char *cpFilename, size_t nX, size_t nY, size_t nZ , bool silent) -{ - std::ifstream CFile(cpFilename,std::ios::binary); - - if(!CFile) - return VOXELS_BAD_FILE_OPEN; - - CFile.seekg(0,std::ios::end); - - - size_t fileSize = CFile.tellg(); - if(fileSize !=nX*nY*nZ*sizeof(T)) - return VOXELS_BAD_FILE_SIZE; - - resize(nX,nY,nZ,Point3D(nX,nY,nZ)); - - CFile.seekg(0,std::ios::beg); - - unsigned int curBufferSize=ITEM_BUFFER_SIZE*sizeof(T); - unsigned char *buffer = new unsigned char[curBufferSize]; - - //Shrink the buffer size by factors of 2 - //in the case of small datasets - while(fileSize < curBufferSize) - curBufferSize = curBufferSize >> 1; - - - //Draw a progress bar - if(!silent) - { - cerr << std::endl << "|"; - for(unsigned int ui=0; ui<100; ui++) - cerr << "."; - cerr << "| 100%" << std::endl << "|"; - } - - unsigned int lastFrac=0; - unsigned int ui=0; - unsigned int pts=0; - do - { - - //Still have data? Keep going - while((size_t)CFile.tellg() <= fileSize-curBufferSize) - { - //Update progress bar - if(!silent && ((unsigned int)(((float)CFile.tellg()*100.0f)/(float)fileSize) > lastFrac)) - { - cerr << "."; - pts++; - lastFrac=(unsigned int)(((float)CFile.tellg()*100.0f)/(float)fileSize) ; - } - - //Read a chunk from the file - CFile.read((char *)buffer,curBufferSize); - - if(!CFile.good()) - return VOXELS_BAD_FILE_READ; - - //Place the chunk contents into ram - for(size_t position=0; position> 1 ; - - }while(curBufferSize> sizeof(T)); //This does a few extra loops. Not many - - delete[] buffer; - - //Fill out the progress bar - if(!silent) - { - while(pts++ <100) - cerr << "."; - - cerr << "| done" << std::endl; - } - - return 0; -} - -template -size_t Voxels::writeFile(const char *filename) const -{ - - ASSERT(voxels.size()) - - std::ofstream file(filename, std::ios::binary); - - if(!file) - return 1; - - - for(size_t ui=0; ui -T Voxels::getSum(const T &initialValue) const -{ - ASSERT(voxels.size()); - T returnVal=initialValue; - T val; -#pragma omp parallel for private(val) reduction(+:returnVal) - for(MP_INT_TYPE ui=0; ui -size_t Voxels::count(const T &minIntensity) const -{ - size_t bins; - bins=binCount[0]*binCount[1]*binCount[2]; - - size_t sum=0; -#pragma omp parallel for reduction(+:sum) - for(size_t ui=0;ui=minIntensity) - sum++; - } - - return sum; -} - -template -void Voxels::swap(Voxels &kernel) -{ - std::swap(binCount[0],kernel.binCount[0]); - std::swap(binCount[1],kernel.binCount[1]); - std::swap(binCount[2],kernel.binCount[2]); - - std::swap(voxels,kernel.voxels); - - std::swap(maxBound,kernel.maxBound); - std::swap(minBound,kernel.minBound); -} - -template -size_t Voxels::convolve(const Voxels &kernel, Voxels &result, size_t boundMode) const -{ - ASSERT(voxels.size()); - - //Check the kernel can fit within this datasest - size_t x,y,z; - kernel.getSize(x,y,z); - if(binCount[0] -size_t Voxels::separableConvolve(const Voxels &kernel, Voxels &result, size_t boundMode) -{ - ASSERT(voxels.size()); - - //Loop through all of the voxel elements, setting the - //result voxels to the convolution of the template - //with the data - - - Point3D resultMinBound, resultMaxBound; - size_t x,y,z; - unsigned long long half; - kernel.getSize(x,y,z); - half=x/2; - //Kernel needs to be cubic - ASSERT(x==y && y == z && (z%2)); - - if(boundMode!=BOUND_CLIP) - { - - resultMinBound=minBound; - resultMaxBound=maxBound; - - ASSERT(result.binCount[0] == binCount[0] && - result.binCount[1] == binCount[1] && - result.binCount[2] == binCount[2]); - - T tally; - - //Separable kernels can be repeatably convolved - //ie, f*g can be expressed as (f*g(x) + - // - - - if(x < binCount[0]/2) - { - //Convolve in X direction only - for(size_t uj=0;uj -T Voxels::getData(size_t x, size_t y, size_t z) const -{ - typedef size_t ull; - ASSERT(x < binCount[0] && y < binCount[1] && z < binCount[2]); - ull off; //byte offset - - //Typecast everything to at least 64 bit uints. - off=(ull)z*(ull)binCount[1]*(ull)binCount[0]; - off+=(ull)y*(ull)binCount[0] + (ull)x; - - ASSERT(off < voxels.size()); - return voxels[off]; -} - -template -T Voxels::getPaddedData(long long x, long long y, long long z, unsigned int padMode) const -{ - if(x >=0 && x<(long long)binCount[0] && y>=0 && y<(long long)binCount[1] && z>=0 && z <(long long)binCount[2]) - { - return getData(x,y,z); - } - - //OK, so we are not inside the dataset -- we have to guess - - switch(padMode) - { - case BOUND_ZERO: - return T(0); - case BOUND_MIRROR: - { - - if(x<0) - x=-x; - - if(y<0) - y=-y; - - if(z<0) - z=-z; - - if(x >=binCount[0]) - x=binCount[0]-(x-binCount[0]+1); - if(y >=binCount[1]) - y=binCount[1]-(y-binCount[1]+1); - if(z >=binCount[2]) - z=binCount[2]-(z-binCount[2]+1); - - - return getData(x,y,z); - } - default: - //Should only get here if we have not implemented the bound mode - ASSERT(false); - } - - ASSERT(false); -} - -template -void Voxels::setGaussianKernelCube(float stdDev, float bound, size_t sideLen) -{ - T obj; - - //Equivariance gaussian. - float product = 1.0/(stdDev*stdDev*stdDev*sqrtf(powf(2.0*M_PI,3))); - - float scale; - const size_t halfLen = sideLen/2; - - resize(sideLen,sideLen,sideLen,Point3D(bound,bound,bound)); - - const float twoVariance=2.0*stdDev*stdDev; - - scale=bound/sideLen; - scale*=scale; - //Loop through the data - //This could be sped up using decrementing whiles, - //at the cost of losing the openMP bit -#pragma omp parallel for shared(product) - for(MP_INT_TYPE ui=0;ui -void Voxels::secondDifference(Voxels &result, size_t boundMode) const -{ - //Only clipping mode is supported at this time - ASSERT(boundMode=BOUND_CLIP); - //Note: Central difference loses two values from each edge - ASSERT(binCount[0] > 2 && binCount[1] > 2 && binCount[2] > 2); - float xSqr,ySqr,zSqr; - - xSqr = (maxBound[0]-minBound[0])/binCount[0]; - - ySqr = (maxBound[1]-minBound[1])/binCount[1]; - - zSqr = (maxBound[2]-minBound[2])/binCount[2]; - - - - //Allocate the second difference result, with a bin wdith - //Note: We are bastardising the definition of xSqr for convenience here - //xSqr at this time is simply the grid pitch (same for ySqr,zSqr) - - result.resize(binCount[0]-2,binCount[1]-2,binCount[2]-2, - Point3D((binCount[0]-2)*xSqr, - (binCount[1]-2)*ySqr, - (binCount[2]-2)*zSqr)); - - - xSqr*=xSqr; - ySqr*=ySqr; - zSqr*=zSqr; - - - //Calculate del^2 - T d; -#pragma omp parallel for private(d) - for(MP_INT_TYPE ui=1; ui -void Voxels::thresholdForPosition(std::vector &p, const T &thresh, bool lowerEq) const -{ - p.clear(); - - if(lowerEq) - { -#pragma omp parallel for - for(MP_INT_TYPE ui=0;ui thresh) - { -#pragma omp critical - p.push_back(getPoint(ui,uj,uk)); - } - - } - } - } - } -} - -template -void Voxels::binarise(Voxels &result, const T &thresh, - const T &onThresh, const T &offThresh) const -{ - - result.resize(binCount[0],binCount[1], - binCount[2],minBound,maxBound); -#pragma omp parallel for - for(MP_INT_TYPE ui=0;ui<(MP_INT_TYPE)binCount[0]; ui++) - { - for(size_t uj=0;uj -void Voxels::rebin(Voxels &result, size_t rate, size_t clipDir) const -{ - //Check that the binsize can be reduced by this factor - //or clipping allowed - ASSERT(clipDir || ( !(binCount[0] % rate) && !(binCount[1] % rate) - && !(binCount[2] % rate))); - - //Datasets must be bigger than their clipping direction - ASSERT(binCount[0] > rate && binCount[1] && rate && binCount[2] > rate); - - - size_t newBin[3]; - newBin[0]=binCount[0]/rate; - newBin[1]=binCount[1]/rate; - newBin[2]=binCount[2]/rate; - - - //Clipping not implmented! - ASSERT(clipDir == CLIP_NONE); - - result.resize(newBin[0],newBin[1],newBin[2],getMinBounds(), getMaxBounds()); - //Draw a progress bar - cerr << std::endl << "|"; - for(unsigned int ui=0; ui<100; ui++) - cerr << "."; - cerr << "| 100%" << std::endl << "|"; - - size_t its=0; - unsigned int progress =0; - float itsToDo = binCount[0]/rate; -#pragma omp parallel for shared(progress,its) - for(MP_INT_TYPE ui=0; ui -void Voxels::makeSphericalKernel(size_t sideLen, float bound, const T &val, unsigned int antialiasLevel) -{ - - const size_t halfLen = sideLen/2; - float sqrSideLen=(float)halfLen*(float)halfLen; - resize(sideLen,sideLen,sideLen,Point3D(bound,bound,bound)); - - if(!antialiasLevel) - { - //Loop through the data - //This could be sped up using decrementing whiles, - //at the cost of losing the openMP bit -#pragma omp parallel for shared(sqrSideLen) - for(MP_INT_TYPE ui=0;ui (float)sqrSideLen && insideSphere)) - { - //We have to do a full volume fraction - //calculation to compute the value of this voxel - fullCalc=true; - break; - } - } - - - if(fullCalc) - { - //Compute volume fraction - - //The method we use is a recursive divide & measure approach - //We chop the voxel into eight half size voxels, then check - //to see which lie in the sphere, and which dont. - std::stack > positionStack; - Point3D thisCentre; - unsigned int thisLevel; - float thisLen,value,x,y,z; - value=0; - //Push this voxel's 8 sub-voxel's centres onto the stack - //to kick things off - for(int off=0;off<8; off++) //CRITICAL that off is an int for bitmask - { - //the right hand part of the addition should - //flip between -0.5 and +0.5 alternately - x= ui + 0.5*(2*(off &1)-1); - y= uj + 0.5*((off &2)-1); - z= uk + 0.5*(0.5*(off &4)-1); - - positionStack.push(std::make_pair(Point3D(x,y,z),0)); - } - - //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)) - while(!positionStack.empty()) - { - thisCentre = positionStack.top().first; - thisLevel = positionStack.top().second; - positionStack.pop(); - - - //Side length for this voxel - thisLen = pow(2.0,-((int)thisLevel+1))*halfLen; - //Calculate r^2 from sphere centre for each corner - for(int off=0;off<8; off++) //critical that off is int for bitmasking - { - x= thisCentre[0] + (2*(off &1)-1)*thisLen; - y= thisCentre[1] + ((off &2)-1)*thisLen; - z= thisCentre[2] + (0.5*(off &4)-1)*thisLen; - - offset[off] = (x - halfLen)*(x-halfLen) + (y-halfLen)*(y-halfLen) - + (z-halfLen)*(z-halfLen); - } - - insideSphere= offset[0] < (float)sqrSideLen; - fullCalc=false; - - //Spin through each to check if this is a border-straddling voxel - for(int off=1;off<8; off++) - { - if( (offset[off] < (float)sqrSideLen && !insideSphere) || - (offset[off] > (float)sqrSideLen && insideSphere)) - { - //We have to do a full volume fraction - //calculation to compute the value of this voxel - fullCalc=true; - break; - } - } - - //OK, the action to take now depends on whether we need to subdivide or not - if(thisLevel < antialiasLevel && fullCalc) - { - for(int off=0;off<8; off++) //Critical that off is signed for bitmask - { - x= thisCentre[0] + (2*(off &1)-1)*thisLen; - y= thisCentre[1] + ((off &2)-1)*thisLen; - z= thisCentre[2] + (0.5*(off &4)-1)*thisLen; - - positionStack.push(std::make_pair(Point3D(x,y,z),thisLevel+1)); - } - } - else - { - if(fullCalc) - { - //Lets just call it a half shall we - value+=pow(2.0,-(((int)thisLevel+1)*3+1)); - - } - else - { - //Voxel is either wholly within, or without - //If inside sphere, add to internal volume - //otherwise we "add zero" - ie do nothing - if(insideSphere) - value+=pow(2.0,-((int)thisLevel+1)*3); - } - } - - } - - - setData(ui,uj,uk,value*val); - } - else - setData(ui,uj,uk,((int)insideSphere)*val); - } - } - } - } - -} - -template -T Voxels::min() const -{ - ASSERT(voxels.size()); - size_t numPts = binCount[0]*binCount[1]*binCount[2]; - T minVal; - minVal = voxels[0]; -#ifdef _OPENMP - //Unfortunately openMP doesn't lend itself well here - //But we can code around it. - size_t maxThr = omp_get_max_threads(); - T minArr[maxThr]; - //Init all mins - for(size_t ui=0; ui -T Voxels::max() const -{ - ASSERT(voxels.size()); - size_t numPts = binCount[0]*binCount[1]*binCount[2]; - T maxVal; - maxVal = voxels[0]; -#ifdef _OPENMP - //Unfortunately openMP doesn't lend itself well here - //But we can code around it. - size_t maxThr = omp_get_max_threads(); - T maxArr[maxThr]; - //Init all maxs - for(size_t ui=0; ui -void Voxels::minMax(T &minVal,T &maxVal) const -{ - ASSERT(voxels.size()); - size_t numPts = binCount[0]*binCount[1]*binCount[2]; - maxVal=voxels[0]; - minVal=voxels[0]; -#ifdef _OPENMP - //Unfortunately openMP doesn't lend itself well here - //But we can code around it. - size_t maxThr = omp_get_max_threads(); - T minArr[maxThr],maxArr[maxThr]; - //Init all maxs - for(size_t ui=0; ui -void Voxels::fillSpheresByPosition( const std::vector &spherePos, float rad, const T &value, bool doErase) -{ - - //I haven't though this through for non cubic datasets - ASSERT((maxBound[0]-minBound[0]) == (maxBound[1]-minBound[1])); - ASSERT((maxBound[1]-minBound[1]) == (maxBound[2]-minBound[2])); - ASSERT(binCount[0] == binCount[1]); - ASSERT(binCount[1] == binCount[2]); - - //Size of rectangular box that contains the sphere - size_t numBlocks[3]; - numBlocks[0] = (size_t)(2.0*rad*binCount[0]/(maxBound[0]-minBound[0])); - numBlocks[1] = (size_t)(2.0*rad*binCount[1]/(maxBound[1]-minBound[1])); - numBlocks[2] = (size_t)(2.0*rad*binCount[2]/(maxBound[2]-minBound[2])); - - //Construct the sphere kernel - std::vector vX,vY,vZ; - float sqrRad=(float)numBlocks[0]*(float)numBlocks[0]/4.0f; -#pragma omp parallel for - for(MP_INT_TYPE ui=0;ui 0 && - p[1] < binCount[1] && p[1] > 0 && - p[2] < binCount[2] && p[2] > 0) - { -#pragma omp critical - setData(p[0],p[1],p[2],value); - } - - } - - } -} - - -template -int Voxels::countPoints( const std::vector &points, bool noWrap, bool doErase) -{ - if(doErase) - { - fill(0); - } - - size_t x,y,z; - - unsigned int downSample=MAX_CALLBACK; - for(size_t ui=0; ui getData(x,y,z)) - setData(x,y,z,value); - } else { - setData(x,y,z,value); - } - } - } - } - - return 0; -} - -template -void Voxels::calculateDensity() -{ - Point3D size = maxBound - minBound; - // calculate the volume of a voxel - double volume = 1.0; - for (int i = 0; i < 3; i++) - volume *= size[i] / binCount[i]; - - // normalise the voxel value based on volume -#pragma omp parallel for - for(size_t ui=0; ui -float Voxels::getBinVolume() const -{ - Point3D size = maxBound - minBound; - double volume = 1.0; - for (int i = 0; i < 3; i++) - volume *= size[i] / binCount[i]; - - return volume; -} - -template -void Voxels::getIndex(size_t &x, size_t &y, - size_t &z, const Point3D &p) const -{ - - ASSERT(p[0] >=minBound[0] && p[1] >=minBound[1] && p[2] >=minBound[2] && - p[0] <=maxBound[0] && p[1] <=maxBound[1] && p[2] <=maxBound[2]); - x=(size_t)((p[0]-minBound[0])/(maxBound[0]-minBound[0])*(float)binCount[0]); - y=(size_t)((p[1]-minBound[1])/(maxBound[1]-minBound[1])*(float)binCount[1]); - z=(size_t)((p[2]-minBound[2])/(maxBound[2]-minBound[2])*(float)binCount[2]); -} - -template -void Voxels::getIndexWithUpper(size_t &x, size_t &y, - size_t &z, const Point3D &p) const -{ - //Get the data index as per normal - getIndex(x,y,z,p); - - //but, as a special case, if the index is the same as our bincount, check - //to see if it is positioned on an edge - if(x==binCount[0] && - fabs(p[0] -maxBound[0]) < sqrt(std::numeric_limits::epsilon())) - x--; - if(y==binCount[1] && - fabs(p[1] -maxBound[1]) < sqrt(std::numeric_limits::epsilon())) - y--; - if(z==binCount[2] && - fabs(p[2] -maxBound[2]) < sqrt(std::numeric_limits::epsilon())) - z--; - -} - -template -void Voxels::fill(const T &v) -{ - size_t nBins = binCount[0]*binCount[1]*binCount[2]; - -#pragma omp parallel for - for(MP_INT_TYPE ui=0;ui<(MP_INT_TYPE)nBins; ui++) - voxels[ui]=v; -} - - -template -int Voxels::histogram(std::vector &v, size_t histBinCount) const -{ - - T maxVal=max(); - T minVal=min(); - -#ifdef _OPENMP - //We need an array for each thread to store results - size_t *vals; - - vals = new size_t[omp_get_max_threads()*histBinCount]; - - //Zero out the array - for(size_t ui=0;ui -void Voxels::findSorted(std::vector &x, std::vector &y, - std::vector &z, size_t n, bool largest) const -{ - //Could be better if we didn't use indexed data aquisition (record opsition) - std::deque bSx,bSy,bSz; - - if(voxels.empty()) - return; - - T curBest; - curBest=getData(0); - - //It is theoretically possible to rewrite this without locking (critical sections). - if(largest) - { - - for(size_t ui=0;ui curBest) - { -#pragma omp critical - { - bSx.push_front(ui); - bSy.push_front(uj); - bSz.push_front(uk); - curBest=getData(ui,uj,uk); - } - } - - } - } - } - - } - else - { - for(size_t ui=0;ui -void Voxels::operator/=(const Voxels &v) -{ - ASSERT(v.voxels.size() == voxels.size()); -#pragma omp parallel for - for (size_t i = 0; i < voxels.size(); i++) - { - if(v.voxels[i]) - voxels[i]/=(v.voxels[i]); - else - voxels[i] =0; - } -} - - -template -void Voxels::operator/=(const T &v) -{ - ASSERT(v); -#pragma omp parallel for - for (size_t i = 0; i < voxels.size(); i++) - voxels[i]/=v; -} -//=== - - - -#endif diff -Nru 3depict-0.0.12/src/wxcommon.cpp 3depict-0.0.13/src/wxcommon.cpp --- 3depict-0.0.12/src/wxcommon.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/wxcommon.cpp 2013-03-22 18:31:39.000000000 +0000 @@ -1,6 +1,6 @@ /* * wxcommon.cpp - Comon wxwidgets functionality - * 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 @@ -17,16 +17,14 @@ */ #include "wxcommon.h" -#include "basics.h" +#include "common/stringFuncs.h" +#include #include -#include #include -#include -#include #if defined(WIN32) || defined(WIN64) -#include + #include #endif //Auto update checking RSS URL @@ -43,17 +41,14 @@ std::string locateDataFile(const char *name) { - //Possible strategies: + //Current strategies: //Linux: - //TODO: Implement me. Currently we just return the name - //which is equivalent to using current working dir (cwd). - // - Look in cwd. - // - Look in $PREFIX from config.h - // - Look in .config + // - Look in cwd & some common hard-coded install locations. + //Mac: + // - look in cwd //Windows // - Locate a registry key that has the install path, which is preset by // application installer - // - Look in cwd #if defined(WIN32) || defined(WIN64) @@ -82,13 +77,14 @@ #ifdef __linux__ - //POssible search paths. Must have trailing slash. will + //Possible search paths. Must have trailing slash. will //be searched in sequence. - const unsigned int NUM_SEARCH_DIRS=4; + const unsigned int NUM_SEARCH_DIRS=5; const char *possibleDirs[] = { "./", "/usr/local/share/3Depict/", "/usr/share/3Depict/", "/usr/share/3depict/", //Under debian, we have to use lowercase according to the debian guidelines, so handle this case. + "../data/", "", }; @@ -132,7 +128,6 @@ std::string strUrl; wxString rssUrl; - std::cerr << "Running version check" << std::endl; //Build the rss query string, encoding 3depict version and OS description strUrl = std::string(RSS_FEED_LOCATION) + std::string("?progver=") + std::string(PROGRAM_VERSION) + std::string("&os=") + stlStr(::wxGetOsDescription()); @@ -153,6 +148,14 @@ inputStream = url.GetInputStream(); + if(!inputStream || !inputStream->CanRead()) + { + retrieveOK=false; + complete=true; + wxPostEvent(targetWindow,event); + return 0; + } + wxXmlDocument *doc= new wxXmlDocument; if(!doc->Load(*inputStream)) { @@ -162,7 +165,8 @@ wxPostEvent(targetWindow,event); return 0; } - + + //FIXME : leaking inptustream? //Check we grabbed an RSS feed if(doc->GetRoot()->GetName() != wxT("rss")) @@ -395,7 +399,7 @@ //FIXME: Hack. Program name under windows is PROGRAM_NAME + ".exe" const char *EXENAME="3Depict.exe"; - //Loop through the linked list of process data strcutures + //Loop through the linked list of process data structures while( (pspid=(PSYSTEM_PROCESS_INFORMATION_DETAILD)(pspid->NextEntryOffset + (PBYTE)pspid)) && pspid->NextEntryOffset) { diff -Nru 3depict-0.0.12/src/wxcommon.h 3depict-0.0.13/src/wxcommon.h --- 3depict-0.0.12/src/wxcommon.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/wxcommon.h 2013-03-22 18:31:39.000000000 +0000 @@ -1,6 +1,6 @@ /* * wxcommon.h - Common wxwidgets header stuff - * Copyright (C) 2011 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 @@ -18,10 +18,9 @@ #ifndef WXCOMMON_H #define WXCOMMON_H #include -#include -#include #include -#include + +#include "common/basics.h" #define wxCStr(a) wxString(a,*wxConvCurrent) #define wxStr(a) wxString(a.c_str(),*wxConvCurrent) diff -Nru 3depict-0.0.12/src/wxcomponents.cpp 3depict-0.0.13/src/wxcomponents.cpp --- 3depict-0.0.12/src/wxcomponents.cpp 2012-11-18 18:30:42.000000000 +0000 +++ 3depict-0.0.13/src/wxcomponents.cpp 2013-04-10 20:30:17.000000000 +0000 @@ -1,6 +1,6 @@ /* * wxcomponents.h - Custom wxWidgets components header - * 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 @@ -18,15 +18,14 @@ #include "wxcomponents.h" #include "wxcommon.h" -#include "basics.h" +#include "common/stringFuncs.h" + +#include "common/constants.h" +#include "common/translation.h" -#include "translation.h" #include -#include -#include -#include using std::ofstream; using std::vector; @@ -37,7 +36,98 @@ const float FONT_HEADING_SCALEFACTOR=0.75f; #endif +void upWxTreeCtrl(const FilterTree &filterTree, wxTreeCtrl *t, + std::map &filterMap,vector &persistentFilters, + const Filter *visibleFilt) +{ + //Remove any filters that don't exist any more + for(unsigned int ui=persistentFilters.size();ui--;) + { + if(!filterTree.contains(persistentFilters[ui])) + { + std::swap(persistentFilters[ui],persistentFilters.back()); + persistentFilters.pop_back(); + } + } + + stack treeIDs; + //Warning: this generates an event, + //most of the time (some windows versions do not according to documentation) + t->DeleteAllItems(); + + //Clear the mapping + filterMap.clear(); + size_t nextID=0; + + size_t lastDepth=0; + //Add dummy root node. This will be invisible to wxTR_HIDE_ROOT controls + wxTreeItemId tid; + tid=t->AddRoot(wxT("TreeBase")); + t->SetItemData(tid,new wxTreeUint(nextID)); + + // Push on stack to prevent underflow, but don't keep a copy, + // as we will never insert or delete this from the UI + treeIDs.push(tid); + + nextID++; + std::map reverseFilterMap; + //Depth first add + for(tree::pre_order_iterator filtIt=filterTree.depthBegin(); + filtIt!=filterTree.depthEnd(); ++filtIt) + { + //Push or pop the stack to make it match the iterator position + if( lastDepth > filterTree.depth(filtIt)) + { + while(filterTree.depth(filtIt) +1 < treeIDs.size()) + treeIDs.pop(); + } + else if( lastDepth < filterTree.depth(filtIt)) + { + treeIDs.push(tid); + } + + + lastDepth=filterTree.depth(filtIt); + + //This will use the user label or the type string. + tid=t->AppendItem(treeIDs.top(), + wxStr((*filtIt)->getUserString())); + t->SetItemData(tid,new wxTreeUint(nextID)); + + //Record mapping to filter for later reference + filterMap[nextID]=*filtIt; + //Remember the reverse mapping for later in + // this function when we reset visibility + reverseFilterMap[*filtIt] = tid; + + nextID++; + } + + //Try to restore the selection in a user friendly manner + // - Try restoring all requested filter's visibility + // - then restore either the first requested filter as the selection + // or the specified parameter filter as the selection. + if(persistentFilters.size()) + { + for(unsigned int ui=0;uiEnsureVisible(reverseFilterMap[persistentFilters[ui]]); + + if(!visibleFilt) + t->SelectItem(reverseFilterMap[persistentFilters[0]]); + else + t->SelectItem(reverseFilterMap[visibleFilt]); + + persistentFilters.clear(); + } + else if(visibleFilt) + { + ASSERT(reverseFilterMap.find(visibleFilt)!=reverseFilterMap.end()) + t->SelectItem(reverseFilterMap[visibleFilt]); + } + t->GetParent()->Layout(); + +} //Convert my internal choice string format to wx's std::string wxChoiceParamString(std::string choiceString) @@ -93,6 +183,13 @@ #endif } + +void wxPropertyGrid::setGroupName(unsigned int set, const std::string &name) +{ + ASSERT(set < sectionNames.size()); + sectionNames[set]=name; +} + void wxPropertyGrid::OnSize(wxSizeEvent &event) { @@ -392,7 +489,7 @@ case PROPERTY_TYPE_COLOUR: //OK, this is totally inefficient, and hacky. but set the colour //based upon the colour string. Then when user edits, use a colour - //dialog (handled elswehere) + //dialog (handled elsewhere) unsigned char r,g,b,a; parseColString(propertyKeys[ui][uj].data,r,g,b,a); attr->SetBackgroundColour(wxColour(r,g,b,a)); @@ -418,6 +515,12 @@ wxGridCellChoiceEditor *choiceEd=new wxFastComboEditor(a,false); this->SetCellEditor(propertyKeys[ui][uj].renderPosition, 1,choiceEd); + + //Required to prevent wx from asserting, + // "GetEventHandler == this" failed in ~wxWindowBase(), any pushed event handlers must be removed". + // I posted on the wxwidgets forum and got the reply that I should try this, but they were not sure. + // seems to work + attr->DecRef(); break; } case PROPERTY_TYPE_STRING: @@ -517,6 +620,9 @@ #endif } +BEGIN_EVENT_TABLE(CopyGrid, wxGrid) + EVT_KEY_DOWN(CopyGrid::OnKey) +END_EVENT_TABLE() CopyGrid::CopyGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos , const wxSize& size , @@ -613,53 +719,151 @@ wxGridCellCoordsArray arrayBR(GetSelectionBlockBottomRight()); - if(!arrayTL.Count() || !arrayBR.Count()) - return; + // data variable contain text that must be set in the clipboard + std::string data; + std::string endline; +#ifdef __WXMSW__ + endline="\r\n"; +#else + endline="\n"; +#endif + + if(arrayTL.Count() && arrayBR.Count()) + { - wxGridCellCoords coordTL = arrayTL.Item(0); - wxGridCellCoords coordBR = arrayBR.Item(0); + wxGridCellCoords coordTL = arrayTL.Item(0); + wxGridCellCoords coordBR = arrayBR.Item(0); - rows = coordBR.GetRow() - coordTL.GetRow() +1; - cols = coordBR.GetCol() - coordTL.GetCol() +1; + rows = coordBR.GetRow() - coordTL.GetRow() +1; + cols = coordBR.GetCol() - coordTL.GetCol() +1; - // data variable contain text that must be set in the clipboard - std::string data; - // For each cell in selected range append the cell value in the data - //variable - // Tabs '\\t' for cols and '\\n' for rows - for(int r=0; rbr, + // so you have to do this first + int lastRow=cells[0].GetRow(); + int lastCol=cells[0].GetCol(); + for(int cell=0; cell lastRow) + { + lastRow=cells[cell].GetRow(); + data+=endline; + } + data+=stlStr(GetCellValue(cells[cell].GetRow(), + cells[cell].GetCol())); + + if(lastCol < cells[cell].GetCol()) + { + lastCol=cells[cell].GetCol(); + data+="\t"; + } + } + } */ + else + return; + - } - #ifdef __WXMSW__ - data+="\r\n"; - #else - data+="\n"; - #endif } - // Create text data object - wxClipboard *clipboard = new wxClipboard(); + // Put the data in the clipboard - if (clipboard->Open()) + if (wxTheClipboard->Open()) { wxTextDataObject* clipData= new wxTextDataObject; // Set data object value clipData->SetText(wxStr(data)); - clipboard->UsePrimarySelection(false); - clipboard->SetData(clipData); - clipboard->Flush(); - //This causes double free bug? - clipboard->Close(); + wxTheClipboard->UsePrimarySelection(false); + wxTheClipboard->SetData(clipData); + wxTheClipboard->Close(); } - delete clipboard; } @@ -679,20 +883,14 @@ } -std::string TTFFinder::nxFindFont(const char *fontFile) +#ifdef __APPLE__ +std::string TTFFinder::macFindFont(const char *fontFile) { //This is a list of possible target dirs to search //(Oh look Ma, I'm autoconf!) const char *dirs[] = { ".", - "/usr/share/fonts/truetype", - "/usr/local/share/fonts/truetype", - "/usr/X11R6/lib/X11/fonts/truetype", - "/usr/X11R6/lib64/X11/fonts/truetype", - "/usr/lib/X11/fonts/truetype", - "/usr/lib64/X11/fonts/truetype", - "/usr/local/lib/X11/fonts/truetype", - "/usr/local/lib64/X11/fonts/truetype", - "", + "/Library/Fonts", + "" , }; //MUST end with "". wxPathList *p = new wxPathList; @@ -721,13 +919,23 @@ delete p; return res; } - -std::string TTFFinder::winFindFont(const char *fontFile) +#elif defined __UNIX_LIKE__ || defined __linux__ +std::string TTFFinder::nxFindFont(const char *fontFile) { - //This is a list of possible target dirs to search + //This is a list of possible target dirs to search //(Oh look Ma, I'm autoconf!) + const char *dirs[] = { ".", - "C:\\Windows\\Fonts", + "/usr/share/fonts/truetype", //Old debian + "/usr/share/fonts/truetype/freefont", // New debian + "/usr/share/fonts/truetype/ttf-dejavu", //New debian + "/usr/local/share/fonts/truetype", // User fonts + "/usr/X11R6/lib/X11/fonts/truetype", + "/usr/X11R6/lib64/X11/fonts/truetype", + "/usr/lib/X11/fonts/truetype",// Fedora 32 + "/usr/lib64/X11/fonts/truetype", //Fedora 64 + "/usr/local/lib/X11/fonts/truetype", // Fedora 32 new + "/usr/local/lib64/X11/fonts/truetype",// Fedora 64 new "", }; //MUST end with "". @@ -743,8 +951,6 @@ wxString s; - - //execute the search for the file s= p->FindValidPath(wxCStr(fontFile)); @@ -758,17 +964,15 @@ delete p; return res; - - } - -std::string TTFFinder::macFindFont(const char *fontFile) +#elif defined __WINDOWS__ +std::string TTFFinder::winFindFont(const char *fontFile) { - //This is a list of possible target dirs to search + //This is a list of possible target dirs to search //(Oh look Ma, I'm autoconf!) const char *dirs[] = { ".", - "/Library/Fonts", - "" , + "C:\\Windows\\Fonts", + "", }; //MUST end with "". wxPathList *p = new wxPathList; @@ -783,6 +987,8 @@ wxString s; + + //execute the search for the file s= p->FindValidPath(wxCStr(fontFile)); @@ -796,7 +1002,10 @@ delete p; return res; + + } +#endif std::string TTFFinder::suggestFontName(unsigned int fontType, unsigned int index) { diff -Nru 3depict-0.0.12/src/wxcomponents.h 3depict-0.0.13/src/wxcomponents.h --- 3depict-0.0.12/src/wxcomponents.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/wxcomponents.h 2013-03-22 18:31:39.000000000 +0000 @@ -1,6 +1,6 @@ /* * wxcomponents.h - custom wxwidgets components - * 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 @@ -20,16 +20,16 @@ #ifndef WXCOMPONENTS_H #define WXCOMPONENTS_H -#include -#include #include #include #include -#include #include #include + +#include "backend/filtertree.h" + //Shut wxwidgets assertion errors up by defining a "safe" cb_sort wrapper macro #if defined(__WXMAC__) || defined(__WXGTK20__) @@ -47,8 +47,6 @@ #define SAFE_CB_SORT wxCB_SORT #endif -#include "assertion.h" -#include "commonConstants.h" //!3D combo grid renderer, from //http://nomadsync.cvs.sourceforge.net/nomadsync/nomadsync/src/EzGrid.cpp?view=markup (GPL) @@ -86,6 +84,10 @@ wxPoint m_pointActivate; }; +//!Update a wxTree control to layout according to the specified filter tree +void upWxTreeCtrl(const FilterTree &filterTree, wxTreeCtrl *t, + std::map &filterMap,vector &persistentFilters, + const Filter *visibleFilt); //!Data container for tree object data class wxTreeUint : public wxTreeItemData @@ -154,7 +156,7 @@ void setNumGroups(unsigned int newGroupCount){propertyKeys.resize(newGroupCount); sectionNames.resize(newGroupCount);}; //Set the names for each group. This will appear as a small text in the blank rows - void setGroupName(unsigned int set, const std::string &name) {ASSERT(set < sectionNames.size()); sectionNames[set]=name;}; + void setGroupName(unsigned int set, const std::string &name); //!This adds the item to the property key vector of a specified group //! key must be unique @@ -198,7 +200,7 @@ void currentCell(); void selectData(); - //!Copy data to the clipboard (TODO: not working under GTK???) + //!Copy data to the clipboard void copyData(); //!Prompts user to save data to file, and then saves it. pops up error // dialog box if there is a problem. Data is tab deliminated @@ -207,6 +209,8 @@ virtual void OnKey(wxKeyEvent &evt); virtual ~CopyGrid(){}; + + DECLARE_EVENT_TABLE() }; diff -Nru 3depict-0.0.12/src/xmlHelper.cpp 3depict-0.0.13/src/xmlHelper.cpp --- 3depict-0.0.12/src/xmlHelper.cpp 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/xmlHelper.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/* - * XmlHelper.cpp : libXML2 wrapper code - * 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 - * 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 . - */ -#include "xmlHelper.h" - -#include - -//Convert a normal string sequence into an XML escaped sequence -std::string escapeXML(const std::string &input) -{ - size_t strLen= input.size(); - std::string output; - for (size_t ui = 0; ui < strLen; ui++) - { - char c; - c= input[ui]; - if (c == '&') - output+=("&"); - else if (c == '<') - output+=("<"); - else if (c == '>') - output+=(">"); - else if (c == '"') - output+=("""); - else if (c == '\'') - output+=("'"); - else - output+=c; - } - return output; -} - - -//Convert an xml escaped sequence into a normal string sequence -//Re-used under GPL v3+ From: -//http://svn.lsdcas.engineering.uiowa.edu/repos/lsdcas/trunk/cas2/libcas/xml.cc -//accessed 3 Mar 2012 -std::string unescapeXML(const std::string &input) -{ - const char* chars = "<>'\"&" ; - const char* refs[] = - { - "<", - ">", - "'", - """, - "&", - 0 - } ; - - std::string data=input; - for( size_t i = 0 ; refs[i] != NULL ; i++ ) - { - std::string::size_type pos = data.find( refs[i] ) ; - - while( pos != std::string::npos ) - { - std::stringstream unescaped ; - unescaped << data.substr( 0, pos ) - << chars[i] - << data.substr( pos + strlen( refs[i] ) ) ; - - data = unescaped.str() ; - pos = data.find( refs[i], pos + strlen( refs[i] ) ) ; - } - } - - return data ; -} - - - -unsigned int XMLHelpNextType(xmlNodePtr &node, int nodeType) -{ - do - { - node= node->next; - if(!node) - return 1; - } - while(node->type != nodeType); - return 0; -} - -//returns zero on success, nonzero on fail -unsigned int XMLHelpFwdToElem(xmlNodePtr &node, const char *nodeName) -{ - do - { - node=node->next; - }while(node != NULL && - xmlStrcmp(node->name,(const xmlChar *) nodeName)); - return (!node); -} - - diff -Nru 3depict-0.0.12/src/xmlHelper.h 3depict-0.0.13/src/xmlHelper.h --- 3depict-0.0.12/src/xmlHelper.h 2012-11-11 19:54:07.000000000 +0000 +++ 3depict-0.0.13/src/xmlHelper.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -/* - * XMLHelper.h - libXML2 wrapper functions - * 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 - * 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 . - */ - -#ifndef XMLHELPER_H -#define XMLHELPER_H - -//Undefs are because wxwidgets and libxml both define this -#ifdef ATTRIBUTE_PRINTF - #pragma push_macro("ATTRIBUTE_PRINTF") - #include - #pragma pop_macro(" ATTRIBUTE_PRINTF") -#else - #include - #undef ATTRIBUTE_PRINTF -#endif -#include -using std::string; - -#include "basics.h" - -//These functions return nonzero on failure, -//zero on success -//be warned that the node WILL be modified. - -//Jump to next element that is of a given type (eg text, node, comment etc) -//see EOF for more details. Returns nonzero on error -unsigned int XMLHelpNextType(xmlNodePtr &node,int); -//Scroll forwards until we reach an element of a given node. return nonzero on error -unsigned int XMLHelpFwdToElem(xmlNodePtr &node, const char *nodeName); - -//Convert a normal string sequence into an XML escaped sequence -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 -//returns false on failure -//NOTE: Do not use if your value may validly contain whitespace. stream_cast skips these cases -template -bool XMLGetNextElemAttrib(xmlNodePtr &nodePtr, T &v, const char *nodeName, const char *attrib) -{ - std::string tmpStr; - xmlChar *xmlString; - //==== - if(XMLHelpFwdToElem(nodePtr,nodeName)) - return false; - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)attrib); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(v,tmpStr)) - { - xmlFree(xmlString); - return false; - } - - xmlFree(xmlString); - - return true; -} - - -//Returns false on failure -//Do not use on validly whitespace containing XML -template -bool XMLGetAttrib(xmlNodePtr &nodePtr, T&v, const char *attrib) -{ - std::string tmpStr; - xmlChar *xmlString; - //==== - - xmlString=xmlGetProp(nodePtr,(const xmlChar *)attrib); - if(!xmlString) - return false; - tmpStr=(char *)xmlString; - - if(stream_cast(v,tmpStr)) - { - xmlFree(xmlString); - return false; - } - - xmlFree(xmlString); - - return true; -} - -/* Defined in the bowels of the xmlLib2 library - * Enum xmlElementType { - * XML_ELEMENT_NODE = 1 - * XML_ATTRIBUTE_NODE = 2 - * XML_TEXT_NODE = 3 - * XML_CDATA_SECTION_NODE = 4 - * XML_ENTITY_REF_NODE = 5 - * XML_ENTITY_NODE = 6 - * XML_PI_NODE = 7 - * XML_COMMENT_NODE = 8 - * XML_DOCUMENT_NODE = 9 - * XML_DOCUMENT_TYPE_NODE = 10 - * XML_DOCUMENT_FRAG_NODE = 11 - * XML_NOTATION_NODE = 12 - * XML_HTML_DOCUMENT_NODE = 13 - * XML_DTD_NODE = 14 - * XML_ELEMENT_DECL = 15 - * XML_ATTRIBUTE_DECL = 16 - * XML_ENTITY_DECL = 17 - * XML_NAMESPACE_DECL = 18 - * XML_XINCLUDE_START = 19 - * XML_XINCLUDE_END = 20 - * XML_DOCB_DOCUMENT_NODE = 21 - * } - */ -#endif - diff -Nru 3depict-0.0.12/test/cppcheck.sh 3depict-0.0.13/test/cppcheck.sh --- 3depict-0.0.12/test/cppcheck.sh 2012-09-30 13:56:44.000000000 +0000 +++ 3depict-0.0.13/test/cppcheck.sh 2013-03-22 18:31:39.000000000 +0000 @@ -29,7 +29,7 @@ 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 @@ -37,5 +37,6 @@ 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 -Nru 3depict-0.0.12/test/rangefiles/test7.rng 3depict-0.0.13/test/rangefiles/test7.rng --- 3depict-0.0.12/test/rangefiles/test7.rng 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/test/rangefiles/test7.rng 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,8 @@ +2 2 +M +M 0 0 1 +N +N 1 0 0 +------- +. -0.5 0.5 1 0 +. 1.5 2.4 0 1 diff -Nru 3depict-0.0.12/test/rangefiles/test8.rng 3depict-0.0.13/test/rangefiles/test8.rng --- 3depict-0.0.12/test/rangefiles/test8.rng 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/test/rangefiles/test8.rng 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,8 @@ +2 2 +M +M 0 0 1 +N +N 1 0 0 +------- +3 -0.5 0.5 1 0 +. 1.5 2.4 0 1 diff -Nru 3depict-0.0.12/test/spell-fixes.sh 3depict-0.0.13/test/spell-fixes.sh --- 3depict-0.0.12/test/spell-fixes.sh 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/test/spell-fixes.sh 2013-04-05 21:38:09.000000000 +0000 @@ -0,0 +1,42 @@ +#!/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 -Nru 3depict-0.0.12/translations/3Depict_base.pot 3depict-0.0.13/translations/3Depict_base.pot --- 3depict-0.0.12/translations/3Depict_base.pot 2012-11-12 22:49:03.000000000 +0000 +++ 3depict-0.0.13/translations/3Depict_base.pot 2013-04-05 21:27:32.000000000 +0000 @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-11-12 10:07+0100\n" +"POT-Creation-Date: 2013-04-05 23:27+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,1617 +17,1513 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../src/cameras.cpp:695 ../src/cameras.cpp:697 +#: ../src/gl/cameras.cpp:688 ../src/gl/cameras.cpp:690 msgid "Lock" msgstr "" -#: ../src/cameras.cpp:704 ../src/filters/transform.cpp:1114 -#: ../src/filters/transform.cpp:1140 ../src/filters/ionClip.cpp:696 -#: ../src/filters/ionClip.cpp:718 ../src/filters/ionClip.cpp:740 -#: ../src/filters/ionClip.cpp:780 ../src/filters/compositionProfile.cpp:912 -#: ../src/filters/annotation.cpp:540 +#: ../src/gl/cameras.cpp:697 ../src/backend/filters/ionClip.cpp:523 +#: ../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/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 msgid "Origin" msgstr "" -#: ../src/cameras.cpp:709 ../src/filters/spatialAnalysis.cpp:1473 +#: ../src/gl/cameras.cpp:702 ../src/backend/filters/spatialAnalysis.cpp:511 msgid "Target" msgstr "" -#: ../src/cameras.cpp:714 +#: ../src/gl/cameras.cpp:707 msgid "Up Dir." msgstr "" -#: ../src/cameras.cpp:722 ../src/cameras.cpp:826 +#: ../src/gl/cameras.cpp:715 ../src/gl/cameras.cpp:819 msgid "Perspective" msgstr "" -#: ../src/cameras.cpp:724 ../src/cameras.cpp:828 +#: ../src/gl/cameras.cpp:717 ../src/gl/cameras.cpp:821 msgid "Orthogonal" msgstr "" -#: ../src/cameras.cpp:728 +#: ../src/gl/cameras.cpp:721 msgid "Projection" msgstr "" -#: ../src/cameras.cpp:736 +#: ../src/gl/cameras.cpp:729 msgid "Field of View (deg)" msgstr "" -#: ../src/cameras.cpp:742 +#: ../src/gl/cameras.cpp:735 msgid "View size" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:77 -msgid "Oak-Ridge RNG" +#: ../src/wxcomponents.cpp:428 ../src/gui/dialogs/ExportRngDialog.cpp:88 +#: ../src/gui/dialogs/prefDialog.cpp:108 +msgid "Param" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:78 -msgid "Cameca/Ametek RRNG" +#: ../src/wxcomponents.cpp:429 ../src/gui/dialogs/ExportRngDialog.cpp:89 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:105 +#: ../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 +msgid "Value" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:79 -msgid "Cameca/Ametek ENV" +#: ../src/wxcomponents.cpp:641 +msgid "Save Data..." msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:137 -msgid "Key frames" +#: ../src/wxcomponents.cpp:642 +msgid "Text File (*.txt)|*.txt|All Files (*)|*" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:138 -msgid "Output Data" +#: ../src/wxcomponents.cpp:654 +msgid "Error saving file. Check output dir is writable." msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:139 -msgid "Filters and properties" +#: ../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 +msgid "Save error" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:145 -msgid "Dir : " +#: ../src/common/basics.cpp:52 ../src/backend/APT/APTClasses.cpp:54 +msgid "Error opening file" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:148 -msgid "Output only when refresh required" +#: ../src/common/basics.cpp:53 +msgid "Error whilst reading file contents" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:150 -msgid "Data Types:" +#: ../src/common/basics.cpp:54 ../src/backend/APT/APTClasses.cpp:58 +msgid "Error interpreting field in file" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:151 -msgid "3D Images" +#: ../src/common/basics.cpp:55 +msgid "Inconsistent number of columns found" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:152 -msgid "File Prefix: " +#: ../src/common/basics.cpp:167 +msgid "in the future?" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:154 -msgid "Size : " +#: ../src/common/basics.cpp:218 +msgid "a decade ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:156 -msgid "..." +#: ../src/common/basics.cpp:219 +msgid "a year ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:157 -msgid "Point data" +#: ../src/common/basics.cpp:220 +msgid "a month ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:158 -msgid "Plots" +#: ../src/common/basics.cpp:221 +msgid "a week ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:159 -msgid "Voxel data" +#: ../src/common/basics.cpp:222 +msgid "a day ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:160 -msgid "Range files" +#: ../src/common/basics.cpp:223 +msgid "an hour ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:161 -msgid "Format" +#: ../src/common/basics.cpp:224 +msgid "45 minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:177 -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:81 -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:327 -msgid "Frame" +#: ../src/common/basics.cpp:225 +msgid "30 minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:619 -msgid "transition frame" +#: ../src/common/basics.cpp:226 +msgid "20 minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:619 ../src/3Depict.cpp:1702 -msgid "Frame count" +#: ../src/common/basics.cpp:227 +msgid "15 minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:691 -msgid "Key frame : Colour" +#: ../src/common/basics.cpp:228 +msgid "10 minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:746 -msgid "File existed, but was unable to read or interpret file contents." +#: ../src/common/basics.cpp:229 +msgid "5 minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:747 -msgid "String load failed" +#: ../src/common/basics.cpp:230 +msgid "a minute ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:768 -msgid "Keyframe : decimal" +#: ../src/common/basics.cpp:231 +msgid "30 seconds ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:777 -msgid "Keyframe : integer" +#: ../src/common/basics.cpp:232 +msgid "10 seconds ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:786 -msgid "Keyframe : 3D Point" +#: ../src/common/basics.cpp:233 +msgid "a second ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:897 -msgid "Select or create new folder" +#: ../src/common/basics.cpp:238 +msgid "a few decades ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1072 -msgid "Export Animation" +#: ../src/common/basics.cpp:239 +msgid "a few years ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1073 -msgid "Select filter" +#: ../src/common/basics.cpp:240 +msgid "a few months ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1075 -#: ../src/dialogs/animateFilterDialog.cpp:1080 -#: ../src/dialogs/animateFilterDialog.cpp:1096 ../src/3Depict.cpp:5332 -#: ../src/3Depict.cpp:5337 -msgid "Property" +#: ../src/common/basics.cpp:241 +msgid "a few weeks ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1076 -#: ../src/dialogs/animateFilterDialog.cpp:1097 -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:82 -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:329 -#: ../src/dialogs/ExportRngDialog.cpp:89 ../src/dialogs/prefDialog.cpp:106 -#: ../src/3Depict.cpp:5333 ../src/3Depict.cpp:5338 ../src/wxcomponents.cpp:330 -#: ../src/filters/dataLoad.cpp:471 -msgid "Value" +#: ../src/common/basics.cpp:242 +msgid "a few days ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1077 -msgid "Select property" +#: ../src/common/basics.cpp:243 +msgid "a few hours ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1079 -#: ../src/dialogs/animateFilterDialog.cpp:1095 -msgid "Filter" +#: ../src/common/basics.cpp:250 +msgid "a few minutes ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1081 -#: ../src/filters/transform.cpp:1033 ../src/filters/annotation.cpp:518 -msgid "Mode" +#: ../src/common/basics.cpp:253 +msgid "a few seconds ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1082 -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:48 -msgid "Start Frame" +#: ../src/common/basics.cpp:280 +msgid "moments ago" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1083 -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:50 -msgid "End Frame" +#: ../src/common/colourmap.cpp:234 +msgid "Jet" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1084 -msgid "Keyframe table" +#: ../src/common/colourmap.cpp:235 +msgid "Hot" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1085 -msgid "Remove the selected keyframe from the table" +#: ../src/common/colourmap.cpp:236 +msgid "Cold" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1086 -msgid "Enter where the animation frames will be exported to" +#: ../src/common/colourmap.cpp:237 +msgid "Grey" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1087 -msgid "Browse to directory where the animation frames will be exported to" +#: ../src/common/colourmap.cpp:238 +msgid "Cyclic" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1089 -#: ../src/dialogs/animateFilterDialog.cpp:1090 -msgid "Enter the target resolution (width)" +#: ../src/common/colourmap.cpp:239 +msgid "General" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1092 -msgid "frame" +#: ../src/common/colourmap.cpp:240 +msgid "Blue" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1093 -msgid "Enter frame number" +#: ../src/common/colourmap.cpp:241 +msgid "Pseudo-Random" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1098 -msgid "Animation parameters for current frame" +#: ../src/gui/glPane.cpp:635 +msgid "Use shift/ctrl-space or double tap to alter reset axis" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1099 -msgid "Abort animation" +#: ../src/gui/glPane.cpp:893 +msgid "Image progress" msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1100 -msgid "Run Animation" +#: ../src/gui/glPane.cpp:894 +msgid "Rendering tiles..." msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1171 -msgid "Filter view" +#: ../src/gui/glPane.cpp:910 +msgid "Tile " msgstr "" -#: ../src/dialogs/animateFilterDialog.cpp:1172 -msgid "Frame view" +#: ../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 +msgid " of " +msgstr "" + +#: ../src/gui/glPane.cpp:1043 +msgid "Animation progress" +msgstr "" + +#: ../src/gui/glPane.cpp:1044 +msgid "Rendering sequence..." +msgstr "" + +#: ../src/gui/glPane.cpp:1077 +msgid "Saving Image " +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:40 +msgid "Range Sources" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:42 +msgid "Details" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:53 +msgid "Source Filter" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:54 +msgid "Ions" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:55 +#: ../src/backend/filters/rangeFile.cpp:666 +msgid "Ranges" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:90 +msgid "Value2" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:97 +msgid "Ion Name" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:98 +msgid "Num Ranges" msgstr "" -#: ../src/dialogs/filterErrorDialog.cpp:20 ../src/filter.cpp:555 -#: ../src/filter.cpp:558 +#: ../src/gui/dialogs/ExportRngDialog.cpp:116 ../src/backend/filter.cpp:43 +msgid "Ion" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:117 +msgid "Range Start" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:118 +msgid "Range end" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2090 +msgid "Save pos..." +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:152 +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 +msgid "Unable to save. Check output destination can be written to." +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:236 +msgid "Export Range" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:241 +msgid "List of rangefiles in filter tree" +msgstr "" + +#: ../src/gui/dialogs/ExportRngDialog.cpp:243 +msgid "Detailed view of selected range" +msgstr "" + +#: ../src/gui/dialogs/autosaveDialog.cpp:39 +msgid "Remove &All" +msgstr "" + +#: ../src/gui/dialogs/autosaveDialog.cpp:123 +msgid "Restore state?" +msgstr "" + +#: ../src/gui/dialogs/autosaveDialog.cpp:133 +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 msgid "Error" msgstr "" -#: ../src/dialogs/filterErrorDialog.cpp:22 +#: ../src/gui/dialogs/filterErrorDialog.cpp:39 msgid "Warning" msgstr "" -#: ../src/dialogs/filterErrorDialog.cpp:25 -#: ../src/dialogs/filterErrorDialog.cpp:35 +#: ../src/gui/dialogs/filterErrorDialog.cpp:42 +#: ../src/gui/dialogs/filterErrorDialog.cpp:52 msgid "Filter Errors" msgstr "" -#: ../src/dialogs/StashDialog.cpp:46 +#: ../src/gui/dialogs/StashDialog.cpp:44 msgid "Stashes" msgstr "" -#: ../src/dialogs/StashDialog.cpp:49 +#: ../src/gui/dialogs/StashDialog.cpp:47 msgid "Stashed Tree" msgstr "" -#: ../src/dialogs/StashDialog.cpp:51 +#: ../src/gui/dialogs/StashDialog.cpp:49 msgid "Properties" msgstr "" -#: ../src/dialogs/StashDialog.cpp:87 +#: ../src/gui/dialogs/StashDialog.cpp:85 msgid "Stashed Trees" msgstr "" -#: ../src/dialogs/StashDialog.cpp:90 +#: ../src/gui/dialogs/StashDialog.cpp:88 msgid "Erase stashed item" msgstr "" -#: ../src/dialogs/StashDialog.cpp:91 +#: ../src/gui/dialogs/StashDialog.cpp:89 msgid "Filter view for current stash" msgstr "" -#: ../src/dialogs/StashDialog.cpp:92 +#: ../src/gui/dialogs/StashDialog.cpp:90 msgid "Settings for selected filter in current stash" msgstr "" -#: ../src/dialogs/StashDialog.cpp:93 +#: ../src/gui/dialogs/StashDialog.cpp:91 msgid "Available stashes" msgstr "" -#: ../src/dialogs/StashDialog.cpp:157 +#: ../src/gui/dialogs/StashDialog.cpp:152 msgid "Stash Name" msgstr "" -#: ../src/dialogs/StashDialog.cpp:158 +#: ../src/gui/dialogs/StashDialog.cpp:153 msgid "Filter Count" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:28 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:45 msgid "Start Frame: " msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:30 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:47 msgid "From File" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:33 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:50 msgid "From Table" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:217 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:104 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:350 +#: ../src/gui/dialogs/animateFilterDialog.cpp:191 +msgid "Frame" +msgstr "" + +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:240 msgid "Select text file..." msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:218 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:241 msgid "Text files (*.txt)|*.txt;|All Files (*)|*" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:319 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:342 msgid "String Keyframes" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:321 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:344 msgid "Frame at which to start string sequence" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:322 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:345 msgid "Frame offset for data start" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:323 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:346 msgid "File to use as string data source, one value per row" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:324 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:347 msgid "Select file to use as data source" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:325 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:348 msgid "Use table below for data source" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:331 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:354 msgid "Add new data rows to table, hold shift/cmd to insert multiple rows" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:332 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:355 msgid "Remove selected strings from table" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:333 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:356 msgid "Abort value selection and return to previous window" msgstr "" -#: ../src/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:334 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:357 msgid "Accept data values" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:40 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:56 msgid "Keyframe Data" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:41 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:57 msgid "Transition" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:44 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:60 msgid "Step" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:45 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:61 msgid "Ramp" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:53 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:64 +#: ../src/gui/dialogs/animateFilterDialog.cpp:1115 +msgid "Start Frame" +msgstr "" + +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:66 +#: ../src/gui/dialogs/animateFilterDialog.cpp:1116 +msgid "End Frame" +msgstr "" + +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:69 msgid "Initial Value" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:54 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:70 msgid "startColour" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:55 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:71 msgid "Final Value" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:56 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:72 msgid "endColour" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:203 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:235 msgid "Key Frame : Colour" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:205 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:237 msgid "Colour at the start of the transtition" msgstr "" -#: ../src/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:206 +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:238 msgid "Colour at end of transition" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:30 -msgid "Width :" +#: ../src/gui/dialogs/animateFilterDialog.cpp:91 +msgid "Oak-Ridge RNG" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:32 -msgid "Height :" +#: ../src/gui/dialogs/animateFilterDialog.cpp:92 +msgid "Cameca/Ametek RRNG" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:34 -msgid "Lock Aspect" +#: ../src/gui/dialogs/animateFilterDialog.cpp:93 +msgid "Cameca/Ametek ENV" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:38 ../src/dialogs/prefDialog.cpp:79 -msgid "Reset" +#: ../src/gui/dialogs/animateFilterDialog.cpp:151 +msgid "Key frames" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:444 -msgid "Resolution Selection" +#: ../src/gui/dialogs/animateFilterDialog.cpp:152 +msgid "Output Data" msgstr "" -#: ../src/dialogs/ExportPos.cpp:71 -msgid "Export:" +#: ../src/gui/dialogs/animateFilterDialog.cpp:153 +msgid "Filters and properties" msgstr "" -#: ../src/dialogs/ExportPos.cpp:72 ../src/filters/boundingBox.cpp:508 -msgid "Visible" +#: ../src/gui/dialogs/animateFilterDialog.cpp:159 +msgid "Dir : " msgstr "" -#: ../src/dialogs/ExportPos.cpp:73 -msgid "Selected Data" +#: ../src/gui/dialogs/animateFilterDialog.cpp:162 +msgid "Output only when refresh required" msgstr "" -#: ../src/dialogs/ExportPos.cpp:75 -msgid "Available Data" +#: ../src/gui/dialogs/animateFilterDialog.cpp:164 +msgid "Data Types:" msgstr "" -#: ../src/dialogs/ExportPos.cpp:81 -msgid "Selection" +#: ../src/gui/dialogs/animateFilterDialog.cpp:165 +msgid "3D Images" msgstr "" -#: ../src/dialogs/ExportPos.cpp:106 ../src/dialogs/ExportPos.cpp:109 -msgid "Index" +#: ../src/gui/dialogs/animateFilterDialog.cpp:166 +msgid "File Prefix: " msgstr "" -#: ../src/dialogs/ExportPos.cpp:107 ../src/dialogs/ExportPos.cpp:110 -#: ../src/filters/spectrumPlot.cpp:224 ../src/filters/spatialAnalysis.cpp:852 -#: ../src/filters/spatialAnalysis.cpp:924 -#: ../src/filters/compositionProfile.cpp:505 -msgid "Count" +#: ../src/gui/dialogs/animateFilterDialog.cpp:168 +msgid "Size : " msgstr "" -#: ../src/dialogs/ExportPos.cpp:446 -msgid "Export Pos Data" +#: ../src/gui/dialogs/animateFilterDialog.cpp:170 +msgid "..." msgstr "" -#: ../src/dialogs/ExportPos.cpp:449 -msgid "Tree of filters, select leaves to show ion data." +#: ../src/gui/dialogs/animateFilterDialog.cpp:171 +msgid "Point data" msgstr "" -#: ../src/dialogs/ExportPos.cpp:451 -msgid "Add all data from all filters" +#: ../src/gui/dialogs/animateFilterDialog.cpp:172 +msgid "Plots" msgstr "" -#: ../src/dialogs/ExportPos.cpp:452 -msgid "Add all data from currently selected filter" +#: ../src/gui/dialogs/animateFilterDialog.cpp:173 +msgid "Voxel data" msgstr "" -#: ../src/dialogs/ExportPos.cpp:453 -msgid "Add selected data from currently selected filter" +#: ../src/gui/dialogs/animateFilterDialog.cpp:174 +msgid "Range files" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:40 -msgid "Range Sources" +#: ../src/gui/dialogs/animateFilterDialog.cpp:175 +msgid "Format" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:42 -msgid "Details" +#: ../src/gui/dialogs/animateFilterDialog.cpp:638 +msgid "transition frame" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:53 -msgid "Source Filter" +#: ../src/gui/dialogs/animateFilterDialog.cpp:638 +#: ../src/gui/mainFrame.cpp:1538 +msgid "Frame count" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:54 -msgid "Ions" +#: ../src/gui/dialogs/animateFilterDialog.cpp:710 +msgid "Key frame : Colour" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:55 ../src/filters/rangeFile.cpp:654 -msgid "Ranges" +#: ../src/gui/dialogs/animateFilterDialog.cpp:763 +msgid "File existed, but was unable to read or interpret file contents." msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:88 ../src/dialogs/prefDialog.cpp:105 -#: ../src/wxcomponents.cpp:329 -msgid "Param" +#: ../src/gui/dialogs/animateFilterDialog.cpp:764 +msgid "String load failed" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:90 -msgid "Value2" +#: ../src/gui/dialogs/animateFilterDialog.cpp:785 +msgid "Keyframe : decimal" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:97 -msgid "Ion Name" +#: ../src/gui/dialogs/animateFilterDialog.cpp:794 +msgid "Keyframe : integer" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:98 -msgid "Num Ranges" +#: ../src/gui/dialogs/animateFilterDialog.cpp:803 +msgid "Keyframe : 3D Point" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:116 ../src/filter.cpp:48 -msgid "Ion" +#: ../src/gui/dialogs/animateFilterDialog.cpp:929 +msgid "Select or create new folder" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:117 -msgid "Range Start" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1105 +msgid "Export Animation" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:118 -msgid "Range end" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1106 +msgid "Select filter" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:151 ../src/3Depict.cpp:2187 -msgid "Save pos..." +#: ../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 +msgid "Property" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:152 -msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1110 +msgid "Select property" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:167 ../src/3Depict.cpp:1484 -#: ../src/3Depict.cpp:1635 ../src/3Depict.cpp:1730 ../src/3Depict.cpp:2128 -#: ../src/3Depict.cpp:2245 ../src/3Depict.cpp:2367 -msgid "Unable to save. Check output destination can be written to." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1112 +#: ../src/gui/dialogs/animateFilterDialog.cpp:1132 +msgid "Filter" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:170 ../src/3Depict.cpp:1487 -#: ../src/3Depict.cpp:1582 ../src/3Depict.cpp:1638 ../src/3Depict.cpp:1733 -#: ../src/3Depict.cpp:2131 ../src/3Depict.cpp:2148 ../src/3Depict.cpp:2248 -#: ../src/3Depict.cpp:2370 ../src/wxcomponents.cpp:546 -msgid "Save error" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1114 +#: ../src/backend/filters/transform.cpp:1180 +#: ../src/backend/filters/annotation.cpp:535 +msgid "Mode" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:236 -msgid "Export Range" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1117 +msgid "Keyframe table" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:241 -msgid "List of rangefiles in filter tree" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1118 +msgid "Remove the selected keyframe from the table" msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:243 -msgid "Detailed view of selected range" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1119 +msgid "Enter where the animation frames will be exported to" msgstr "" -#: ../src/dialogs/prefDialog.cpp:63 ../src/dialogs/prefDialog.cpp:538 -msgid "Preferences" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1120 +msgid "Browse to directory where the animation frames will be exported to" msgstr "" -#: ../src/dialogs/prefDialog.cpp:70 -msgid "Online Updates" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1122 +msgid "Enter a descriptive name for output files" msgstr "" -#: ../src/dialogs/prefDialog.cpp:72 -msgid "Panel Display" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1123 +msgid "Enter the target resoltuion (image size)" msgstr "" -#: ../src/dialogs/prefDialog.cpp:73 -msgid "Camera Speed" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1125 +msgid "Select frame for property display" msgstr "" -#: ../src/dialogs/prefDialog.cpp:74 -msgid "Filter Defaults" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1126 +msgid "Enter frame number to change frame (eg 1/20)" msgstr "" -#: ../src/dialogs/prefDialog.cpp:75 -msgid "Available Filters" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1127 +msgid "Save point data (POS files) in output folder?" msgstr "" -#: ../src/dialogs/prefDialog.cpp:78 -msgid "Reset All" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1128 +msgid "Save plots (as text files) in output folder?" msgstr "" -#: ../src/dialogs/prefDialog.cpp:81 -msgid "Show all panels" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1129 +msgid "Save voxel data (raw files) in output folder?" msgstr "" -#: ../src/dialogs/prefDialog.cpp:82 -msgid "Remember last" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1130 +msgid "Save range files in output folder?" msgstr "" -#: ../src/dialogs/prefDialog.cpp:83 -msgid "Show Selected" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:86 -msgid "Control Pane" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:87 -msgid "Raw Data Panel" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:88 ../src/3Depict.cpp:678 -msgid "Plot List" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:90 -msgid "Periodically notify about available updates" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:92 -msgid "Move Rate" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:93 ../src/dialogs/prefDialog.cpp:97 -msgid "(slow)" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:95 ../src/dialogs/prefDialog.cpp:99 -msgid "(fast)" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:96 -msgid "Zoom Rate" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:446 -msgid "Notice" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:449 -msgid "For security reasons, defaults are not modifiable for this filter" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:479 -msgid "Show all panels when starting program" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:482 -msgid "Show panels visible at last shutdown when starting program" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:489 -msgid "Show selected panels when starting program" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:540 -msgid "Set the method of panel layout when starting the program" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:543 -msgid "" -"Lets the program check the internet to see if updates to the program version " -"are available, then notifies you about updates now and again." -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:545 -msgid "Camera translation, orbit and swivel rates. " -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:546 -msgid "Camera zooming rate." -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:548 -msgid "Reset the filter initial values back to program defaults" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:549 -msgid "Reset all filter initial values back to program defaults" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:611 -msgid "Pref" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:612 -msgid "Startup" -msgstr "" - -#: ../src/dialogs/prefDialog.cpp:613 -msgid "Camera" -msgstr "" - -#: ../src/dialogs/autosaveDialog.cpp:22 -msgid "Remove &All" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1135 +msgid "Animation parameters for current frame" msgstr "" -#: ../src/dialogs/autosaveDialog.cpp:86 -msgid "Restore state?" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1136 +msgid "Abort animation" msgstr "" -#: ../src/dialogs/autosaveDialog.cpp:96 -msgid "Multiple autosave states were found; would you like to restore one?" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1137 +msgid "Run Animation" msgstr "" -#: ../src/colourmap.cpp:234 -msgid "Jet" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1208 +msgid "Filter view" msgstr "" -#: ../src/colourmap.cpp:235 -msgid "Hot" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1209 +msgid "Frame view" msgstr "" -#: ../src/colourmap.cpp:236 -msgid "Cold" +#: ../src/gui/dialogs/resolutionDialog.cpp:46 +msgid "Width :" msgstr "" -#: ../src/colourmap.cpp:237 -msgid "Grey" +#: ../src/gui/dialogs/resolutionDialog.cpp:48 +msgid "Height :" msgstr "" -#: ../src/colourmap.cpp:238 -msgid "Cyclic" +#: ../src/gui/dialogs/resolutionDialog.cpp:50 +msgid "Lock Aspect" msgstr "" -#: ../src/colourmap.cpp:239 -msgid "General" +#: ../src/gui/dialogs/resolutionDialog.cpp:54 +#: ../src/gui/dialogs/prefDialog.cpp:82 +msgid "Reset" msgstr "" -#: ../src/colourmap.cpp:240 -msgid "Blue" +#: ../src/gui/dialogs/resolutionDialog.cpp:462 +msgid "Resolution Selection" msgstr "" -#: ../src/colourmap.cpp:241 -msgid "Pseudo-Random" +#: ../src/gui/dialogs/ExportPos.cpp:75 +msgid "Export:" msgstr "" -#: ../src/viscontrol.cpp:1033 -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" +#: ../src/gui/dialogs/ExportPos.cpp:76 +#: ../src/backend/filters/boundingBox.cpp:528 +msgid "Visible" msgstr "" -#: ../src/viscontrol.cpp:1175 -msgid "Failed to allocate parser" +#: ../src/gui/dialogs/ExportPos.cpp:77 +msgid "Selected Data" msgstr "" -#: ../src/viscontrol.cpp:1211 -msgid "" -"Unable to retrieve root node in input state file... Is this really a non-" -"empty XML file?" +#: ../src/gui/dialogs/ExportPos.cpp:79 +msgid "Available Data" msgstr "" -#: ../src/viscontrol.cpp:1218 -msgid "Base state node missing. Is this really a state XML file??" +#: ../src/gui/dialogs/ExportPos.cpp:85 +msgid "Selection" msgstr "" -#: ../src/viscontrol.cpp:1247 -msgid "State was created by a newer version of this program.. " +#: ../src/gui/dialogs/ExportPos.cpp:110 ../src/gui/dialogs/ExportPos.cpp:113 +msgid "Index" msgstr "" -#: ../src/viscontrol.cpp:1248 -msgid "file reading will continue, but may fail." +#: ../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/spectrumPlot.cpp:240 +msgid "Count" msgstr "" -#: ../src/viscontrol.cpp:1253 -msgid "" -"Warning, unparseable version number in state file. File reading will " -"continue, but may fail" +#: ../src/gui/dialogs/ExportPos.cpp:450 +msgid "Export Pos Data" msgstr "" -#: ../src/viscontrol.cpp:1260 -msgid "Unable to find the \"writer\" node" +#: ../src/gui/dialogs/ExportPos.cpp:453 +msgid "Tree of filters, select leaves to show ion data." msgstr "" -#: ../src/viscontrol.cpp:1270 -msgid "Unable to find the \"backcolour\" node." +#: ../src/gui/dialogs/ExportPos.cpp:455 +msgid "Add all data from all filters" msgstr "" -#: ../src/viscontrol.cpp:1277 -msgid "\"backcolour\" node missing \"r\" value." +#: ../src/gui/dialogs/ExportPos.cpp:456 +msgid "Add all data from currently selected filter" msgstr "" -#: ../src/viscontrol.cpp:1282 -msgid "Unable to interpret \"backColour\" node's \"r\" value." +#: ../src/gui/dialogs/ExportPos.cpp:457 +msgid "Add selected data from currently selected filter" msgstr "" -#: ../src/viscontrol.cpp:1290 -msgid "\"backcolour\" node missing \"g\" value." +#: ../src/gui/dialogs/prefDialog.cpp:66 ../src/gui/dialogs/prefDialog.cpp:541 +msgid "Preferences" msgstr "" -#: ../src/viscontrol.cpp:1296 -msgid "Unable to interpret \"backColour\" node's \"g\" value." +#: ../src/gui/dialogs/prefDialog.cpp:73 +msgid "Online Updates" msgstr "" -#: ../src/viscontrol.cpp:1304 -msgid "\"backcolour\" node missing \"b\" value." +#: ../src/gui/dialogs/prefDialog.cpp:75 +msgid "Panel Display" msgstr "" -#: ../src/viscontrol.cpp:1310 -msgid "Unable to interpret \"backColour\" node's \"b\" value." +#: ../src/gui/dialogs/prefDialog.cpp:76 +msgid "Camera Speed" msgstr "" -#: ../src/viscontrol.cpp:1317 -msgid "\"backcolour\"s rgb values must be in range [0,1]" +#: ../src/gui/dialogs/prefDialog.cpp:77 +msgid "Filter Defaults" msgstr "" -#: ../src/viscontrol.cpp:1344 -msgid "Unable to find or interpret \"showaxis\" node" +#: ../src/gui/dialogs/prefDialog.cpp:78 +msgid "Available Filters" msgstr "" -#: ../src/viscontrol.cpp:1353 -msgid "Unable to locate \"filtertree\" node." +#: ../src/gui/dialogs/prefDialog.cpp:81 +msgid "Reset All" msgstr "" -#: ../src/viscontrol.cpp:1369 -msgid "Cameras section missing \"active\" node." +#: ../src/gui/dialogs/prefDialog.cpp:84 +msgid "Show all panels" msgstr "" -#: ../src/viscontrol.cpp:1377 -msgid "Unable to find property \"value\" for \"cameras->active\" node." +#: ../src/gui/dialogs/prefDialog.cpp:85 +msgid "Remember last" msgstr "" -#: ../src/viscontrol.cpp:1383 -msgid "Unable to interpret property \"value\" for \"cameras->active\" node." +#: ../src/gui/dialogs/prefDialog.cpp:86 +msgid "Show Selected" msgstr "" -#: ../src/viscontrol.cpp:1405 -msgid "Unable to interpret the camera type" +#: ../src/gui/dialogs/prefDialog.cpp:89 +msgid "Control Pane" msgstr "" -#: ../src/viscontrol.cpp:1440 -msgid "Unable to locate stash name for stash " +#: ../src/gui/dialogs/prefDialog.cpp:90 +msgid "Raw Data Panel" msgstr "" -#: ../src/viscontrol.cpp:1447 -msgid "Empty stash name for stash " +#: ../src/gui/dialogs/prefDialog.cpp:91 ../src/gui/mainFrame.cpp:618 +msgid "Plot List" msgstr "" -#: ../src/viscontrol.cpp:1453 -msgid "For stash " +#: ../src/gui/dialogs/prefDialog.cpp:93 +msgid "Periodically notify about available updates" msgstr "" -#: ../src/viscontrol.cpp:1481 -msgid "Unrecognised effect :" +#: ../src/gui/dialogs/prefDialog.cpp:95 +msgid "Move Rate" msgstr "" -#: ../src/viscontrol.cpp:1491 -msgid "Duplicate effect found" +#: ../src/gui/dialogs/prefDialog.cpp:96 ../src/gui/dialogs/prefDialog.cpp:100 +msgid "(slow)" msgstr "" -#: ../src/viscontrol.cpp:1491 -msgid " cannot use." +#: ../src/gui/dialogs/prefDialog.cpp:98 ../src/gui/dialogs/prefDialog.cpp:102 +msgid "(fast)" msgstr "" -#: ../src/viscontrol.cpp:1501 -msgid "Error reading effect : " +#: ../src/gui/dialogs/prefDialog.cpp:99 +msgid "Zoom Rate" msgstr "" -#: ../src/viscontrol.cpp:1562 -msgid "-merge" +#: ../src/gui/dialogs/prefDialog.cpp:449 +msgid "Notice" msgstr "" -#: ../src/viscontrol.cpp:1567 -msgid "" -" Unable to merge stashes correctly. This is improbable, so please report " -"this." +#: ../src/gui/dialogs/prefDialog.cpp:452 +msgid "For security reasons, defaults are not modifiable for this filter" msgstr "" -#: ../src/configFile.cpp:190 -msgid "Config file present, but is not valid (root node test)" +#: ../src/gui/dialogs/prefDialog.cpp:482 +msgid "Show all panels when starting program" msgstr "" -#: ../src/configFile.cpp:231 -msgid "Unable to interpret recent file entry" +#: ../src/gui/dialogs/prefDialog.cpp:485 +msgid "Show panels visible at last shutdown when starting program" msgstr "" -#: ../src/configFile.cpp:271 -msgid "Unable to determine filter type in defaults listing." +#: ../src/gui/dialogs/prefDialog.cpp:492 +msgid "Show selected panels when starting program" msgstr "" -#: ../src/configFile.cpp:572 -msgid "Online access for non win32/apple platforms is intentionally disabled, " +#: ../src/gui/dialogs/prefDialog.cpp:543 +msgid "Set the method of panel layout when starting the program" msgstr "" -#: ../src/configFile.cpp:573 +#: ../src/gui/dialogs/prefDialog.cpp:546 msgid "" -"regardless of the settings you use here. Use your package manager to keep up-" -"to-date" -msgstr "" - -#: ../src/plot.cpp:39 ../src/filters/voxelise.cpp:78 -msgid "None" -msgstr "" - -#: ../src/plot.cpp:40 -msgid "Moving avg." -msgstr "" - -#: ../src/plot.cpp:44 -msgid "Lines" -msgstr "" - -#: ../src/plot.cpp:45 -msgid "Bars" -msgstr "" - -#: ../src/plot.cpp:46 -msgid "Steps" -msgstr "" - -#: ../src/plot.cpp:47 -msgid "Stem" -msgstr "" - -#: ../src/plot.cpp:48 -msgid "Points" -msgstr "" - -#: ../src/plot.cpp:635 ../src/plot.cpp:643 -msgid "Multiple data types" -msgstr "" - -#: ../src/plot.cpp:789 -msgid "Mixed log/non-log:" -msgstr "" - -#: ../src/plot.cpp:1248 -msgid "error" -msgstr "" - -#: ../src/basics.cpp:56 ../src/APTClasses.cpp:187 -msgid "Error opening file" -msgstr "" - -#: ../src/basics.cpp:57 -msgid "Error whilst reading file contents" -msgstr "" - -#: ../src/basics.cpp:58 ../src/APTClasses.cpp:191 -msgid "Error interpreting field in file" -msgstr "" - -#: ../src/basics.cpp:59 -msgid "Inconsistent number of columns found" -msgstr "" - -#: ../src/basics.cpp:724 -msgid "in the future?" -msgstr "" - -#: ../src/basics.cpp:775 -msgid "a decade ago" -msgstr "" - -#: ../src/basics.cpp:776 -msgid "a year ago" -msgstr "" - -#: ../src/basics.cpp:777 -msgid "a month ago" -msgstr "" - -#: ../src/basics.cpp:778 -msgid "a week ago" -msgstr "" - -#: ../src/basics.cpp:779 -msgid "a day ago" -msgstr "" - -#: ../src/basics.cpp:780 -msgid "an hour ago" -msgstr "" - -#: ../src/basics.cpp:781 -msgid "45 minutes ago" -msgstr "" - -#: ../src/basics.cpp:782 -msgid "30 minutes ago" -msgstr "" - -#: ../src/basics.cpp:783 -msgid "20 minutes ago" -msgstr "" - -#: ../src/basics.cpp:784 -msgid "15 minutes ago" -msgstr "" - -#: ../src/basics.cpp:785 -msgid "10 minutes ago" -msgstr "" - -#: ../src/basics.cpp:786 -msgid "5 minutes ago" -msgstr "" - -#: ../src/basics.cpp:787 -msgid "a minute ago" -msgstr "" - -#: ../src/basics.cpp:788 -msgid "30 seconds ago" -msgstr "" - -#: ../src/basics.cpp:789 -msgid "10 seconds ago" -msgstr "" - -#: ../src/basics.cpp:790 -msgid "a second ago" -msgstr "" - -#: ../src/basics.cpp:795 -msgid "a few decades ago" -msgstr "" - -#: ../src/basics.cpp:796 -msgid "a few years ago" +"Lets the program check the internet to see if updates to the program version " +"are available, then notifies you about updates now and again." msgstr "" -#: ../src/basics.cpp:797 -msgid "a few months ago" +#: ../src/gui/dialogs/prefDialog.cpp:548 +msgid "Camera translation, orbit and swivel rates. " msgstr "" -#: ../src/basics.cpp:798 -msgid "a few weeks ago" +#: ../src/gui/dialogs/prefDialog.cpp:549 +msgid "Camera zooming rate." msgstr "" -#: ../src/basics.cpp:799 -msgid "a few days ago" +#: ../src/gui/dialogs/prefDialog.cpp:551 +msgid "Reset the filter initial values back to program defaults" msgstr "" -#: ../src/basics.cpp:800 -msgid "a few hours ago" +#: ../src/gui/dialogs/prefDialog.cpp:552 +msgid "Reset all filter initial values back to program defaults" msgstr "" -#: ../src/basics.cpp:807 -msgid "a few minutes ago" +#: ../src/gui/dialogs/prefDialog.cpp:614 +msgid "Pref" msgstr "" -#: ../src/basics.cpp:810 -msgid "a few seconds ago" +#: ../src/gui/dialogs/prefDialog.cpp:615 +msgid "Startup" msgstr "" -#: ../src/basics.cpp:837 -msgid "moments ago" +#: ../src/gui/dialogs/prefDialog.cpp:616 +msgid "Camera" msgstr "" -#: ../src/3Depict.cpp:143 +#: ../src/gui/mainFrame.cpp:88 msgid "New camera name..." msgstr "" -#: ../src/3Depict.cpp:144 +#: ../src/gui/mainFrame.cpp:89 msgid "New stash name...." msgstr "" -#: ../src/3Depict.cpp:163 ../src/filters/annotation.cpp:532 -#: ../src/filters/annotation.cpp:634 ../src/filters/annotation.h:81 +#: ../src/gui/mainFrame.cpp:105 ../src/backend/filters/annotation.cpp:549 +#: ../src/backend/filters/annotation.cpp:651 +#: ../src/backend/filters/annotation.h:98 msgid "Annotation" msgstr "" -#: ../src/3Depict.cpp:164 +#: ../src/gui/mainFrame.cpp:106 msgid "Bounding Box" msgstr "" -#: ../src/3Depict.cpp:165 ../src/filters/ionClip.h:49 +#: ../src/gui/mainFrame.cpp:107 ../src/backend/filters/ionClip.h:66 msgid "Clipping" msgstr "" -#: ../src/3Depict.cpp:166 ../src/filters/clusterAnalysis.h:113 +#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/clusterAnalysis.h:132 msgid "Cluster Analysis" msgstr "" -#: ../src/3Depict.cpp:167 +#: ../src/gui/mainFrame.cpp:109 msgid "Compos. Profiles" msgstr "" -#: ../src/3Depict.cpp:168 +#: ../src/gui/mainFrame.cpp:110 msgid "Downsampling" msgstr "" -#: ../src/3Depict.cpp:169 +#: ../src/gui/mainFrame.cpp:111 msgid "Extern. Prog." msgstr "" -#: ../src/3Depict.cpp:170 +#: ../src/gui/mainFrame.cpp:112 msgid "Ion Colour" msgstr "" -#: ../src/3Depict.cpp:171 +#: ../src/gui/mainFrame.cpp:113 msgid "Ion Info" msgstr "" -#: ../src/3Depict.cpp:172 +#: ../src/gui/mainFrame.cpp:114 msgid "Ion Transform" msgstr "" -#: ../src/3Depict.cpp:173 ../src/filters/spectrumPlot.h:36 +#: ../src/gui/mainFrame.cpp:115 ../src/backend/filters/spectrumPlot.h:53 msgid "Spectrum" msgstr "" -#: ../src/3Depict.cpp:174 +#: ../src/gui/mainFrame.cpp:116 msgid "Range File" msgstr "" -#: ../src/3Depict.cpp:175 ../src/filters/spatialAnalysis.h:73 +#: ../src/gui/mainFrame.cpp:117 ../src/backend/filters/spatialAnalysis.h:142 msgid "Spat. Analysis" msgstr "" -#: ../src/3Depict.cpp:176 ../src/filters/voxelise.h:72 +#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/voxelise.h:89 msgid "Voxelisation" msgstr "" -#: ../src/3Depict.cpp:462 ../src/3Depict.cpp:468 +#: ../src/gui/mainFrame.cpp:403 +msgid "OpenGL Failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:404 ../src/gui/mainFrame.cpp:406 msgid "" "Unable to initialise the openGL (3D) panel. Program cannot start. Please " "check your video drivers." msgstr "" -#: ../src/3Depict.cpp:463 -msgid "OpenGL Failed" -msgstr "" - -#: ../src/3Depict.cpp:487 +#: ../src/gui/mainFrame.cpp:426 msgid "&Open...\tCtrl+O" msgstr "" -#: ../src/3Depict.cpp:487 +#: ../src/gui/mainFrame.cpp:426 msgid "Open state file" msgstr "" -#: ../src/3Depict.cpp:488 +#: ../src/gui/mainFrame.cpp:427 msgid "&Merge...\tCtrl+Shift+O" msgstr "" -#: ../src/3Depict.cpp:488 +#: ../src/gui/mainFrame.cpp:427 msgid "Merge other file" msgstr "" -#: ../src/3Depict.cpp:492 +#: ../src/gui/mainFrame.cpp:431 msgid "&Recent" msgstr "" -#: ../src/3Depict.cpp:493 +#: ../src/gui/mainFrame.cpp:432 msgid "&Save\tCtrl+S" msgstr "" -#: ../src/3Depict.cpp:493 +#: ../src/gui/mainFrame.cpp:432 msgid "Save state to file" msgstr "" -#: ../src/3Depict.cpp:495 +#: ../src/gui/mainFrame.cpp:434 msgid "Save &As...\tCtrl+Shift+S" msgstr "" -#: ../src/3Depict.cpp:495 +#: ../src/gui/mainFrame.cpp:434 msgid "Save current state to new file" msgstr "" -#: ../src/3Depict.cpp:498 +#: ../src/gui/mainFrame.cpp:437 msgid "&Plot...\tCtrl+P" msgstr "" -#: ../src/3Depict.cpp:498 +#: ../src/gui/mainFrame.cpp:437 msgid "Export Current Plot" msgstr "" -#: ../src/3Depict.cpp:499 +#: ../src/gui/mainFrame.cpp:438 msgid "&Image...\tCtrl+I" msgstr "" -#: ../src/3Depict.cpp:499 +#: ../src/gui/mainFrame.cpp:438 msgid "Export Current 3D View" msgstr "" -#: ../src/3Depict.cpp:500 +#: ../src/gui/mainFrame.cpp:439 msgid "Ion&s...\tCtrl+N" msgstr "" -#: ../src/3Depict.cpp:500 +#: ../src/gui/mainFrame.cpp:439 msgid "Export Ion Data" msgstr "" -#: ../src/3Depict.cpp:501 +#: ../src/gui/mainFrame.cpp:440 msgid "Ran&ges...\tCtrl+G" msgstr "" -#: ../src/3Depict.cpp:501 +#: ../src/gui/mainFrame.cpp:440 msgid "Export Range Data" msgstr "" -#: ../src/3Depict.cpp:502 +#: ../src/gui/mainFrame.cpp:441 msgid "&Animate Filters...\tCtrl+A" msgstr "" -#: ../src/3Depict.cpp:502 +#: ../src/gui/mainFrame.cpp:441 msgid "Export Animated Filter" msgstr "" -#: ../src/3Depict.cpp:503 +#: ../src/gui/mainFrame.cpp:442 msgid "Ani&mate Camera...\tCtrl+M" msgstr "" -#: ../src/3Depict.cpp:503 +#: ../src/gui/mainFrame.cpp:442 msgid "Export Animated Camera" msgstr "" -#: ../src/3Depict.cpp:504 +#: ../src/gui/mainFrame.cpp:443 msgid "Pac&kage...\tCtrl+K" msgstr "" -#: ../src/3Depict.cpp:504 +#: ../src/gui/mainFrame.cpp:443 msgid "Export analysis package" msgstr "" -#: ../src/3Depict.cpp:506 +#: ../src/gui/mainFrame.cpp:445 msgid "&Export" msgstr "" -#: ../src/3Depict.cpp:509 +#: ../src/gui/mainFrame.cpp:448 msgid "&Quit\tCtrl+Q" msgstr "" -#: ../src/3Depict.cpp:509 ../src/3Depict.cpp:511 +#: ../src/gui/mainFrame.cpp:448 ../src/gui/mainFrame.cpp:450 msgid "Exit Program" msgstr "" -#: ../src/3Depict.cpp:511 +#: ../src/gui/mainFrame.cpp:450 msgid "E&xit" msgstr "" -#: ../src/3Depict.cpp:513 +#: ../src/gui/mainFrame.cpp:452 msgid "&File" msgstr "" -#: ../src/3Depict.cpp:516 +#: ../src/gui/mainFrame.cpp:456 msgid "&Background Colour...\tCtrl+B" msgstr "" -#: ../src/3Depict.cpp:516 +#: ../src/gui/mainFrame.cpp:456 msgid "Change background colour" msgstr "" -#: ../src/3Depict.cpp:520 +#: ../src/gui/mainFrame.cpp:460 msgid "&Control Pane\tF3" msgstr "" -#: ../src/3Depict.cpp:520 ../src/3Depict.cpp:523 +#: ../src/gui/mainFrame.cpp:460 ../src/gui/mainFrame.cpp:463 msgid "Toggle left control pane" msgstr "" -#: ../src/3Depict.cpp:523 +#: ../src/gui/mainFrame.cpp:463 msgid "&Control Pane\tAlt+C" msgstr "" -#: ../src/3Depict.cpp:529 +#: ../src/gui/mainFrame.cpp:469 msgid "&Raw Data Pane\tF4" msgstr "" -#: ../src/3Depict.cpp:529 ../src/3Depict.cpp:532 +#: ../src/gui/mainFrame.cpp:469 ../src/gui/mainFrame.cpp:472 msgid "Toggle raw data pane (bottom)" msgstr "" -#: ../src/3Depict.cpp:532 +#: ../src/gui/mainFrame.cpp:472 msgid "&Raw Data Pane\tAlt+R" msgstr "" -#: ../src/3Depict.cpp:536 +#: ../src/gui/mainFrame.cpp:476 msgid "&Plot List\tF5" msgstr "" -#: ../src/3Depict.cpp:536 ../src/3Depict.cpp:538 +#: ../src/gui/mainFrame.cpp:476 ../src/gui/mainFrame.cpp:478 msgid "Toggle plot list" msgstr "" -#: ../src/3Depict.cpp:538 +#: ../src/gui/mainFrame.cpp:478 msgid "&Plot List\tAlt+P" msgstr "" -#: ../src/3Depict.cpp:544 +#: ../src/gui/mainFrame.cpp:484 msgid "&Legend\tCtrl+L" msgstr "" -#: ../src/3Depict.cpp:544 +#: ../src/gui/mainFrame.cpp:484 msgid "Toggle Legend display" msgstr "" -#: ../src/3Depict.cpp:546 +#: ../src/gui/mainFrame.cpp:486 msgid "P&lot..." msgstr "" -#: ../src/3Depict.cpp:547 +#: ../src/gui/mainFrame.cpp:487 msgid "&Axis\tCtrl+Shift+I" msgstr "" -#: ../src/3Depict.cpp:547 +#: ../src/gui/mainFrame.cpp:487 msgid "Toggle World Axis display" msgstr "" -#: ../src/3Depict.cpp:552 +#: ../src/gui/mainFrame.cpp:492 msgid "&Fullscreen mode\tF11" msgstr "" -#: ../src/3Depict.cpp:552 ../src/3Depict.cpp:554 +#: ../src/gui/mainFrame.cpp:492 ../src/gui/mainFrame.cpp:494 msgid "Next fullscreen mode: with toolbars" msgstr "" -#: ../src/3Depict.cpp:554 +#: ../src/gui/mainFrame.cpp:494 msgid "&Fullscreen mode\tCtrl+Shift+F" msgstr "" -#: ../src/3Depict.cpp:559 +#: ../src/gui/mainFrame.cpp:499 msgid "&Undo\tCtrl+Z" msgstr "" -#: ../src/3Depict.cpp:561 +#: ../src/gui/mainFrame.cpp:501 msgid "&Redo\tCtrl+Y" msgstr "" -#: ../src/3Depict.cpp:564 +#: ../src/gui/mainFrame.cpp:504 msgid "&Preferences" msgstr "" -#: ../src/3Depict.cpp:566 +#: ../src/gui/mainFrame.cpp:506 msgid "&Edit" msgstr "" -#: ../src/3Depict.cpp:569 +#: ../src/gui/mainFrame.cpp:509 msgid "&View" msgstr "" -#: ../src/3Depict.cpp:571 +#: ../src/gui/mainFrame.cpp:511 msgid "&Help...\tCtrl+H" msgstr "" -#: ../src/3Depict.cpp:571 +#: ../src/gui/mainFrame.cpp:511 msgid "Show help files and documentation" msgstr "" -#: ../src/3Depict.cpp:572 +#: ../src/gui/mainFrame.cpp:512 msgid "&Contact..." msgstr "" -#: ../src/3Depict.cpp:572 +#: ../src/gui/mainFrame.cpp:512 msgid "Open contact page" msgstr "" -#: ../src/3Depict.cpp:574 +#: ../src/gui/mainFrame.cpp:514 msgid "&About..." msgstr "" -#: ../src/3Depict.cpp:574 +#: ../src/gui/mainFrame.cpp:514 msgid "Information about this program" msgstr "" -#: ../src/3Depict.cpp:575 +#: ../src/gui/mainFrame.cpp:515 msgid "&Help" msgstr "" -#: ../src/3Depict.cpp:577 +#: ../src/gui/mainFrame.cpp:517 msgid "Stashed Filters" msgstr "" -#: ../src/3Depict.cpp:582 +#: ../src/gui/mainFrame.cpp:522 msgid "Data Filtering" msgstr "" -#: ../src/3Depict.cpp:606 +#: ../src/gui/mainFrame.cpp:546 msgid "Last Outputs" msgstr "" -#: ../src/3Depict.cpp:608 +#: ../src/gui/mainFrame.cpp:548 msgid "Auto Refresh" msgstr "" -#: ../src/3Depict.cpp:614 +#: ../src/gui/mainFrame.cpp:554 msgid "Filter settings" msgstr "" -#: ../src/3Depict.cpp:616 +#: ../src/gui/mainFrame.cpp:556 msgid "Camera Name" msgstr "" -#: ../src/3Depict.cpp:622 +#: ../src/gui/mainFrame.cpp:562 msgid "3D Post-processing" msgstr "" -#: ../src/3Depict.cpp:624 +#: ../src/gui/mainFrame.cpp:564 msgid "Enable Cropping" msgstr "" -#: ../src/3Depict.cpp:626 ../src/3Depict.cpp:637 +#: ../src/gui/mainFrame.cpp:566 ../src/gui/mainFrame.cpp:577 msgid "x-y" msgstr "" -#: ../src/3Depict.cpp:627 ../src/3Depict.cpp:638 +#: ../src/gui/mainFrame.cpp:567 ../src/gui/mainFrame.cpp:578 msgid "x-z" msgstr "" -#: ../src/3Depict.cpp:628 ../src/3Depict.cpp:639 +#: ../src/gui/mainFrame.cpp:568 ../src/gui/mainFrame.cpp:579 msgid "y-x" msgstr "" -#: ../src/3Depict.cpp:629 ../src/3Depict.cpp:640 +#: ../src/gui/mainFrame.cpp:569 ../src/gui/mainFrame.cpp:580 msgid "y-z" msgstr "" -#: ../src/3Depict.cpp:630 ../src/3Depict.cpp:641 +#: ../src/gui/mainFrame.cpp:570 ../src/gui/mainFrame.cpp:581 msgid "z-x" msgstr "" -#: ../src/3Depict.cpp:631 ../src/3Depict.cpp:642 +#: ../src/gui/mainFrame.cpp:571 ../src/gui/mainFrame.cpp:582 msgid "z-y" msgstr "" -#: ../src/3Depict.cpp:646 +#: ../src/gui/mainFrame.cpp:586 msgid "Use camera coordinates" msgstr "" -#: ../src/3Depict.cpp:647 +#: ../src/gui/mainFrame.cpp:587 msgid "dX" msgstr "" -#: ../src/3Depict.cpp:649 +#: ../src/gui/mainFrame.cpp:589 msgid "dY" msgstr "" -#: ../src/3Depict.cpp:651 +#: ../src/gui/mainFrame.cpp:591 msgid "dZ" msgstr "" -#: ../src/3Depict.cpp:653 +#: ../src/gui/mainFrame.cpp:593 msgid "Enable Anaglyphic Stereo" msgstr "" -#: ../src/3Depict.cpp:654 +#: ../src/gui/mainFrame.cpp:594 msgid "Flip Channels" msgstr "" -#: ../src/3Depict.cpp:655 +#: ../src/gui/mainFrame.cpp:595 msgid "Anaglyph Mode" msgstr "" -#: ../src/3Depict.cpp:657 +#: ../src/gui/mainFrame.cpp:597 msgid "Red-Blue" msgstr "" -#: ../src/3Depict.cpp:658 +#: ../src/gui/mainFrame.cpp:598 msgid "Red-Green" msgstr "" -#: ../src/3Depict.cpp:659 +#: ../src/gui/mainFrame.cpp:599 msgid "Red-Cyan" msgstr "" -#: ../src/3Depict.cpp:660 +#: ../src/gui/mainFrame.cpp:600 msgid "Green-Magenta" msgstr "" -#: ../src/3Depict.cpp:664 +#: ../src/gui/mainFrame.cpp:604 msgid "Baseline Separation" msgstr "" -#: ../src/3Depict.cpp:666 +#: ../src/gui/mainFrame.cpp:606 msgid "Smooth && translucent objects" msgstr "" -#: ../src/3Depict.cpp:668 +#: ../src/gui/mainFrame.cpp:608 msgid "3D lighting" msgstr "" -#: ../src/3Depict.cpp:670 +#: ../src/gui/mainFrame.cpp:610 msgid "Fast and weak randomisation." msgstr "" -#: ../src/3Depict.cpp:672 +#: ../src/gui/mainFrame.cpp:612 msgid "Filter caching" msgstr "" -#: ../src/3Depict.cpp:674 +#: ../src/gui/mainFrame.cpp:614 msgid "Max. Ram usage (%)" msgstr "" -#: ../src/3Depict.cpp:728 +#: ../src/gui/mainFrame.cpp:671 msgid "Type" msgstr "" -#: ../src/3Depict.cpp:729 +#: ../src/gui/mainFrame.cpp:672 msgid "Num" msgstr "" -#: ../src/3Depict.cpp:794 +#: ../src/gui/mainFrame.cpp:683 msgid "Warning: Your configuration file appears to be invalid:\n" msgstr "" -#: ../src/3Depict.cpp:795 +#: ../src/gui/mainFrame.cpp:684 msgid "\tConfig Load: " msgstr "" -#: ../src/3Depict.cpp:1030 ../src/3Depict.cpp:1080 +#: ../src/gui/mainFrame.cpp:885 ../src/gui/mainFrame.cpp:933 msgid "Select Data or State File..." msgstr "" -#: ../src/3Depict.cpp:1031 +#: ../src/gui/mainFrame.cpp:886 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/3Depict.cpp:1065 ../src/3Depict.cpp:1449 +#: ../src/gui/mainFrame.cpp:919 ../src/gui/mainFrame.cpp:1274 msgid "Loaded file." msgstr "" -#: ../src/3Depict.cpp:1081 +#: ../src/gui/mainFrame.cpp:934 msgid "" "3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|" "XML State File (*.xml)|*.xml|All Files (*)|*" msgstr "" -#: ../src/3Depict.cpp:1100 +#: ../src/gui/mainFrame.cpp:945 msgid "Merged file." msgstr "" -#: ../src/3Depict.cpp:1217 +#: ../src/gui/mainFrame.cpp:1047 msgid "Tip: You can use ⌘ (command) to merge" msgstr "" -#: ../src/3Depict.cpp:1219 +#: ../src/gui/mainFrame.cpp:1049 msgid "Tip: You can use ctrl to merge" msgstr "" -#: ../src/3Depict.cpp:1268 +#: ../src/gui/mainFrame.cpp:1097 +msgid "Load error" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1098 msgid "" "Error loading state file.\n" "See console for more info." msgstr "" -#: ../src/3Depict.cpp:1269 -msgid "Load error" -msgstr "" - -#: ../src/3Depict.cpp:1293 +#: ../src/gui/mainFrame.cpp:1120 msgid "" "This state file contains filters that can be unsafe to run\n" "Do you wish to remove these before continuing?." msgstr "" -#: ../src/3Depict.cpp:1294 +#: ../src/gui/mainFrame.cpp:1121 msgid "Security warning" msgstr "" -#: ../src/3Depict.cpp:1512 -msgid "No plot available. Please create a plot before exporting." +#: ../src/gui/mainFrame.cpp:1330 ../src/gui/mainFrame.cpp:1429 +#: ../src/gui/mainFrame.cpp:1792 +msgid "Unable to save" msgstr "" -#: ../src/3Depict.cpp:1514 ../src/3Depict.cpp:1568 ../src/3Depict.cpp:1883 -msgid "Unable to save" +#: ../src/gui/mainFrame.cpp:1331 +msgid "No plot available. Please create a plot before exporting." msgstr "" -#: ../src/3Depict.cpp:1521 +#: ../src/gui/mainFrame.cpp:1335 msgid "Save plot..." msgstr "" -#: ../src/3Depict.cpp:1522 +#: ../src/gui/mainFrame.cpp:1336 msgid "" "By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*." "svg|PNG File (*.png)|*.png|All Files (*)|*" msgstr "" -#: ../src/3Depict.cpp:1551 ../src/3Depict.cpp:1604 ../src/3Depict.cpp:1661 +#: ../src/gui/mainFrame.cpp:1392 +msgid "Select type for save" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1392 +msgid "Choose file type" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1414 ../src/gui/mainFrame.cpp:1457 +#: ../src/gui/mainFrame.cpp:1504 msgid "Choose resolution" msgstr "" -#: ../src/3Depict.cpp:1566 +#: ../src/gui/mainFrame.cpp:1430 msgid "Unknown file extension. Please use \"svg\" or \"png\"" msgstr "" -#: ../src/3Depict.cpp:1588 +#: ../src/gui/mainFrame.cpp:1441 msgid "Saved plot: " msgstr "" -#: ../src/3Depict.cpp:1595 ../src/3Depict.cpp:1653 +#: ../src/gui/mainFrame.cpp:1448 ../src/gui/mainFrame.cpp:1496 msgid "Save Image..." msgstr "" -#: ../src/3Depict.cpp:1596 ../src/3Depict.cpp:1654 +#: ../src/gui/mainFrame.cpp:1449 ../src/gui/mainFrame.cpp:1497 msgid "PNG File (*.png)|*.png|All Files (*)|*" msgstr "" -#: ../src/3Depict.cpp:1619 +#: ../src/gui/mainFrame.cpp:1472 ../src/gui/mainFrame.cpp:1521 +msgid "Program limitation" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1473 msgid "" "Limitation on the screenshot dimension; please ensure that both width and " "height exceed the initial values,\n" -" or that they are smaller than the initial values.\n" +" or that they are both smaller than the initial values.\n" " If this bothers you, please submit a bug." msgstr "" -#: ../src/3Depict.cpp:1620 ../src/3Depict.cpp:1680 -msgid "Program limitation" -msgstr "" - -#: ../src/3Depict.cpp:1644 ../src/3Depict.cpp:1740 +#: ../src/gui/mainFrame.cpp:1487 ../src/gui/mainFrame.cpp:1570 msgid "Saved 3D View :" msgstr "" -#: ../src/3Depict.cpp:1679 +#: ../src/gui/mainFrame.cpp:1522 msgid "" "Limitation on the screenshot dimension; please ensure that both width and " "height exceed the initial values,\n" @@ -1635,403 +1531,404 @@ " If this bothers, please submit a bug." msgstr "" -#: ../src/3Depict.cpp:1702 +#: ../src/gui/mainFrame.cpp:1538 msgid "Number of frames" msgstr "" -#: ../src/3Depict.cpp:1815 +#: ../src/gui/mainFrame.cpp:1678 +msgid "Cannot animate with no filters." +msgstr "" + +#: ../src/gui/mainFrame.cpp:1725 msgid "Filter property change failed" msgstr "" -#: ../src/3Depict.cpp:1817 +#: ../src/gui/mainFrame.cpp:1727 msgid "Filter change error" msgstr "" -#: ../src/3Depict.cpp:1841 +#: ../src/gui/mainFrame.cpp:1750 msgid "Refresh failed on frame :" msgstr "" -#: ../src/3Depict.cpp:1843 +#: ../src/gui/mainFrame.cpp:1752 msgid "Refresh failed" msgstr "" -#: ../src/3Depict.cpp:1869 +#: ../src/gui/mainFrame.cpp:1778 msgid "Scene generation failed" msgstr "" -#: ../src/3Depict.cpp:1870 +#: ../src/gui/mainFrame.cpp:1779 msgid "Unable to generate scene for frame " msgstr "" -#: ../src/3Depict.cpp:1884 +#: ../src/gui/mainFrame.cpp:1793 msgid "Image save failed for frame " msgstr "" -#: ../src/3Depict.cpp:1909 +#: ../src/gui/mainFrame.cpp:1818 msgid "Ion save failed" msgstr "" -#: ../src/3Depict.cpp:1910 +#: ../src/gui/mainFrame.cpp:1819 msgid "Unable to save ions for frame " msgstr "" -#: ../src/3Depict.cpp:1941 +#: ../src/gui/mainFrame.cpp:1850 msgid "Plot save failed" msgstr "" -#: ../src/3Depict.cpp:1942 +#: ../src/gui/mainFrame.cpp:1851 msgid "Unable to save plot or frame " msgstr "" -#: ../src/3Depict.cpp:1983 +#: ../src/gui/mainFrame.cpp:1892 msgid "Range save failed" msgstr "" -#: ../src/3Depict.cpp:1984 +#: ../src/gui/mainFrame.cpp:1893 msgid "Unable to save range for frame " msgstr "" -#: ../src/3Depict.cpp:2013 +#: ../src/gui/mainFrame.cpp:1922 msgid "Voxel save failed" msgstr "" -#: ../src/3Depict.cpp:2014 +#: ../src/gui/mainFrame.cpp:1923 msgid "Unable to save voxels for frame " msgstr "" -#: ../src/3Depict.cpp:2057 ../src/3Depict.cpp:2173 ../src/3Depict.cpp:2275 +#: ../src/gui/mainFrame.cpp:1969 ../src/gui/mainFrame.cpp:2076 +#: ../src/gui/mainFrame.cpp:2173 msgid "No filters means no data to export" msgstr "" -#: ../src/3Depict.cpp:2063 +#: ../src/gui/mainFrame.cpp:1975 msgid "Package name" msgstr "" -#: ../src/3Depict.cpp:2064 +#: ../src/gui/mainFrame.cpp:1976 msgid "Package directory name" msgstr "" -#: ../src/3Depict.cpp:2066 +#: ../src/gui/mainFrame.cpp:1978 msgid "AnalysisPackage" msgstr "" -#: ../src/3Depict.cpp:2078 +#: ../src/gui/mainFrame.cpp:1990 msgid "Package folder already exists, won't overwrite." msgstr "" -#: ../src/3Depict.cpp:2079 +#: ../src/gui/mainFrame.cpp:1991 msgid "Not available" msgstr "" -#: ../src/3Depict.cpp:2110 +#: ../src/gui/mainFrame.cpp:2022 msgid "" "Package folder creation failed\n" "check writing to this location is possible." msgstr "" -#: ../src/3Depict.cpp:2111 +#: ../src/gui/mainFrame.cpp:2023 msgid "Folder creation failed" msgstr "" -#: ../src/3Depict.cpp:2138 +#: ../src/gui/mainFrame.cpp:2045 msgid "Copying" msgstr "" -#: ../src/3Depict.cpp:2139 +#: ../src/gui/mainFrame.cpp:2046 msgid "Copying referenced files" msgstr "" -#: ../src/3Depict.cpp:2147 +#: ../src/gui/mainFrame.cpp:2054 msgid "Error copying file" msgstr "" -#: ../src/3Depict.cpp:2162 +#: ../src/gui/mainFrame.cpp:2065 msgid "Saved package: " msgstr "" -#: ../src/3Depict.cpp:2183 +#: ../src/gui/mainFrame.cpp:2086 msgid "Export" msgstr "" -#: ../src/3Depict.cpp:2188 +#: ../src/gui/mainFrame.cpp:2091 msgid "POS Data (*.pos)|*.pos|All Files (*)|*" msgstr "" -#: ../src/3Depict.cpp:2216 ../src/3Depict.cpp:2320 +#: ../src/gui/mainFrame.cpp:2119 ../src/gui/mainFrame.cpp:2218 msgid "File already exists, overwrite?" msgstr "" -#: ../src/3Depict.cpp:2217 ../src/3Depict.cpp:2321 ../src/3Depict.cpp:2347 +#: ../src/gui/mainFrame.cpp:2120 ../src/gui/mainFrame.cpp:2219 +#: ../src/gui/mainFrame.cpp:2245 msgid "Overwrite?" msgstr "" -#: ../src/3Depict.cpp:2254 +#: ../src/gui/mainFrame.cpp:2152 msgid "Saved ions: " msgstr "" -#: ../src/3Depict.cpp:2279 +#: ../src/gui/mainFrame.cpp:2177 msgid "Export Ranges" msgstr "" -#: ../src/3Depict.cpp:2302 +#: ../src/gui/mainFrame.cpp:2200 msgid "Save state..." msgstr "" -#: ../src/3Depict.cpp:2303 +#: ../src/gui/mainFrame.cpp:2201 msgid "XML state file (*.xml)|*.xml|All Files (*)|*" msgstr "" -#: ../src/3Depict.cpp:2346 +#: ../src/gui/mainFrame.cpp:2244 msgid "Files have been referred to using relative paths. Keep relative paths?" msgstr "" -#: ../src/3Depict.cpp:2383 +#: ../src/gui/mainFrame.cpp:2276 msgid "Saved state: " msgstr "" -#: ../src/3Depict.cpp:2719 +#: ../src/gui/mainFrame.cpp:2612 msgid "Manual not found locally. Launching web browser" msgstr "" -#: ../src/3Depict.cpp:2728 +#: ../src/gui/mainFrame.cpp:2621 msgid "Opening contact page in external web browser" msgstr "" -#: ../src/3Depict.cpp:2740 +#: ../src/gui/mainFrame.cpp:2633 msgid "No filter stashes to edit." msgstr "" -#: ../src/3Depict.cpp:2744 +#: ../src/gui/mainFrame.cpp:2637 msgid "Filter Stashes" msgstr "" -#: ../src/3Depict.cpp:2773 +#: ../src/gui/mainFrame.cpp:2666 msgid "Quick and dirty analysis for point data." msgstr "" -#: ../src/3Depict.cpp:2783 +#: ../src/gui/mainFrame.cpp:2676 msgid "Compiled with wx Version: " msgstr "" -#: ../src/3Depict.cpp:2804 +#: ../src/gui/mainFrame.cpp:2697 msgid "Press enter to store new stash" msgstr "" -#: ../src/3Depict.cpp:2810 +#: ../src/gui/mainFrame.cpp:2703 msgid "Press enter to restore stash" msgstr "" -#: ../src/3Depict.cpp:2848 +#: ../src/gui/mainFrame.cpp:2738 msgid "Unable to create stash, selection invalid" msgstr "" -#: ../src/3Depict.cpp:2860 +#: ../src/gui/mainFrame.cpp:2746 msgid "Created new filter tree stash" msgstr "" -#: ../src/3Depict.cpp:2983 +#: ../src/gui/mainFrame.cpp:2868 msgid "Filter type not a data source - can't be at tree base" msgstr "" -#: ../src/3Depict.cpp:3154 +#: ../src/gui/mainFrame.cpp:3026 msgid "Moving - Hold ⌘ (command) to copy" msgstr "" -#: ../src/3Depict.cpp:3156 +#: ../src/gui/mainFrame.cpp:3028 msgid "Moving - Hold control to copy" msgstr "" -#: ../src/3Depict.cpp:3427 +#: ../src/gui/mainFrame.cpp:3284 msgid "Press enter to store new camera" msgstr "" -#: ../src/3Depict.cpp:3429 +#: ../src/gui/mainFrame.cpp:3286 msgid "Press enter to restore camera" msgstr "" -#: ../src/3Depict.cpp:3454 ../src/3Depict.cpp:3491 +#: ../src/gui/mainFrame.cpp:3311 ../src/gui/mainFrame.cpp:3348 msgid "Restored camera: " msgstr "" -#: ../src/3Depict.cpp:3472 +#: ../src/gui/mainFrame.cpp:3329 msgid "Stored camera: " msgstr "" -#: ../src/3Depict.cpp:3553 +#: ../src/gui/mainFrame.cpp:3406 msgid "Select an item from the filter tree before choosing a new filter" msgstr "" -#: ../src/3Depict.cpp:3555 +#: ../src/gui/mainFrame.cpp:3408 msgid "Load data source (file->open) before choosing a new filter" msgstr "" -#: ../src/3Depict.cpp:3576 +#: ../src/gui/mainFrame.cpp:3429 msgid "Select RNG File..." msgstr "" -#: ../src/3Depict.cpp:3577 +#: ../src/gui/mainFrame.cpp:3430 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/3Depict.cpp:3597 +#: ../src/gui/mainFrame.cpp:3450 msgid "Failed reading range file." msgstr "" -#: ../src/3Depict.cpp:3602 +#: ../src/gui/mainFrame.cpp:3454 msgid "Error loading file" msgstr "" -#: ../src/3Depict.cpp:3672 ../src/3Depict.cpp:3725 ../src/3Depict.cpp:5010 -#: ../src/3Depict.cpp:5540 +#: ../src/gui/mainFrame.cpp:3510 ../src/gui/mainFrame.cpp:3563 +#: ../src/gui/mainFrame.cpp:4946 ../src/gui/mainFrame.cpp:5481 msgid "Cons." msgstr "" -#: ../src/3Depict.cpp:3702 +#: ../src/gui/mainFrame.cpp:3540 msgid "Refresh Aborted." msgstr "" -#: ../src/3Depict.cpp:3729 +#: ../src/gui/mainFrame.cpp:3567 msgid "*Cons." msgstr "" -#: ../src/3Depict.cpp:3731 +#: ../src/gui/mainFrame.cpp:3569 msgid "§Cons." msgstr "" -#: ../src/3Depict.cpp:3841 +#: ../src/gui/mainFrame.cpp:3680 msgid "Autosave complete." msgstr "" -#: ../src/3Depict.cpp:4001 +#: ../src/gui/mainFrame.cpp:3835 msgid "Aborted." msgstr "" -#: ../src/3Depict.cpp:4027 ../src/3Depict.cpp:4031 ../src/3Depict.cpp:4044 -#: ../src/glPane.cpp:917 ../src/glPane.cpp:1082 -msgid " of " -msgstr "" - -#: ../src/3Depict.cpp:4042 +#: ../src/gui/mainFrame.cpp:3876 msgid "Updated." msgstr "" -#: ../src/3Depict.cpp:4048 +#: ../src/gui/mainFrame.cpp:3882 msgid "\\% Done (Esc aborts)" msgstr "" -#: ../src/3Depict.cpp:4050 +#: ../src/gui/mainFrame.cpp:3884 msgid "\\% Done" msgstr "" -#: ../src/3Depict.cpp:4299 ../src/3Depict.cpp:4306 +#: ../src/gui/mainFrame.cpp:4133 ../src/gui/mainFrame.cpp:4140 msgid "Next Fullscreen mode: none" msgstr "" -#: ../src/3Depict.cpp:4302 +#: ../src/gui/mainFrame.cpp:4136 msgid "Next Fullscreen mode: complete" msgstr "" -#: ../src/3Depict.cpp:4310 +#: ../src/gui/mainFrame.cpp:4144 msgid "Next Fullscreen mode: with toolbars" msgstr "" -#: ../src/3Depict.cpp:4326 +#: ../src/gui/mainFrame.cpp:4160 msgid "Next Mode: No fullscreen" msgstr "" -#: ../src/3Depict.cpp:4330 +#: ../src/gui/mainFrame.cpp:4164 msgid "Next Mode: fullscreen w/o toolbar" msgstr "" -#: ../src/3Depict.cpp:4334 +#: ../src/gui/mainFrame.cpp:4168 msgid "Next Mode: fullscreen with toolbar" msgstr "" -#: ../src/3Depict.cpp:4375 -msgid "Use shift-click to force full refresh" +#: ../src/gui/mainFrame.cpp:4209 +msgid "Tip: You can shift-click to force full refresh, if required" msgstr "" -#: ../src/3Depict.cpp:4637 +#: ../src/gui/mainFrame.cpp:4461 msgid "No data to save" msgstr "" -#: ../src/3Depict.cpp:4748 +#: ../src/gui/mainFrame.cpp:4572 msgid "Aborting..." msgstr "" -#: ../src/3Depict.cpp:4754 +#: ../src/gui/mainFrame.cpp:4578 msgid "" "Waiting for refresh to abort. Exiting could lead to the program " "backgrounding. Exit anyway? " msgstr "" -#: ../src/3Depict.cpp:4755 ../src/3Depict.cpp:4775 +#: ../src/gui/mainFrame.cpp:4579 ../src/gui/mainFrame.cpp:4601 msgid "Confirmation request" msgstr "" -#: ../src/3Depict.cpp:4774 +#: ../src/gui/mainFrame.cpp:4600 msgid "Are you sure you wish to exit 3Depict?" msgstr "" -#: ../src/3Depict.cpp:5038 +#: ../src/gui/mainFrame.cpp:4974 msgid "Update Notice: New version " msgstr "" -#: ../src/3Depict.cpp:5038 +#: ../src/gui/mainFrame.cpp:4974 msgid " found online." msgstr "" -#: ../src/3Depict.cpp:5042 +#: ../src/gui/mainFrame.cpp:4978 msgid "Online Check: " msgstr "" -#: ../src/3Depict.cpp:5042 +#: ../src/gui/mainFrame.cpp:4978 msgid " is up-to-date." msgstr "" -#: ../src/3Depict.cpp:5134 +#: ../src/gui/mainFrame.cpp:5068 msgid "An auto-save state was found, would you like to restore it?." msgstr "" -#: ../src/3Depict.cpp:5135 +#: ../src/gui/mainFrame.cpp:5069 msgid "Autosave" msgstr "" -#: ../src/3Depict.cpp:5142 +#: ../src/gui/mainFrame.cpp:5076 msgid "Unable to load autosave file.." msgstr "" -#: ../src/3Depict.cpp:5320 +#: ../src/gui/mainFrame.cpp:5261 msgid "List of available filters" msgstr "" -#: ../src/3Depict.cpp:5321 +#: ../src/gui/mainFrame.cpp:5262 msgid "Tree of data filters" msgstr "" -#: ../src/3Depict.cpp:5322 +#: ../src/gui/mainFrame.cpp:5263 msgid "" "Enable/Disable automatic updates of data when filter change takes effect" msgstr "" -#: ../src/3Depict.cpp:5325 +#: ../src/gui/mainFrame.cpp:5266 msgid "" -"Enable/Disable \"Alpha blending\" (transparency) in rendering system. This " -"is used to smooth objects (avoids artefacts known as \"jaggies\") and to " -"make transparent surfaces. Disabling will provide faster rendering but look " -"more blocky" +"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 "" -#: ../src/3Depict.cpp:5326 +#: ../src/gui/mainFrame.cpp:5267 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/3Depict.cpp:5327 +#: ../src/gui/mainFrame.cpp:5268 msgid "" "Enable/Disable weak randomisation (Galois linear feedback shift register). " "Strong randomisation uses a much slower random selection method, but " @@ -2039,2376 +1936,2634 @@ "recommended for final analyses" msgstr "" -#: ../src/3Depict.cpp:5328 +#: ../src/gui/mainFrame.cpp:5269 msgid "" -"Enable/Disable caching of intermediate results during filter updates. This " -"will use less system RAM, though changes to any filter property will cause " -"the entire filter tree to be recomputed, greatly slowing computations" +"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 "" -#: ../src/3Depict.cpp:5339 +#: ../src/gui/mainFrame.cpp:5280 msgid "Camera data information" msgstr "" -#: ../src/3Depict.cpp:5343 +#: ../src/gui/mainFrame.cpp:5284 msgid "Enable/disable visual effects on final 3D output" msgstr "" -#: ../src/3Depict.cpp:5345 +#: ../src/gui/mainFrame.cpp:5286 msgid "Enable cropping post-process effect" msgstr "" -#: ../src/3Depict.cpp:5348 +#: ../src/gui/mainFrame.cpp:5289 msgid "" "Colour based 3D effect enable/disable - requires appropriate colour filter " "3D glasses." msgstr "" -#: ../src/3Depict.cpp:5349 +#: ../src/gui/mainFrame.cpp:5290 msgid "Glasses colour mode" msgstr "" -#: ../src/3Depict.cpp:5351 +#: ../src/gui/mainFrame.cpp:5292 msgid "" "Level of separation between left and right images, which sets 3D depth to " "visual distortion tradeoff" msgstr "" -#: ../src/3Depict.cpp:5355 +#: ../src/gui/mainFrame.cpp:5296 msgid "X" msgstr "" -#: ../src/3Depict.cpp:5356 +#: ../src/gui/mainFrame.cpp:5297 msgid "Y" msgstr "" -#: ../src/3Depict.cpp:5357 +#: ../src/gui/mainFrame.cpp:5298 msgid "Save raw data to file" msgstr "" -#: ../src/3Depict.cpp:5358 +#: ../src/gui/mainFrame.cpp:5299 msgid "Copy raw data to clipboard" msgstr "" -#: ../src/3Depict.cpp:5359 +#: ../src/gui/mainFrame.cpp:5300 msgid "Manage \"stashed\" data." msgstr "" -#: ../src/3Depict.cpp:5360 +#: ../src/gui/mainFrame.cpp:5301 msgid "Program text output" msgstr "" -#: ../src/3Depict.cpp:5361 +#: ../src/gui/mainFrame.cpp:5302 msgid "Select active camera, or type to create new named camera" msgstr "" -#: ../src/3Depict.cpp:5362 +#: ../src/gui/mainFrame.cpp:5303 msgid "Remove the selected camera" msgstr "" -#: ../src/3Depict.cpp:5363 +#: ../src/gui/mainFrame.cpp:5304 msgid "Perform cropping from coordinate frame of camera" msgstr "" -#: ../src/3Depict.cpp:5364 +#: ../src/gui/mainFrame.cpp:5305 msgid "" "Set the maximum amount of RAM to use in order to speed repeat computations" msgstr "" -#: ../src/3Depict.cpp:5365 +#: ../src/gui/mainFrame.cpp:5306 msgid "Collapse the filter tree" msgstr "" -#: ../src/3Depict.cpp:5366 +#: ../src/gui/mainFrame.cpp:5307 msgid "Expand the filter tree" msgstr "" -#: ../src/3Depict.cpp:5367 +#: ../src/gui/mainFrame.cpp:5308 msgid "Process the filter tree, hold shift to purge cached filter data" msgstr "" -#: ../src/3Depict.cpp:5506 +#: ../src/gui/mainFrame.cpp:5447 msgid "Crop" msgstr "" -#: ../src/3Depict.cpp:5507 +#: ../src/gui/mainFrame.cpp:5448 msgid "Stereo" msgstr "" -#: ../src/3Depict.cpp:5518 +#: ../src/gui/mainFrame.cpp:5459 msgid "Data" msgstr "" -#: ../src/3Depict.cpp:5519 +#: ../src/gui/mainFrame.cpp:5460 msgid "Cam" msgstr "" -#: ../src/3Depict.cpp:5520 +#: ../src/gui/mainFrame.cpp:5461 msgid "Post" msgstr "" -#: ../src/3Depict.cpp:5521 +#: ../src/gui/mainFrame.cpp:5462 msgid "Tools" msgstr "" -#: ../src/3Depict.cpp:5538 ../src/filter.cpp:49 +#: ../src/gui/mainFrame.cpp:5479 ../src/backend/filter.cpp:44 msgid "Plot" msgstr "" -#: ../src/3Depict.cpp:5539 +#: ../src/gui/mainFrame.cpp:5480 msgid "Raw" msgstr "" -#: ../src/3Depict.cpp:5607 +#: ../src/gui/mathglPane.cpp:203 +msgid "No plots selected." +msgstr "" + +#: ../src/gui/mathglPane.cpp:1125 +msgid "" +"Unable to allocate requested memory.\n" +" Try a lower resolution, or save as vector (SVG)." +msgstr "" + +#: ../src/gui/mathglPane.cpp:1127 +msgid "Plotting functions returned an error:\n" +msgstr "" + +#: ../src/gui/mathglPane.cpp:1129 +msgid "File readback check failed" +msgstr "" + +#: ../src/gui/mathglPane.cpp:1131 +msgid "Filesize during readback appears to be zero." +msgstr "" + +#: ../src/3Depict.cpp:77 msgid "displays this message" msgstr "" -#: ../src/3Depict.cpp:5609 +#: ../src/3Depict.cpp:79 msgid "inputfile" msgstr "" -#: ../src/3Depict.cpp:5618 +#: ../src/3Depict.cpp:88 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:5889 +#: ../src/3Depict.cpp:374 msgid "File : " msgstr "" -#: ../src/3Depict.cpp:5889 +#: ../src/3Depict.cpp:374 msgid " does not exist. Skipping" msgstr "" -#: ../src/wxcomponents.cpp:533 -msgid "Save Data..." +#: ../src/backend/configFile.cpp:186 +msgid "Config file present, but is not valid (root node test)" msgstr "" -#: ../src/wxcomponents.cpp:534 -msgid "Text File (*.txt)|*.txt|All Files (*)|*" +#: ../src/backend/configFile.cpp:227 +msgid "Unable to interpret recent file entry" msgstr "" -#: ../src/wxcomponents.cpp:546 -msgid "Error saving file. Check output dir is writable." +#: ../src/backend/configFile.cpp:267 +msgid "Unable to determine filter type in defaults listing." msgstr "" -#: ../src/filters/transform.cpp:59 ../src/filters/transform.cpp:1225 -msgid "Translate" +#: ../src/backend/configFile.cpp:568 +msgid "Online access for non win32/apple platforms is intentionally disabled, " msgstr "" -#: ../src/filters/transform.cpp:60 ../src/filters/transform.cpp:1229 -msgid "Scale" +#: ../src/backend/configFile.cpp:569 +msgid "" +"regardless of the settings you use here. Use your package manager to keep up-" +"to-date" msgstr "" -#: ../src/filters/transform.cpp:61 ../src/filters/transform.cpp:1231 -msgid "Rotate" +#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:96 +msgid "None" msgstr "" -#: ../src/filters/transform.cpp:62 ../src/filters/transform.cpp:1233 -msgid "Value Shuffle" +#: ../src/backend/plot.cpp:31 +msgid "Moving avg." msgstr "" -#: ../src/filters/transform.cpp:63 ../src/filters/transform.cpp:1235 -msgid "Spatial Noise" +#: ../src/backend/plot.cpp:35 +msgid "Lines" msgstr "" -#: ../src/filters/transform.cpp:64 ../src/filters/transform.cpp:1227 -msgid "Translate Value" +#: ../src/backend/plot.cpp:36 +msgid "Bars" msgstr "" -#: ../src/filters/transform.cpp:68 -msgid "Specify" +#: ../src/backend/plot.cpp:37 +msgid "Steps" msgstr "" -#: ../src/filters/transform.cpp:69 -msgid "Boundbox Centre" +#: ../src/backend/plot.cpp:38 +msgid "Stem" msgstr "" -#: ../src/filters/transform.cpp:70 -msgid "Mass Centre" +#: ../src/backend/plot.cpp:39 +msgid "Points" msgstr "" -#: ../src/filters/transform.cpp:892 ../src/filters/spatialAnalysis.cpp:286 -#: ../src/filters/spatialAnalysis.cpp:598 -#: ../src/filters/spatialAnalysis.cpp:986 -#: ../src/filters/clusterAnalysis.cpp:1813 -msgid "Collate" +#: ../src/backend/plot.cpp:619 ../src/backend/plot.cpp:627 +msgid "Multiple data types" msgstr "" -#: ../src/filters/transform.cpp:911 -msgid "Mass-to-Charge (amu/e)" +#: ../src/backend/plot.cpp:783 +msgid "Mixed log/non-log:" msgstr "" -#: ../src/filters/transform.cpp:965 -msgid "Shuffle" +#: ../src/backend/plot.cpp:1227 +msgid "error" msgstr "" -#: ../src/filters/transform.cpp:981 -msgid "Splice" +#: ../src/backend/filtertree.cpp:952 +msgid "WARNING: Skipping node " msgstr "" -#: ../src/filters/transform.cpp:1036 -msgid "Algorithm to use to transform point data" +#: ../src/backend/filtertree.cpp:952 +msgid " as it was not recognised" msgstr "" -#: ../src/filters/transform.cpp:1051 -msgid "Origin mode" +#: ../src/backend/filtertree.cpp:990 +msgid "Error processing node: " msgstr "" -#: ../src/filters/transform.cpp:1054 -msgid "Select how transform origin is computed" +#: ../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/filters/transform.cpp:1059 -msgid "Show marker" +#: ../src/backend/viscontrol.cpp:1089 +msgid "Failed to allocate parser" msgstr "" -#: ../src/filters/transform.cpp:1063 -msgid "Display an interactive object to set transform origin" +#: ../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/filters/transform.cpp:1065 -msgid "Display a small marker to denote transform origin" +#: ../src/backend/viscontrol.cpp:1132 +msgid "Base state node missing. Is this really a state XML file??" msgstr "" -#: ../src/filters/transform.cpp:1081 -msgid "Translation" +#: ../src/backend/viscontrol.cpp:1161 +msgid "State was created by a newer version of this program.. " msgstr "" -#: ../src/filters/transform.cpp:1084 -msgid "Translation vector for transform" +#: ../src/backend/viscontrol.cpp:1162 +msgid "file reading will continue, but may fail." msgstr "" -#: ../src/filters/transform.cpp:1096 -msgid "Offset" +#: ../src/backend/viscontrol.cpp:1167 +msgid "" +"Warning, unparseable version number in state file. File reading will " +"continue, but may fail" msgstr "" -#: ../src/filters/transform.cpp:1100 -msgid "Scalar to use to offset each point's associated value" +#: ../src/backend/viscontrol.cpp:1174 +msgid "Unable to find the \"writer\" node" msgstr "" -#: ../src/filters/transform.cpp:1117 -msgid "Origin of scale trasnform" +#: ../src/backend/viscontrol.cpp:1184 +msgid "Unable to find the \"backcolour\" node." msgstr "" -#: ../src/filters/transform.cpp:1124 -msgid "Scale Fact." +#: ../src/backend/viscontrol.cpp:1191 +msgid "\"backcolour\" node missing \"r\" value." msgstr "" -#: ../src/filters/transform.cpp:1127 -msgid "Enlargement factor for scaling around origin" +#: ../src/backend/viscontrol.cpp:1196 +msgid "Unable to interpret \"backColour\" node's \"r\" value." msgstr "" -#: ../src/filters/transform.cpp:1143 -msgid "Origin of rotation" +#: ../src/backend/viscontrol.cpp:1204 +msgid "\"backcolour\" node missing \"g\" value." msgstr "" -#: ../src/filters/transform.cpp:1148 ../src/filters/ionClip.cpp:748 -#: ../src/filters/compositionProfile.cpp:920 -msgid "Axis" +#: ../src/backend/viscontrol.cpp:1210 +msgid "Unable to interpret \"backColour\" node's \"g\" value." msgstr "" -#: ../src/filters/transform.cpp:1151 -msgid "Axis around which to revolve" +#: ../src/backend/viscontrol.cpp:1218 +msgid "\"backcolour\" node missing \"b\" value." msgstr "" -#: ../src/filters/transform.cpp:1156 -msgid "Angle (deg)" +#: ../src/backend/viscontrol.cpp:1224 +msgid "Unable to interpret \"backColour\" node's \"b\" value." msgstr "" -#: ../src/filters/transform.cpp:1159 -msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)" +#: ../src/backend/viscontrol.cpp:1231 +msgid "\"backcolour\"s rgb values must be in range [0,1]" msgstr "" -#: ../src/filters/transform.cpp:1176 -msgid "Noise Type" +#: ../src/backend/viscontrol.cpp:1258 +msgid "Unable to find or interpret \"showaxis\" node" msgstr "" -#: ../src/filters/transform.cpp:1179 -msgid "Method to use to degrade point data" +#: ../src/backend/viscontrol.cpp:1267 +msgid "Unable to locate \"filtertree\" node." msgstr "" -#: ../src/filters/transform.cpp:1186 -msgid "Noise level" +#: ../src/backend/viscontrol.cpp:1283 +msgid "Cameras section missing \"active\" node." msgstr "" -#: ../src/filters/transform.cpp:1188 -msgid "Standard dev." +#: ../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/filters/transform.cpp:1196 -msgid "Amplitude of noise" +#: ../src/backend/viscontrol.cpp:1374 +msgid "For stash " msgstr "" -#: ../src/filters/transform.cpp:1208 -msgid "Transform Params" +#: ../src/backend/viscontrol.cpp:1402 +msgid "Unrecognised effect :" msgstr "" -#: ../src/filters/transform.cpp:1391 ../src/filters/ionInfo.cpp:651 -#: ../src/filters/ionColour.cpp:409 -msgid "Aborted" +#: ../src/backend/viscontrol.cpp:1412 +msgid "Duplicate effect found" msgstr "" -#: ../src/filters/transform.cpp:1394 -msgid "Unable to allocate memory" +#: ../src/backend/viscontrol.cpp:1412 +msgid " cannot use." msgstr "" -#: ../src/filters/transform.cpp:1638 -msgid "White" +#: ../src/backend/viscontrol.cpp:1422 +msgid "Error reading effect : " msgstr "" -#: ../src/filters/transform.cpp:1640 -msgid "Gaussian" +#: ../src/backend/viscontrol.cpp:1483 +msgid "-merge" msgstr "" -#: ../src/filters/spectrumPlot.cpp:109 -msgid "Extrema" +#: ../src/backend/viscontrol.cpp:1488 +msgid "" +" Unable to merge stashes correctly. This is improbable, so please report " +"this." msgstr "" -#: ../src/filters/spectrumPlot.cpp:158 -msgid "count" +#: ../src/backend/filters/externalProgram.cpp:513 +msgid "Command" msgstr "" -#: ../src/filters/spectrumPlot.cpp:243 -msgid "Mixed data" +#: ../src/backend/filters/externalProgram.cpp:516 +msgid "" +"Full command to send to operating system. See manual for escape sequence " +"meanings" msgstr "" -#: ../src/filters/spectrumPlot.cpp:379 -#: ../src/filters/compositionProfile.cpp:969 -msgid "Bin width" +#: ../src/backend/filters/externalProgram.cpp:520 +msgid "Work Dir" msgstr "" -#: ../src/filters/spectrumPlot.cpp:383 -msgid "Step size for spectrum" +#: ../src/backend/filters/externalProgram.cpp:523 +msgid "Directory to run the command in" msgstr "" -#: ../src/filters/spectrumPlot.cpp:392 -msgid "Auto Min/max" +#: ../src/backend/filters/externalProgram.cpp:533 +msgid "Cleanup input" msgstr "" -#: ../src/filters/spectrumPlot.cpp:396 -msgid "Automatically compute spectrum upper and lower bound" +#: ../src/backend/filters/externalProgram.cpp:536 +msgid "Erase input files when command completed" msgstr "" -#: ../src/filters/spectrumPlot.cpp:401 -msgid "Min" +#: ../src/backend/filters/externalProgram.cpp:545 +msgid "Cache" msgstr "" -#: ../src/filters/spectrumPlot.cpp:404 -msgid "Starting position for spectrum" +#: ../src/backend/filters/externalProgram.cpp:548 +msgid "" +"Assume program does not alter its output, unless inputs from 3Depict are " +"altered" msgstr "" -#: ../src/filters/spectrumPlot.cpp:409 -msgid "Max" +#: ../src/backend/filters/externalProgram.cpp:630 +msgid "Error processing command line" msgstr "" -#: ../src/filters/spectrumPlot.cpp:412 -msgid "Ending position for spectrum" +#: ../src/backend/filters/externalProgram.cpp:632 +msgid "Unable to set working directory" msgstr "" -#: ../src/filters/spectrumPlot.cpp:420 -msgid "Logarithmic" +#: ../src/backend/filters/externalProgram.cpp:634 +msgid "Error saving posfile result for external program" msgstr "" -#: ../src/filters/spectrumPlot.cpp:423 -msgid "Convert the plot to logarithmic mode" +#: ../src/backend/filters/externalProgram.cpp:636 +msgid "Error saving plot result for externalprogram" msgstr "" -#: ../src/filters/spectrumPlot.cpp:442 -#: ../src/filters/compositionProfile.cpp:1005 -msgid "Plot Type" +#: ../src/backend/filters/externalProgram.cpp:638 +msgid "Error creating temporary directory" msgstr "" -#: ../src/filters/spectrumPlot.cpp:445 -msgid "Visual style of plot" +#: ../src/backend/filters/externalProgram.cpp:640 +msgid "Detected unusable number of columns in plot" msgstr "" -#: ../src/filters/spectrumPlot.cpp:455 -#: ../src/filters/compositionProfile.cpp:1018 -#: ../src/filters/annotation.cpp:864 ../src/filters/voxelise.cpp:832 -msgid "Colour" +#: ../src/backend/filters/externalProgram.cpp:642 +msgid "Unable to parse plot result from external program" msgstr "" -#: ../src/filters/spectrumPlot.cpp:458 -msgid "Colour of plotted spectrum" +#: ../src/backend/filters/externalProgram.cpp:644 +msgid "Unable to load ions from external program" msgstr "" -#: ../src/filters/spectrumPlot.cpp:692 -msgid "Insufficient memory for spectrum filter." +#: ../src/backend/filters/externalProgram.cpp:646 +msgid "Unable to perform commandline substitution" msgstr "" -#: ../src/filters/spectrumPlot.cpp:694 -msgid "Bad bincount value in spectrum filter." +#: ../src/backend/filters/externalProgram.cpp:648 +msgid "Error executing external program" msgstr "" -#: ../src/filters/ionClip.cpp:49 +#: ../src/backend/filters/ionClip.cpp:59 +#: ../src/backend/filters/compositionProfile.cpp:43 msgid "Sphere" msgstr "" -#: ../src/filters/ionClip.cpp:50 +#: ../src/backend/filters/ionClip.cpp:60 msgid "Plane" msgstr "" -#: ../src/filters/ionClip.cpp:51 ../src/filters/compositionProfile.cpp:24 +#: ../src/backend/filters/ionClip.cpp:61 +#: ../src/backend/filters/compositionProfile.cpp:42 msgid "Cylinder" msgstr "" -#: ../src/filters/ionClip.cpp:52 +#: ../src/backend/filters/ionClip.cpp:62 msgid "Aligned box" msgstr "" -#: ../src/filters/ionClip.cpp:665 +#: ../src/backend/filters/ionClip.cpp:492 msgid "Primitive" msgstr "" -#: ../src/filters/ionClip.cpp:668 +#: ../src/backend/filters/ionClip.cpp:495 msgid "Shape of clipping object" msgstr "" -#: ../src/filters/ionClip.cpp:674 ../src/filters/compositionProfile.cpp:897 +#: ../src/backend/filters/ionClip.cpp:501 +#: ../src/backend/filters/compositionProfile.cpp:916 msgid "Show Primitive" msgstr "" -#: ../src/filters/ionClip.cpp:677 +#: ../src/backend/filters/ionClip.cpp:504 msgid "Display the 3D interaction object" msgstr "" -#: ../src/filters/ionClip.cpp:682 +#: ../src/backend/filters/ionClip.cpp:509 msgid "Invert Clip" msgstr "" -#: ../src/filters/ionClip.cpp:685 +#: ../src/backend/filters/ionClip.cpp:512 msgid "" "Switch between retaining points inside (false) and outside (true) of " "primitive" msgstr "" -#: ../src/filters/ionClip.cpp:699 +#: ../src/backend/filters/ionClip.cpp:526 +#: ../src/backend/filters/compositionProfile.cpp:975 msgid "Position for centre of sphere" msgstr "" -#: ../src/filters/ionClip.cpp:704 ../src/filters/ionClip.cpp:767 -#: ../src/filters/compositionProfile.cpp:939 +#: ../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/spatialAnalysis.cpp:610 msgid "Radius" msgstr "" -#: ../src/filters/ionClip.cpp:707 +#: ../src/backend/filters/ionClip.cpp:534 +#: ../src/backend/filters/compositionProfile.cpp:983 msgid "Radius of sphere" msgstr "" -#: ../src/filters/ionClip.cpp:721 +#: ../src/backend/filters/ionClip.cpp:548 msgid "Position that plane passes through" msgstr "" -#: ../src/filters/ionClip.cpp:726 +#: ../src/backend/filters/ionClip.cpp:553 msgid "Plane Normal" msgstr "" -#: ../src/filters/ionClip.cpp:729 +#: ../src/backend/filters/ionClip.cpp:556 msgid "Perpendicular direction for plane" msgstr "" -#: ../src/filters/ionClip.cpp:743 +#: ../src/backend/filters/ionClip.cpp:570 msgid "Centre of cylinder" msgstr "" -#: ../src/filters/ionClip.cpp:751 +#: ../src/backend/filters/ionClip.cpp:575 +#: ../src/backend/filters/compositionProfile.cpp:939 +#: ../src/backend/filters/spatialAnalysis.cpp:601 +#: ../src/backend/filters/transform.cpp:1323 +msgid "Axis" +msgstr "" + +#: ../src/backend/filters/ionClip.cpp:578 msgid "Positive vector for cylinder" msgstr "" -#: ../src/filters/ionClip.cpp:759 ../src/filters/compositionProfile.cpp:931 +#: ../src/backend/filters/ionClip.cpp:586 +#: ../src/backend/filters/compositionProfile.cpp:950 msgid "Lock Axis Mag." msgstr "" -#: ../src/filters/ionClip.cpp:762 +#: ../src/backend/filters/ionClip.cpp:589 msgid "Prevent changing length of cylinder during 3D interaction" msgstr "" -#: ../src/filters/ionClip.cpp:770 ../src/filters/compositionProfile.cpp:942 +#: ../src/backend/filters/ionClip.cpp:597 +#: ../src/backend/filters/compositionProfile.cpp:961 +#: ../src/backend/filters/spatialAnalysis.cpp:613 msgid "Radius of cylinder" msgstr "" -#: ../src/filters/ionClip.cpp:783 +#: ../src/backend/filters/ionClip.cpp:610 msgid "Centre of axis aligned box" msgstr "" -#: ../src/filters/ionClip.cpp:788 +#: ../src/backend/filters/ionClip.cpp:615 msgid "Corner offset" msgstr "" -#: ../src/filters/ionClip.cpp:791 +#: ../src/backend/filters/ionClip.cpp:618 msgid "Vector to corner of box" msgstr "" -#: ../src/filters/boundingBox.cpp:39 -msgid "Box only" +#: ../src/backend/filters/clusterAnalysis.cpp:74 +#: ../src/backend/filters/clusterAnalysis.cpp:998 +msgid "Size Distribution" msgstr "" -#: ../src/filters/boundingBox.cpp:40 -msgid "Tick" +#: ../src/backend/filters/clusterAnalysis.cpp:75 +msgid "Chemistry Distribution" msgstr "" -#: ../src/filters/boundingBox.cpp:41 -msgid "Dimension" +#: ../src/backend/filters/clusterAnalysis.cpp:487 +msgid "No range data. Can't cluster." msgstr "" -#: ../src/filters/boundingBox.cpp:512 -msgid "If true, show box, otherwise hide box" +#: ../src/backend/filters/clusterAnalysis.cpp:498 +msgid "" +"No ranges selected for cluster \"core\". Cannot continue with clustering." msgstr "" -#: ../src/filters/boundingBox.cpp:525 -msgid "Style" +#: ../src/backend/filters/clusterAnalysis.cpp:510 +msgid "" +"No ranges selected for cluster \"bulk\". Cannot continue with clustering." msgstr "" -#: ../src/filters/boundingBox.cpp:528 -msgid "Box display mode" +#: ../src/backend/filters/clusterAnalysis.cpp:684 +msgid "Morphology Plot" msgstr "" -#: ../src/filters/boundingBox.cpp:539 -msgid "Fixed Tick Num" +#: ../src/backend/filters/clusterAnalysis.cpp:685 +msgid "\\lambda_1:\\lambda_2 ratio" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:686 +msgid "\\lambda_2:\\lambda_3 ratio" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:723 +msgid "No clusters had sufficient dimensionality to compute singular values" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:780 +msgid "Found :" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:782 +msgid " clusters" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:850 +msgid "Compositions (fractional, core+bulk)" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:852 +msgid "Compositions (fractional, core only)" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:870 +msgid "Frequencies (core+bulk)" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:898 +msgid "Core Link + Erode" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:902 +#: ../src/backend/filters/spatialAnalysis.cpp:360 +#: ../src/backend/filters/ionInfo.cpp:447 +msgid "Algorithm" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:906 +msgid "Cluster algorithm mode" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:915 +msgid "Core Classify Dist" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:918 +msgid "Restrict only atoms by distance to be cluster sources" msgstr "" -#: ../src/filters/boundingBox.cpp:543 +#: ../src/backend/filters/clusterAnalysis.cpp:923 +msgid "Classify Knn Max" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:926 msgid "" -"If true, evenly use specified number of ticks. Otherwise, use distance to " -"determine tick count" +"Require that the kth NN (this number) is within the classify distance, to be " +"a cluster source" msgstr "" -#: ../src/filters/boundingBox.cpp:551 -msgid "Num X" +#: ../src/backend/filters/clusterAnalysis.cpp:931 +msgid "Core Link Dist" msgstr "" -#: ../src/filters/boundingBox.cpp:554 -msgid "Tick count in X direction" +#: ../src/backend/filters/clusterAnalysis.cpp:934 +msgid "Distance between clusters to allow linking" msgstr "" -#: ../src/filters/boundingBox.cpp:559 -msgid "Num Y" +#: ../src/backend/filters/clusterAnalysis.cpp:939 +msgid "Bulk Link (Envelope) Dist" msgstr "" -#: ../src/filters/boundingBox.cpp:562 -msgid "Tick count in Y direction" +#: ../src/backend/filters/clusterAnalysis.cpp:942 +msgid "" +"Distance from core points that form cluster that is used to grab surrounding " +"bulk points" msgstr "" -#: ../src/filters/boundingBox.cpp:567 -msgid "Num Z" +#: ../src/backend/filters/clusterAnalysis.cpp:947 +msgid "Erode Dist" msgstr "" -#: ../src/filters/boundingBox.cpp:570 -msgid "Tick count in Z direction" +#: ../src/backend/filters/clusterAnalysis.cpp:950 +msgid "" +"Distance from unclustered material in which bulk points are eroded from " +"cluster" msgstr "" -#: ../src/filters/boundingBox.cpp:576 -msgid "Spacing X" +#: ../src/backend/filters/clusterAnalysis.cpp:955 +msgid "Clustering Params" msgstr "" -#: ../src/filters/boundingBox.cpp:580 -msgid "Distance between ticks on X axis" +#: ../src/backend/filters/clusterAnalysis.cpp:962 +msgid "Count bulk" msgstr "" -#: ../src/filters/boundingBox.cpp:584 -msgid "Spacing Y" +#: ../src/backend/filters/clusterAnalysis.cpp:965 +msgid "Include bulk ions in size distribution." msgstr "" -#: ../src/filters/boundingBox.cpp:588 -msgid "Distance between ticks on Y axis" +#: ../src/backend/filters/clusterAnalysis.cpp:971 +msgid "Size Cropping" msgstr "" -#: ../src/filters/boundingBox.cpp:592 -msgid "Spacing Z" +#: ../src/backend/filters/clusterAnalysis.cpp:974 +msgid "Perform removal of clusters based upon size distribution" msgstr "" -#: ../src/filters/boundingBox.cpp:596 -msgid "Distance between ticks on Z axis" +#: ../src/backend/filters/clusterAnalysis.cpp:981 +msgid "Min Size" msgstr "" -#: ../src/filters/boundingBox.cpp:599 -msgid "Tick marks" +#: ../src/backend/filters/clusterAnalysis.cpp:984 +msgid "Remove clusters below this size" msgstr "" -#: ../src/filters/boundingBox.cpp:609 -msgid "Box Colour" +#: ../src/backend/filters/clusterAnalysis.cpp:989 +msgid "Max Size" msgstr "" -#: ../src/filters/boundingBox.cpp:613 -msgid "Colour of the bounding box" +#: ../src/backend/filters/clusterAnalysis.cpp:992 +msgid "Remove clusters above this size" msgstr "" -#: ../src/filters/boundingBox.cpp:618 -msgid "Line thickness" +#: ../src/backend/filters/clusterAnalysis.cpp:1001 +msgid "Show number of clusters as a function of cluster size" msgstr "" -#: ../src/filters/boundingBox.cpp:622 -msgid "Thickness of the lines used to draw the box" +#: ../src/backend/filters/clusterAnalysis.cpp:1007 +msgid "Log Scale" msgstr "" -#: ../src/filters/boundingBox.cpp:630 ../src/filters/annotation.cpp:815 -msgid "Font Size" +#: ../src/backend/filters/clusterAnalysis.cpp:1010 +msgid "Use logarithmic scale for size distribution" msgstr "" -#: ../src/filters/boundingBox.cpp:633 -msgid "Relative size for text" +#: ../src/backend/filters/clusterAnalysis.cpp:1026 +msgid "Chemistry Dist." msgstr "" -#: ../src/filters/boundingBox.cpp:636 ../src/filters/dataLoad.cpp:552 -#: ../src/filters/compositionProfile.cpp:1027 ../src/filters/voxelise.cpp:794 -msgid "Appearance" +#: ../src/backend/filters/clusterAnalysis.cpp:1029 +msgid "Create a plot showing chemistry for each cluster size" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:47 -msgid "Local Density" +#: ../src/backend/filters/clusterAnalysis.cpp:1036 +#: ../src/backend/filters/compositionProfile.cpp:1023 +#: ../src/backend/filters/ionInfo.cpp:419 +msgid "Normalise" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:48 -msgid "Density Filtering" +#: ../src/backend/filters/clusterAnalysis.cpp:1039 +msgid "Convert cluster counts to composition" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:49 -msgid "Radial Distribution" +#: ../src/backend/filters/clusterAnalysis.cpp:1045 +msgid "Postprocess" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:53 -msgid "Fixed Neighbour Count" +#: ../src/backend/filters/clusterAnalysis.cpp:1064 +msgid "If selected, use as \"core\" ion type (can make clusters)" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:54 -msgid "Fixed Radius" +#: ../src/backend/filters/clusterAnalysis.cpp:1069 +msgid "Core Ranges" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:316 -#: ../src/filters/spatialAnalysis.cpp:704 -#: ../src/filters/spatialAnalysis.cpp:763 -#: ../src/filters/spatialAnalysis.cpp:1016 -msgid "Build" +#: ../src/backend/filters/clusterAnalysis.cpp:1081 +msgid "" +"If selected, use as \"bulk\" ion type (can be included in existing clusters)" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:343 -#: ../src/filters/spatialAnalysis.cpp:794 -#: ../src/filters/spatialAnalysis.cpp:1043 -msgid "Analyse" +#: ../src/backend/filters/clusterAnalysis.cpp:1086 +msgid "Bulk Ranges" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:539 -#: ../src/filters/spatialAnalysis.cpp:1249 -msgid "Number Density (\\#/Vol^3)" +#: ../src/backend/filters/clusterAnalysis.cpp:1101 +msgid "Max. Sep + Erode" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:566 -#: ../src/filters/spatialAnalysis.cpp:1274 -msgid "Warning," +#: ../src/backend/filters/clusterAnalysis.cpp:1730 +msgid "Clustering aborted" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:567 -#: ../src/filters/spatialAnalysis.cpp:1275 -msgid " points were un-analysable. These have been dropped" +#: ../src/backend/filters/clusterAnalysis.cpp:1732 +msgid "No core ions for cluster" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:589 -#: ../src/filters/spatialAnalysis.cpp:1297 -msgid "And so on..." +#: ../src/backend/filters/clusterAnalysis.cpp:1734 +msgid "No bulk ions for cluster" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:716 -#: ../src/filters/spatialAnalysis.cpp:775 -msgid "Surface" +#: ../src/backend/filters/clusterAnalysis.cpp:1812 +msgid " --------------------------- Parameter selection notice ------------- " msgstr "" -#: ../src/filters/spatialAnalysis.cpp:851 -#: ../src/filters/spatialAnalysis.cpp:923 -msgid "Radial Distance" +#: ../src/backend/filters/clusterAnalysis.cpp:1813 +msgid "You have specified a bulk distance larger than half your link distance." msgstr "" -#: ../src/filters/spatialAnalysis.cpp:855 -msgid "NN Freq." +#: ../src/backend/filters/clusterAnalysis.cpp:1814 +msgid "" +"You can do this; thats OK, but the output is no longer independent of the " +"computational process;" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:914 -msgid "Warning, " +#: ../src/backend/filters/clusterAnalysis.cpp:1815 +msgid "" +"This will be a problem in the case where two or more clusters can equally " +"lay claim to a \"bulk\" ion. " msgstr "" -#: ../src/filters/spatialAnalysis.cpp:915 +#: ../src/backend/filters/clusterAnalysis.cpp:1816 msgid "" -" points were unable to find neighbour points that exceeded the search " -"radius, and thus terminated prematurely" +" If your inter-cluster distance is sufficiently large (larger than your bulk " +"linking distance), then you can get away with this." msgstr "" -#: ../src/filters/spatialAnalysis.cpp:925 -msgid " RDF" +#: ../src/backend/filters/clusterAnalysis.cpp:1817 +msgid "" +" In theory it is possible to \"join\" the clusters, but this has not been " +"implemented for speed reasons." msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1322 ../src/filters/ionInfo.cpp:550 -#: ../src/filters/clusterAnalysis.cpp:885 -msgid "Algorithm" +#: ../src/backend/filters/clusterAnalysis.cpp:1818 +msgid "" +"If you want this, please contact the author, or just use the source to add " +"this in yourself." msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1325 -msgid "Spatial analysis algorithm to use" +#: ../src/backend/filters/clusterAnalysis.cpp:1819 +msgid "---------------------------------------------------------------------- " msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1346 -msgid "Stop Mode" +#: ../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 +msgid "Collate" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1349 -msgid "Method to use to terminate algorithm when examining each point" +#: ../src/backend/filters/clusterAnalysis.cpp:1848 +msgid "Build Core" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1356 -msgid "NN Max" +#: ../src/backend/filters/clusterAnalysis.cpp:1866 +msgid "Classify Core" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1359 -msgid "Maximum number of neighbours to examine" +#: ../src/backend/filters/clusterAnalysis.cpp:1959 +msgid "Build Bulk" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1365 -msgid "Dist Max" +#: ../src/backend/filters/clusterAnalysis.cpp:1979 +msgid "Core" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1368 -msgid "Maximum distance from each point for search" +#: ../src/backend/filters/clusterAnalysis.cpp:2124 +msgid "Bulk" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1382 -#: ../src/filters/compositionProfile.cpp:959 -msgid "Num Bins" +#: ../src/backend/filters/clusterAnalysis.cpp:2254 +msgid "Erode" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1385 -msgid "Number of bins for output 1D RDF plot" +#: ../src/backend/filters/clusterAnalysis.cpp:2328 +msgid "Re-Collate" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1394 -msgid "Surface Remove" +#: ../src/backend/filters/clusterAnalysis.cpp:2596 +#: ../src/backend/filters/clusterAnalysis.cpp:2823 +msgid "Cluster Size" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1397 -msgid "" -"Exclude surface as part of source to minimise bias in RDF (at cost of " -"increased noise)" +#: ../src/backend/filters/clusterAnalysis.cpp:2597 +#: ../src/backend/filters/clusterAnalysis.cpp:2827 +msgid "Frequency" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1404 -msgid "Remove Dist" +#: ../src/backend/filters/clusterAnalysis.cpp:2825 +msgid "Composition" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1407 -msgid "Minimum distance to remove from surface" +#: ../src/backend/filters/voxelise.cpp:84 +msgid "None (Raw count)" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1418 -msgid "Plot colour " +#: ../src/backend/filters/voxelise.cpp:85 +msgid "Volume (Density)" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1421 -msgid "Colour of output plot" +#: ../src/backend/filters/voxelise.cpp:86 +msgid "All Ions (conc)" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:87 +msgid "Ratio (Num/Denom)" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:91 +msgid "Point Cloud" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:92 +msgid "Isosurface" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:97 +msgid "Gaussian (2𝜎)" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:101 +msgid "Zero" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1440 -msgid "Source" +#: ../src/backend/filters/voxelise.cpp:102 +msgid "Bounce" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1443 -msgid "Ions to use for initiating RDF search" +#: ../src/backend/filters/voxelise.cpp:543 +msgid "Voxel Limits (min,max): (" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1459 -msgid "Enable/disable ion as source" +#: ../src/backend/filters/voxelise.cpp:592 +msgid "Fixed width" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1476 -msgid "Enable/disable all ions as target" +#: ../src/backend/filters/voxelise.cpp:596 +msgid "If true, use fixed size voxels, otherwise use fixed count" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1491 -msgid "Enable/disable this ion as target" +#: ../src/backend/filters/voxelise.cpp:602 +msgid "Bin width x" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1504 -msgid "Cutoff" +#: ../src/backend/filters/voxelise.cpp:606 +msgid "Voxel size in X direction" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1507 -msgid "Remove points with local density above/below this value" +#: ../src/backend/filters/voxelise.cpp:610 +msgid "Bin width y" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1517 -msgid "Retain Upper" +#: ../src/backend/filters/voxelise.cpp:613 +msgid "Voxel size in Y direction" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1520 -msgid "Retain either points with density above (enabled) or below cutoff" +#: ../src/backend/filters/voxelise.cpp:619 +msgid "Bin width z" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1531 -msgid "Alg. Params." +#: ../src/backend/filters/voxelise.cpp:622 +msgid "Voxel size in Z direction" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1882 -msgid "Spatial analysis aborted by user" +#: ../src/backend/filters/voxelise.cpp:629 +msgid "Num bins x" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1884 -msgid "Insufficient data to complete analysis." +#: ../src/backend/filters/voxelise.cpp:633 +msgid "Number of voxels to use in X direction" msgstr "" -#: ../src/filters/dataLoad.cpp:32 -msgid "POS Data" +#: ../src/backend/filters/voxelise.cpp:638 +msgid "Num bins y" msgstr "" -#: ../src/filters/dataLoad.cpp:33 -msgid "Text Data" +#: ../src/backend/filters/voxelise.cpp:641 +msgid "Number of voxels to use in Y direction" msgstr "" -#: ../src/filters/dataLoad.cpp:212 -msgid " does not exist" +#: ../src/backend/filters/voxelise.cpp:647 +msgid "Num bins z" msgstr "" -#: ../src/filters/dataLoad.cpp:249 ../src/filters/dataLoad.cpp:260 -#: ../src/filters/dataLoad.cpp:280 ../src/filters/dataLoad.cpp:292 -msgid "Error loading file: " +#: ../src/backend/filters/voxelise.cpp:649 +msgid "Number of voxels to use in Z direction" msgstr "" -#: ../src/filters/dataLoad.cpp:306 -msgid "Data file contained incorrect number of columns -- should be 4, was " +#: ../src/backend/filters/voxelise.cpp:670 +msgid "Normalise by" msgstr "" -#: ../src/filters/dataLoad.cpp:359 -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" +#: ../src/backend/filters/voxelise.cpp:673 +msgid "Method to use to normalise scalar value in each voxel" msgstr "" -#: ../src/filters/dataLoad.cpp:366 -msgid "Loaded " +#: ../src/backend/filters/voxelise.cpp:676 +msgid "Computation" msgstr "" -#: ../src/filters/dataLoad.cpp:366 -msgid " Points" +#: ../src/backend/filters/voxelise.cpp:683 +msgid "Numerator" msgstr "" -#: ../src/filters/dataLoad.cpp:394 ../src/filters/rangeFile.cpp:489 -msgid "File" +#: ../src/backend/filters/voxelise.cpp:686 +msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value" msgstr "" -#: ../src/filters/dataLoad.cpp:395 -msgid "File from which to load data" +#: ../src/backend/filters/voxelise.cpp:706 +msgid "Enable this ion for numerator" msgstr "" -#: ../src/filters/dataLoad.cpp:406 -msgid "File type" +#: ../src/backend/filters/voxelise.cpp:717 +msgid "Denominator" msgstr "" -#: ../src/filters/dataLoad.cpp:408 -msgid "Type of file to be loaded" +#: ../src/backend/filters/voxelise.cpp:720 +msgid "Parameter \"b\" used in fraction (a/b) to get voxel value" msgstr "" -#: ../src/filters/dataLoad.cpp:422 -msgid "Entries per point" +#: ../src/backend/filters/voxelise.cpp:736 +msgid "Enable this ion for denominator contribution" msgstr "" -#: ../src/filters/dataLoad.cpp:423 -msgid "Number of decimal values in file per 3D point (normally 4)" +#: ../src/backend/filters/voxelise.cpp:757 +#: ../src/backend/filters/voxelise.cpp:792 +msgid "Filtering" msgstr "" -#: ../src/filters/dataLoad.cpp:451 -msgid "Relative offset of each entry in file for point's X position" +#: ../src/backend/filters/voxelise.cpp:761 +msgid "Smoothing method to use on voxels" msgstr "" -#: ../src/filters/dataLoad.cpp:459 -msgid "Relative offset of each entry in file for point's Y position" +#: ../src/backend/filters/voxelise.cpp:764 +msgid "Processing" msgstr "" -#: ../src/filters/dataLoad.cpp:467 -msgid "Relative offset of each entry in file for point's Z position" +#: ../src/backend/filters/voxelise.cpp:770 +msgid "Kernel Bins" msgstr "" -#: ../src/filters/dataLoad.cpp:475 -msgid "" -"Relative offset of each entry in file to use for scalar value of 3D point" +#: ../src/backend/filters/voxelise.cpp:774 +msgid "Number of bins in convolution kernel" msgstr "" -#: ../src/filters/dataLoad.cpp:478 -msgid "Value Label" +#: ../src/backend/filters/voxelise.cpp:785 +msgid "Exterior values" msgstr "" -#: ../src/filters/dataLoad.cpp:482 -msgid "Name for the scalar value associated with each point" +#: ../src/backend/filters/voxelise.cpp:788 +msgid "Method to use to treat boundaries of voxel data for convolution" msgstr "" -#: ../src/filters/dataLoad.cpp:485 -msgid "Format params." +#: ../src/backend/filters/voxelise.cpp:806 +msgid "Representation" msgstr "" -#: ../src/filters/dataLoad.cpp:491 -msgid "Enabled" +#: ../src/backend/filters/voxelise.cpp:809 +msgid "3D display method" msgstr "" -#: ../src/filters/dataLoad.cpp:495 -msgid "Load this file?" +#: ../src/backend/filters/voxelise.cpp:812 +#: ../src/backend/filters/compositionProfile.cpp:1070 +#: ../src/backend/filters/boundingBox.cpp:656 +#: ../src/backend/filters/dataLoad.cpp:565 +msgid "Appearance" msgstr "" -#: ../src/filters/dataLoad.cpp:503 -msgid "Sample data" +#: ../src/backend/filters/voxelise.cpp:819 +msgid "Spot size" msgstr "" -#: ../src/filters/dataLoad.cpp:506 -msgid "" -"Perform random selection on file contents, instead of loading entire file" +#: ../src/backend/filters/voxelise.cpp:822 +msgid "Size of the spots to use for display" msgstr "" -#: ../src/filters/dataLoad.cpp:513 -msgid "Load Limit (MB)" +#: ../src/backend/filters/voxelise.cpp:827 +#: ../src/backend/filters/voxelise.cpp:858 +msgid "Transparency" msgstr "" -#: ../src/filters/dataLoad.cpp:516 -msgid "Limit for size of data to load" +#: ../src/backend/filters/voxelise.cpp:830 +msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)" msgstr "" -#: ../src/filters/dataLoad.cpp:522 -msgid "Monitor" +#: ../src/backend/filters/voxelise.cpp:838 +msgid "Isovalue" msgstr "" -#: ../src/filters/dataLoad.cpp:526 -msgid "" -"Watch file timestamp to track changes to file contents from other programs" +#: ../src/backend/filters/voxelise.cpp:841 +msgid "Scalar value to show as isosurface" msgstr "" -#: ../src/filters/dataLoad.cpp:528 -msgid "Load params." +#: ../src/backend/filters/voxelise.cpp:850 +#: ../src/backend/filters/compositionProfile.cpp:1061 +#: ../src/backend/filters/annotation.cpp:882 +#: ../src/backend/filters/spectrumPlot.cpp:471 +msgid "Colour" msgstr "" -#: ../src/filters/dataLoad.cpp:538 -msgid "Default colour " +#: ../src/backend/filters/voxelise.cpp:853 +msgid "Colour of isosurface" msgstr "" -#: ../src/filters/dataLoad.cpp:541 -msgid "Default colour for points, if not overridden by other filters" +#: ../src/backend/filters/voxelise.cpp:861 +msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)" msgstr "" -#: ../src/filters/dataLoad.cpp:546 -msgid "Draw Size" +#: ../src/backend/filters/voxelise.cpp:1264 +msgid "Voxelisation aborted" msgstr "" -#: ../src/filters/dataLoad.cpp:549 -msgid "Default size for points, if not overridden by other filters" +#: ../src/backend/filters/voxelise.cpp:1266 +msgid "Out of memory" msgstr "" -#: ../src/filters/ionDownsample.cpp:447 -msgid "By Count" +#: ../src/backend/filters/voxelise.cpp:1268 +msgid "Unable to perform filter convolution" msgstr "" -#: ../src/filters/ionDownsample.cpp:450 -msgid "Sample up to a fixed number of ions" +#: ../src/backend/filters/voxelise.cpp:1270 +msgid "Voxelisation bounds are invalid" msgstr "" -#: ../src/filters/ionDownsample.cpp:456 -msgid "Per Species" +#: ../src/backend/filters/ionColour.cpp:289 +msgid "Colour Map" msgstr "" -#: ../src/filters/ionDownsample.cpp:460 -msgid "Use species specific (from ranging) sampling values" +#: ../src/backend/filters/ionColour.cpp:293 +msgid "Colour scheme used to assign points colours by value" msgstr "" -#: ../src/filters/ionDownsample.cpp:465 -msgid "Sampling rates" +#: ../src/backend/filters/ionColour.cpp:301 +msgid "Show Bar" msgstr "" -#: ../src/filters/ionDownsample.cpp:488 -msgid "Sampling value for species" +#: ../src/backend/filters/ionColour.cpp:308 +msgid "Num Colours" msgstr "" -#: ../src/filters/ionDownsample.cpp:500 -msgid "Output Count" +#: ../src/backend/filters/ionColour.cpp:310 +msgid "Number of unique colours to use in colour map" msgstr "" -#: ../src/filters/ionDownsample.cpp:503 -msgid "Sample up to this value of points" +#: ../src/backend/filters/ionColour.cpp:316 +msgid "Map start" msgstr "" -#: ../src/filters/ionDownsample.cpp:508 -msgid "Out Fraction" +#: ../src/backend/filters/ionColour.cpp:317 +msgid "Assign points with this value to the first colour in map" msgstr "" -#: ../src/filters/ionDownsample.cpp:512 -msgid "Sample this fraction of points" +#: ../src/backend/filters/ionColour.cpp:324 +msgid "Map end" msgstr "" -#: ../src/filters/ionDownsample.cpp:660 -msgid "Downsample Aborted" +#: ../src/backend/filters/ionColour.cpp:325 +msgid "Assign points with this value to the last colour in map" msgstr "" -#: ../src/filters/ionDownsample.cpp:662 -msgid "Insuffient memory for downsample" +#: ../src/backend/filters/ionColour.cpp:425 +#: ../src/backend/filters/transform.cpp:1577 +#: ../src/backend/filters/ionInfo.cpp:548 +msgid "Aborted" msgstr "" -#: ../src/filters/compositionProfile.cpp:492 +#: ../src/backend/filters/compositionProfile.cpp:449 msgid "Distance" msgstr "" -#: ../src/filters/compositionProfile.cpp:500 +#: ../src/backend/filters/compositionProfile.cpp:457 msgid "Fraction" msgstr "" -#: ../src/filters/compositionProfile.cpp:502 +#: ../src/backend/filters/compositionProfile.cpp:459 msgid "Density (\\#.len^3)" msgstr "" -#: ../src/filters/compositionProfile.cpp:529 +#: ../src/backend/filters/compositionProfile.cpp:486 msgid "Freq. Profile" msgstr "" -#: ../src/filters/compositionProfile.cpp:602 +#: ../src/backend/filters/compositionProfile.cpp:584 msgid "Too many bins in comp. profile." msgstr "" -#: ../src/filters/compositionProfile.cpp:604 +#: ../src/backend/filters/compositionProfile.cpp:586 msgid "Not enough memory for comp. profile." msgstr "" -#: ../src/filters/compositionProfile.cpp:606 +#: ../src/backend/filters/compositionProfile.cpp:588 msgid "Aborted composition prof." msgstr "" -#: ../src/filters/compositionProfile.cpp:886 +#: ../src/backend/filters/compositionProfile.cpp:905 msgid "Primitive type" msgstr "" -#: ../src/filters/compositionProfile.cpp:890 +#: ../src/backend/filters/compositionProfile.cpp:909 msgid "Basic shape to use for profile" msgstr "" -#: ../src/filters/compositionProfile.cpp:901 +#: ../src/backend/filters/compositionProfile.cpp:920 msgid "Display the 3D composition profile interaction object" msgstr "" -#: ../src/filters/compositionProfile.cpp:915 +#: ../src/backend/filters/compositionProfile.cpp:934 +#: ../src/backend/filters/spatialAnalysis.cpp:596 msgid "Position for centre of cylinder" msgstr "" -#: ../src/filters/compositionProfile.cpp:923 -msgid "Vector between centre and end of cylinder" +#: ../src/backend/filters/compositionProfile.cpp:942 +msgid "Vector between ends of cylinder" msgstr "" -#: ../src/filters/compositionProfile.cpp:934 +#: ../src/backend/filters/compositionProfile.cpp:953 msgid "Prevent length of cylinder changing during interaction" msgstr "" -#: ../src/filters/compositionProfile.cpp:950 +#: ../src/backend/filters/compositionProfile.cpp:993 msgid "Fixed Bin Num" msgstr "" -#: ../src/filters/compositionProfile.cpp:953 +#: ../src/backend/filters/compositionProfile.cpp:996 msgid "" "If true, use a fixed number of bins for profile, otherwise use fixed step " "size" msgstr "" -#: ../src/filters/compositionProfile.cpp:964 +#: ../src/backend/filters/compositionProfile.cpp:1002 +#: ../src/backend/filters/spatialAnalysis.cpp:420 +#: ../src/backend/filters/spatialAnalysis.cpp:569 +msgid "Num Bins" +msgstr "" + +#: ../src/backend/filters/compositionProfile.cpp:1007 msgid "Number of bins to use for profile" msgstr "" -#: ../src/filters/compositionProfile.cpp:975 -msgid "Size of each bin in profile" +#: ../src/backend/filters/compositionProfile.cpp:1012 +#: ../src/backend/filters/spectrumPlot.cpp:395 +msgid "Bin width" msgstr "" -#: ../src/filters/compositionProfile.cpp:980 ../src/filters/ionInfo.cpp:522 -#: ../src/filters/clusterAnalysis.cpp:1015 -msgid "Normalise" +#: ../src/backend/filters/compositionProfile.cpp:1018 +msgid "Size of each bin in profile" msgstr "" -#: ../src/filters/compositionProfile.cpp:984 +#: ../src/backend/filters/compositionProfile.cpp:1027 msgid "Convert bin counts into relative frequencies in each bin" msgstr "" -#: ../src/filters/compositionProfile.cpp:1008 +#: ../src/backend/filters/compositionProfile.cpp:1048 +#: ../src/backend/filters/spectrumPlot.cpp:458 +msgid "Plot Type" +msgstr "" + +#: ../src/backend/filters/compositionProfile.cpp:1051 msgid "Visual style for plot" msgstr "" -#: ../src/filters/compositionProfile.cpp:1021 +#: ../src/backend/filters/compositionProfile.cpp:1064 msgid "Colour of plot" msgstr "" -#: ../src/filters/compositionProfile.cpp:1037 +#: ../src/backend/filters/compositionProfile.cpp:1080 msgid "Err. Estimator" msgstr "" -#: ../src/filters/compositionProfile.cpp:1040 +#: ../src/backend/filters/compositionProfile.cpp:1083 msgid "Method of estimating error associated with each bin" msgstr "" -#: ../src/filters/compositionProfile.cpp:1047 +#: ../src/backend/filters/compositionProfile.cpp:1090 msgid "Avg. Window" msgstr "" -#: ../src/filters/compositionProfile.cpp:1050 +#: ../src/backend/filters/compositionProfile.cpp:1093 msgid "Number of bins to include in moving average filter" msgstr "" -#: ../src/filters/compositionProfile.cpp:1054 +#: ../src/backend/filters/compositionProfile.cpp:1097 msgid "Error analysis" msgstr "" -#: ../src/filters/ionInfo.cpp:34 -msgid "Rectilinear" +#: ../src/backend/filters/spatialAnalysis.cpp:72 +msgid "Local Density" msgstr "" -#: ../src/filters/ionInfo.cpp:35 -msgid "Convex hull" +#: ../src/backend/filters/spatialAnalysis.cpp:73 +msgid "Density Filtering" msgstr "" -#: ../src/filters/ionInfo.cpp:298 -msgid "No ions" +#: ../src/backend/filters/spatialAnalysis.cpp:74 +msgid "Radial Distribution" msgstr "" -#: ../src/filters/ionInfo.cpp:336 -msgid "--Counts--" +#: ../src/backend/filters/spatialAnalysis.cpp:75 +msgid "Axial Distribution" msgstr "" -#: ../src/filters/ionInfo.cpp:348 -msgid "Total Ranged\t" +#: ../src/backend/filters/spatialAnalysis.cpp:79 +msgid "Fixed Neighbour Count" msgstr "" -#: ../src/filters/ionInfo.cpp:353 -msgid "Total (incl. unranged)\t" +#: ../src/backend/filters/spatialAnalysis.cpp:80 +msgid "Fixed Radius" msgstr "" -#: ../src/filters/ionInfo.cpp:366 -msgid "n/a" +#: ../src/backend/filters/spatialAnalysis.cpp:363 +msgid "Spatial analysis algorithm to use" msgstr "" -#: ../src/filters/ionInfo.cpp:376 -msgid "Unranged" +#: ../src/backend/filters/spatialAnalysis.cpp:385 +msgid "Stop Mode" msgstr "" -#: ../src/filters/ionInfo.cpp:392 -msgid "Number of points : " +#: ../src/backend/filters/spatialAnalysis.cpp:388 +msgid "Method to use to terminate algorithm when examining each point" msgstr "" -#: ../src/filters/ionInfo.cpp:421 -msgid "Rectilinear Bounds : " +#: ../src/backend/filters/spatialAnalysis.cpp:395 +msgid "NN Max" msgstr "" -#: ../src/filters/ionInfo.cpp:426 -msgid "Volume (len^3): " +#: ../src/backend/filters/spatialAnalysis.cpp:398 +msgid "Maximum number of neighbours to examine" msgstr "" -#: ../src/filters/ionInfo.cpp:442 -msgid "Convex Volume (len^3): " +#: ../src/backend/filters/spatialAnalysis.cpp:404 +msgid "Dist Max" msgstr "" -#: ../src/filters/ionInfo.cpp:444 -msgid "Unable to compute volume" +#: ../src/backend/filters/spatialAnalysis.cpp:407 +msgid "Maximum distance from each point for search" msgstr "" -#: ../src/filters/ionInfo.cpp:473 -msgid "Ranged Density (pts/vol):" +#: ../src/backend/filters/spatialAnalysis.cpp:423 +#: ../src/backend/filters/spatialAnalysis.cpp:572 +msgid "Number of bins for output 1D RDF plot" msgstr "" -#: ../src/filters/ionInfo.cpp:478 -msgid "Total Density (pts/vol):" +#: ../src/backend/filters/spatialAnalysis.cpp:432 +msgid "Surface Remove" msgstr "" -#: ../src/filters/ionInfo.cpp:506 -msgid "Compositions" +#: ../src/backend/filters/spatialAnalysis.cpp:435 +msgid "" +"Exclude surface as part of source to minimise bias in RDF (at cost of " +"increased noise)" msgstr "" -#: ../src/filters/ionInfo.cpp:507 -msgid "Display compositional data for points in console" +#: ../src/backend/filters/spatialAnalysis.cpp:442 +msgid "Remove Dist" msgstr "" -#: ../src/filters/ionInfo.cpp:511 -msgid "Counts" +#: ../src/backend/filters/spatialAnalysis.cpp:445 +msgid "Minimum distance to remove from surface" msgstr "" -#: ../src/filters/ionInfo.cpp:512 -msgid "Display count data for points in console" +#: ../src/backend/filters/spatialAnalysis.cpp:456 +#: ../src/backend/filters/spatialAnalysis.cpp:581 +msgid "Plot colour " msgstr "" -#: ../src/filters/ionInfo.cpp:526 -msgid "Normalise count data" +#: ../src/backend/filters/spatialAnalysis.cpp:459 +#: ../src/backend/filters/spatialAnalysis.cpp:584 +msgid "Colour of output plot" msgstr "" -#: ../src/filters/ionInfo.cpp:535 -msgid "Volume" +#: ../src/backend/filters/spatialAnalysis.cpp:478 +msgid "Source" msgstr "" -#: ../src/filters/ionInfo.cpp:538 -msgid "Compute volume for point data" +#: ../src/backend/filters/spatialAnalysis.cpp:481 +msgid "Ions to use for initiating RDF search" msgstr "" -#: ../src/filters/ionInfo.cpp:553 -msgid "Select volume counting technique" +#: ../src/backend/filters/spatialAnalysis.cpp:497 +msgid "Enable/disable ion as source" msgstr "" -#: ../src/filters/ionInfo.cpp:649 -msgid "Insufficient memory for operation" +#: ../src/backend/filters/spatialAnalysis.cpp:514 +msgid "Enable/disable all ions as target" msgstr "" -#: ../src/filters/ionInfo.cpp:653 -msgid "Bug? Problem with qhull library, cannot run convex hull." +#: ../src/backend/filters/spatialAnalysis.cpp:529 +msgid "Enable/disable this ion as target" msgstr "" -#: ../src/filters/annotation.cpp:50 -msgid "Arrow" +#: ../src/backend/filters/spatialAnalysis.cpp:542 +msgid "Cutoff" msgstr "" -#: ../src/filters/annotation.cpp:51 -msgid "Text" +#: ../src/backend/filters/spatialAnalysis.cpp:545 +msgid "Remove points with local density above/below this value" msgstr "" -#: ../src/filters/annotation.cpp:52 -msgid "Arrow+Text" +#: ../src/backend/filters/spatialAnalysis.cpp:555 +msgid "Retain Upper" msgstr "" -#: ../src/filters/annotation.cpp:53 -msgid "Angle" +#: ../src/backend/filters/spatialAnalysis.cpp:558 +msgid "Retain either points with density above (enabled) or below cutoff" msgstr "" -#: ../src/filters/annotation.cpp:54 -msgid "Ruler" +#: ../src/backend/filters/spatialAnalysis.cpp:604 +msgid "Vector between centre and end of cylinder" msgstr "" -#: ../src/filters/annotation.cpp:521 -msgid "Type or style of annotation" +#: ../src/backend/filters/spatialAnalysis.cpp:622 +msgid "Alg. Params." msgstr "" -#: ../src/filters/annotation.cpp:536 ../src/filters/annotation.cpp:637 -msgid "Text of annotation" +#: ../src/backend/filters/spatialAnalysis.cpp:1016 +msgid "Spatial analysis aborted by user" msgstr "" -#: ../src/filters/annotation.cpp:544 -msgid "Position of annotation" +#: ../src/backend/filters/spatialAnalysis.cpp:1018 +msgid "Insufficient data to complete analysis." msgstr "" -#: ../src/filters/annotation.cpp:548 ../src/filters/annotation.cpp:651 -#: ../src/filters/annotation.cpp:709 ../src/filters/annotation.cpp:798 -msgid "Up dir" +#: ../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 +msgid "Build" msgstr "" -#: ../src/filters/annotation.cpp:552 ../src/filters/annotation.cpp:802 -msgid "Vector for up direction of annotation text" +#: ../src/backend/filters/spatialAnalysis.cpp:1504 +#: ../src/backend/filters/spatialAnalysis.cpp:1558 +msgid "Surface" msgstr "" -#: ../src/filters/annotation.cpp:556 ../src/filters/annotation.cpp:658 -#: ../src/filters/annotation.cpp:701 ../src/filters/annotation.cpp:806 -msgid "Across dir" +#: ../src/backend/filters/spatialAnalysis.cpp:1598 +#: ../src/backend/filters/spatialAnalysis.cpp:1820 +#: ../src/backend/filters/spatialAnalysis.cpp:2116 +msgid "Analyse" msgstr "" -#: ../src/filters/annotation.cpp:560 ../src/filters/annotation.cpp:810 -msgid "Reading direction for annotation" +#: ../src/backend/filters/spatialAnalysis.cpp:1655 +#: ../src/backend/filters/spatialAnalysis.cpp:1724 +msgid "Radial Distance" msgstr "" -#: ../src/filters/annotation.cpp:565 ../src/filters/annotation.cpp:643 -#: ../src/filters/annotation.cpp:736 -msgid "Text size" +#: ../src/backend/filters/spatialAnalysis.cpp:1659 +msgid "NN Freq." msgstr "" -#: ../src/filters/annotation.cpp:569 ../src/filters/annotation.cpp:647 -#: ../src/filters/annotation.cpp:818 -msgid "Relative size of annotation text" +#: ../src/backend/filters/spatialAnalysis.cpp:1715 +msgid "Warning, " msgstr "" -#: ../src/filters/annotation.cpp:577 ../src/filters/annotation.cpp:616 -#: ../src/filters/annotation.cpp:782 -msgid "Start" +#: ../src/backend/filters/spatialAnalysis.cpp:1716 +msgid "" +" points were unable to find neighbour points that exceeded the search " +"radius, and thus terminated prematurely" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:1726 +msgid " RDF" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2016 +#: ../src/backend/filters/spatialAnalysis.cpp:2322 +msgid "Number Density (\\#/Vol^3)" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2043 +#: ../src/backend/filters/spatialAnalysis.cpp:2347 +msgid "Warning," +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2044 +#: ../src/backend/filters/spatialAnalysis.cpp:2348 +msgid " points were un-analysable. These have been dropped" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2066 +#: ../src/backend/filters/spatialAnalysis.cpp:2370 +msgid "And so on..." +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2450 +msgid "Extract" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2501 +msgid "Reduce" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2595 +msgid "Compute" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2620 +msgid "Insufficient points to complete analysis" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2658 +msgid "Axial Distance" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2660 +msgid " 1D Dist. Func." +msgstr "" + +#: ../src/backend/filters/transform.cpp:77 +msgid "Translate" +msgstr "" + +#: ../src/backend/filters/transform.cpp:78 +msgid "Scale (isotropic)" +msgstr "" + +#: ../src/backend/filters/transform.cpp:79 +msgid "Scale (anisotropic)" +msgstr "" + +#: ../src/backend/filters/transform.cpp:80 +msgid "Rotate" +msgstr "" + +#: ../src/backend/filters/transform.cpp:81 +msgid "Value Shuffle" msgstr "" -#: ../src/filters/annotation.cpp:581 ../src/filters/annotation.cpp:620 -msgid "3D position for tail of arrow" +#: ../src/backend/filters/transform.cpp:82 +msgid "Spatial Noise" msgstr "" -#: ../src/filters/annotation.cpp:585 ../src/filters/annotation.cpp:625 -#: ../src/filters/annotation.cpp:790 -msgid "End" +#: ../src/backend/filters/transform.cpp:83 +msgid "Translate Value" msgstr "" -#: ../src/filters/annotation.cpp:589 ../src/filters/annotation.cpp:629 -msgid "3D Position to which arrow points" +#: ../src/backend/filters/transform.cpp:87 +msgid "Specify" msgstr "" -#: ../src/filters/annotation.cpp:595 ../src/filters/annotation.cpp:665 -msgid "Tip radius" +#: ../src/backend/filters/transform.cpp:88 +msgid "Boundbox Centre" msgstr "" -#: ../src/filters/annotation.cpp:599 -msgid "Size of the arrow head" +#: ../src/backend/filters/transform.cpp:89 +msgid "Mass Centre" msgstr "" -#: ../src/filters/annotation.cpp:603 -msgid "Line size" +#: ../src/backend/filters/transform.cpp:1058 +msgid "Mass-to-Charge (amu/e)" msgstr "" -#: ../src/filters/annotation.cpp:607 -msgid "Thickness of line used to draw arrow stem" +#: ../src/backend/filters/transform.cpp:1112 +msgid "Shuffle" msgstr "" -#: ../src/filters/annotation.cpp:675 -msgid "Position A" +#: ../src/backend/filters/transform.cpp:1128 +msgid "Splice" msgstr "" -#: ../src/filters/annotation.cpp:679 -msgid "Location of first non-central vertex" +#: ../src/backend/filters/transform.cpp:1183 +msgid "Algorithm to use to transform point data" msgstr "" -#: ../src/filters/annotation.cpp:683 -msgid "Origin " +#: ../src/backend/filters/transform.cpp:1199 +msgid "Origin mode" msgstr "" -#: ../src/filters/annotation.cpp:687 -msgid "Location of central vertex" +#: ../src/backend/filters/transform.cpp:1202 +msgid "Select how transform origin is computed" msgstr "" -#: ../src/filters/annotation.cpp:691 -msgid "Position B" +#: ../src/backend/filters/transform.cpp:1207 +msgid "Show marker" msgstr "" -#: ../src/filters/annotation.cpp:695 -msgid "Location of second non-central vertex" +#: ../src/backend/filters/transform.cpp:1211 +msgid "Display an interactive object to set transform origin" msgstr "" -#: ../src/filters/annotation.cpp:705 -msgid "Reading direction for angle text" +#: ../src/backend/filters/transform.cpp:1213 +msgid "Display a small marker to denote transform origin" msgstr "" -#: ../src/filters/annotation.cpp:710 -msgid "Vector for up direction of angle text" +#: ../src/backend/filters/transform.cpp:1229 +msgid "Translation" msgstr "" -#: ../src/filters/annotation.cpp:718 -msgid "Reflexive" +#: ../src/backend/filters/transform.cpp:1232 +msgid "Translation vector for transform" msgstr "" -#: ../src/filters/annotation.cpp:721 -msgid "Measure interor (enabled) or exterior angle (disabled)" +#: ../src/backend/filters/transform.cpp:1244 +msgid "Offset" msgstr "" -#: ../src/filters/annotation.cpp:726 -msgid "Show Angle" +#: ../src/backend/filters/transform.cpp:1248 +msgid "Scalar to use to offset each point's associated value" msgstr "" -#: ../src/filters/annotation.cpp:730 -msgid "Display angle text (when enabled)" +#: ../src/backend/filters/transform.cpp:1265 +#: ../src/backend/filters/transform.cpp:1292 +msgid "Origin of scale trasnform" msgstr "" -#: ../src/filters/annotation.cpp:740 -msgid "Size of angle text" +#: ../src/backend/filters/transform.cpp:1272 +#: ../src/backend/filters/transform.cpp:1299 +msgid "Scale Fact." msgstr "" -#: ../src/filters/annotation.cpp:758 -msgid "Digit format" +#: ../src/backend/filters/transform.cpp:1275 +#: ../src/backend/filters/transform.cpp:1302 +msgid "Enlargement factor for scaling around origin" msgstr "" -#: ../src/filters/annotation.cpp:762 -msgid "" -"Format of angle text; # for numeral position, '.' for separator, eg ##.## " -"gives 12.34" +#: ../src/backend/filters/transform.cpp:1318 +msgid "Origin of rotation" msgstr "" -#: ../src/filters/annotation.cpp:768 -msgid "Sphere size" +#: ../src/backend/filters/transform.cpp:1326 +msgid "Axis around which to revolve" msgstr "" -#: ../src/filters/annotation.cpp:772 -msgid "Marker sphere size for manipulating tool" +#: ../src/backend/filters/transform.cpp:1331 +msgid "Angle (deg)" msgstr "" -#: ../src/filters/annotation.cpp:786 -msgid "Ruler beginning 3D location" +#: ../src/backend/filters/transform.cpp:1334 +msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)" msgstr "" -#: ../src/filters/annotation.cpp:794 -msgid "Ruler finish 3D location" +#: ../src/backend/filters/transform.cpp:1351 +msgid "Noise Type" msgstr "" -#: ../src/filters/annotation.cpp:827 -msgid "Fixed ticks" +#: ../src/backend/filters/transform.cpp:1354 +msgid "Method to use to degrade point data" msgstr "" -#: ../src/filters/annotation.cpp:830 -msgid "" -"Use fixed (enabled) number of text markers, or one every fixed distance " -"(disabled)" +#: ../src/backend/filters/transform.cpp:1361 +msgid "Noise level" msgstr "" -#: ../src/filters/annotation.cpp:837 -msgid "Num Ticks" +#: ../src/backend/filters/transform.cpp:1363 +msgid "Standard dev." msgstr "" -#: ../src/filters/annotation.cpp:840 -msgid "Number of tick marks along ruler" +#: ../src/backend/filters/transform.cpp:1371 +msgid "Amplitude of noise" msgstr "" -#: ../src/filters/annotation.cpp:847 -msgid "Tick Spacing" +#: ../src/backend/filters/transform.cpp:1383 +msgid "Transform Params" msgstr "" -#: ../src/filters/annotation.cpp:850 -msgid "Distance between tick marks along ruler" +#: ../src/backend/filters/transform.cpp:1580 +msgid "Unable to allocate memory" msgstr "" -#: ../src/filters/annotation.cpp:867 -msgid "Colour for ruler and ticks" +#: ../src/backend/filters/transform.cpp:1759 +msgid "White" msgstr "" -#: ../src/filters/voxelise.cpp:66 -msgid "None (Raw count)" +#: ../src/backend/filters/transform.cpp:1761 +msgid "Gaussian" msgstr "" -#: ../src/filters/voxelise.cpp:67 -msgid "Volume (Density)" +#: ../src/backend/filters/boundingBox.cpp:55 +msgid "Box only" msgstr "" -#: ../src/filters/voxelise.cpp:68 -msgid "All Ions (conc)" +#: ../src/backend/filters/boundingBox.cpp:56 +msgid "Tick" msgstr "" -#: ../src/filters/voxelise.cpp:69 -msgid "Ratio (Num/Denom)" +#: ../src/backend/filters/boundingBox.cpp:57 +msgid "Dimension" msgstr "" -#: ../src/filters/voxelise.cpp:73 -msgid "Point Cloud" +#: ../src/backend/filters/boundingBox.cpp:532 +msgid "If true, show box, otherwise hide box" msgstr "" -#: ../src/filters/voxelise.cpp:74 -msgid "Isosurface" +#: ../src/backend/filters/boundingBox.cpp:545 +msgid "Style" msgstr "" -#: ../src/filters/voxelise.cpp:79 -msgid "Gaussian (2𝜎)" +#: ../src/backend/filters/boundingBox.cpp:548 +msgid "Box display mode" msgstr "" -#: ../src/filters/voxelise.cpp:83 -msgid "Zero" +#: ../src/backend/filters/boundingBox.cpp:559 +msgid "Fixed Tick Num" msgstr "" -#: ../src/filters/voxelise.cpp:84 -msgid "Bounce" +#: ../src/backend/filters/boundingBox.cpp:563 +msgid "" +"If true, evenly use specified number of ticks. Otherwise, use distance to " +"determine tick count" msgstr "" -#: ../src/filters/voxelise.cpp:525 -msgid "Voxel Limits (min,max): (" +#: ../src/backend/filters/boundingBox.cpp:571 +msgid "Num X" msgstr "" -#: ../src/filters/voxelise.cpp:574 -msgid "Fixed width" +#: ../src/backend/filters/boundingBox.cpp:574 +msgid "Tick count in X direction" msgstr "" -#: ../src/filters/voxelise.cpp:578 -msgid "If true, use fixed size voxels, otherwise use fixed count" +#: ../src/backend/filters/boundingBox.cpp:579 +msgid "Num Y" msgstr "" -#: ../src/filters/voxelise.cpp:584 -msgid "Bin width x" +#: ../src/backend/filters/boundingBox.cpp:582 +msgid "Tick count in Y direction" msgstr "" -#: ../src/filters/voxelise.cpp:588 -msgid "Voxel size in X direction" +#: ../src/backend/filters/boundingBox.cpp:587 +msgid "Num Z" msgstr "" -#: ../src/filters/voxelise.cpp:592 -msgid "Bin width y" +#: ../src/backend/filters/boundingBox.cpp:590 +msgid "Tick count in Z direction" msgstr "" -#: ../src/filters/voxelise.cpp:595 -msgid "Voxel size in Y direction" +#: ../src/backend/filters/boundingBox.cpp:596 +msgid "Spacing X" msgstr "" -#: ../src/filters/voxelise.cpp:601 -msgid "Bin width z" +#: ../src/backend/filters/boundingBox.cpp:600 +msgid "Distance between ticks on X axis" msgstr "" -#: ../src/filters/voxelise.cpp:604 -msgid "Voxel size in Z direction" +#: ../src/backend/filters/boundingBox.cpp:604 +msgid "Spacing Y" msgstr "" -#: ../src/filters/voxelise.cpp:611 -msgid "Num bins x" +#: ../src/backend/filters/boundingBox.cpp:608 +msgid "Distance between ticks on Y axis" msgstr "" -#: ../src/filters/voxelise.cpp:615 -msgid "Number of voxels to use in X direction" +#: ../src/backend/filters/boundingBox.cpp:612 +msgid "Spacing Z" msgstr "" -#: ../src/filters/voxelise.cpp:620 -msgid "Num bins y" +#: ../src/backend/filters/boundingBox.cpp:616 +msgid "Distance between ticks on Z axis" msgstr "" -#: ../src/filters/voxelise.cpp:623 -msgid "Number of voxels to use in Y direction" +#: ../src/backend/filters/boundingBox.cpp:619 +msgid "Tick marks" msgstr "" -#: ../src/filters/voxelise.cpp:629 -msgid "Num bins z" +#: ../src/backend/filters/boundingBox.cpp:629 +msgid "Box Colour" msgstr "" -#: ../src/filters/voxelise.cpp:631 -msgid "Number of voxels to use in Z direction" +#: ../src/backend/filters/boundingBox.cpp:633 +msgid "Colour of the bounding box" msgstr "" -#: ../src/filters/voxelise.cpp:652 -msgid "Normalise by" +#: ../src/backend/filters/boundingBox.cpp:638 +msgid "Line thickness" msgstr "" -#: ../src/filters/voxelise.cpp:655 -msgid "Method to use to normalise scalar value in each voxel" +#: ../src/backend/filters/boundingBox.cpp:642 +msgid "Thickness of the lines used to draw the box" msgstr "" -#: ../src/filters/voxelise.cpp:658 -msgid "Computation" +#: ../src/backend/filters/boundingBox.cpp:650 +#: ../src/backend/filters/annotation.cpp:833 +msgid "Font Size" msgstr "" -#: ../src/filters/voxelise.cpp:665 -msgid "Numerator" +#: ../src/backend/filters/boundingBox.cpp:653 +msgid "Relative size for text" msgstr "" -#: ../src/filters/voxelise.cpp:668 -msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value" +#: ../src/backend/filters/annotation.cpp:67 +msgid "Arrow" msgstr "" -#: ../src/filters/voxelise.cpp:688 -msgid "Enable this ion for numerator" +#: ../src/backend/filters/annotation.cpp:68 +msgid "Text" msgstr "" -#: ../src/filters/voxelise.cpp:699 -msgid "Denominator" +#: ../src/backend/filters/annotation.cpp:69 +msgid "Arrow+Text" msgstr "" -#: ../src/filters/voxelise.cpp:702 -msgid "Parameter \"b\" used in fraction (a/b) to get voxel value" +#: ../src/backend/filters/annotation.cpp:70 +msgid "Angle" msgstr "" -#: ../src/filters/voxelise.cpp:718 -msgid "Enable this ion for denominator contribution" +#: ../src/backend/filters/annotation.cpp:71 +msgid "Ruler" msgstr "" -#: ../src/filters/voxelise.cpp:739 ../src/filters/voxelise.cpp:774 -msgid "Filtering" +#: ../src/backend/filters/annotation.cpp:538 +msgid "Type or style of annotation" msgstr "" -#: ../src/filters/voxelise.cpp:743 -msgid "Smoothing method to use on voxels" +#: ../src/backend/filters/annotation.cpp:553 +#: ../src/backend/filters/annotation.cpp:655 +msgid "Text of annotation" msgstr "" -#: ../src/filters/voxelise.cpp:746 -msgid "Processing" +#: ../src/backend/filters/annotation.cpp:561 +msgid "Position of annotation" msgstr "" -#: ../src/filters/voxelise.cpp:752 -msgid "Kernel Bins" +#: ../src/backend/filters/annotation.cpp:565 +#: ../src/backend/filters/annotation.cpp:669 +#: ../src/backend/filters/annotation.cpp:727 +#: ../src/backend/filters/annotation.cpp:816 +msgid "Up dir" msgstr "" -#: ../src/filters/voxelise.cpp:756 -msgid "Number of bins in convolution kernel" +#: ../src/backend/filters/annotation.cpp:569 +#: ../src/backend/filters/annotation.cpp:820 +msgid "Vector for up direction of annotation text" msgstr "" -#: ../src/filters/voxelise.cpp:767 -msgid "Exterior values" +#: ../src/backend/filters/annotation.cpp:573 +#: ../src/backend/filters/annotation.cpp:676 +#: ../src/backend/filters/annotation.cpp:719 +#: ../src/backend/filters/annotation.cpp:824 +msgid "Across dir" msgstr "" -#: ../src/filters/voxelise.cpp:770 -msgid "Method to use to treat boundaries of voxel data for convolution" +#: ../src/backend/filters/annotation.cpp:577 +#: ../src/backend/filters/annotation.cpp:828 +msgid "Reading direction for annotation" msgstr "" -#: ../src/filters/voxelise.cpp:788 -msgid "Representation" +#: ../src/backend/filters/annotation.cpp:582 +#: ../src/backend/filters/annotation.cpp:661 +#: ../src/backend/filters/annotation.cpp:754 +msgid "Text size" msgstr "" -#: ../src/filters/voxelise.cpp:791 -msgid "3D display method" +#: ../src/backend/filters/annotation.cpp:586 +#: ../src/backend/filters/annotation.cpp:665 +#: ../src/backend/filters/annotation.cpp:836 +msgid "Relative size of annotation text" msgstr "" -#: ../src/filters/voxelise.cpp:801 -msgid "Spot size" +#: ../src/backend/filters/annotation.cpp:594 +#: ../src/backend/filters/annotation.cpp:633 +#: ../src/backend/filters/annotation.cpp:800 +msgid "Start" msgstr "" -#: ../src/filters/voxelise.cpp:804 -msgid "Size of the spots to use for display" +#: ../src/backend/filters/annotation.cpp:598 +#: ../src/backend/filters/annotation.cpp:637 +msgid "3D position for tail of arrow" msgstr "" -#: ../src/filters/voxelise.cpp:809 ../src/filters/voxelise.cpp:840 -msgid "Transparency" +#: ../src/backend/filters/annotation.cpp:602 +#: ../src/backend/filters/annotation.cpp:642 +#: ../src/backend/filters/annotation.cpp:808 +msgid "End" msgstr "" -#: ../src/filters/voxelise.cpp:812 -msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)" +#: ../src/backend/filters/annotation.cpp:606 +#: ../src/backend/filters/annotation.cpp:646 +msgid "3D Position to which arrow points" msgstr "" -#: ../src/filters/voxelise.cpp:820 -msgid "Isovalue" +#: ../src/backend/filters/annotation.cpp:612 +#: ../src/backend/filters/annotation.cpp:683 +msgid "Tip radius" msgstr "" -#: ../src/filters/voxelise.cpp:823 -msgid "Scalar value to show as isosurface" +#: ../src/backend/filters/annotation.cpp:616 +msgid "Size of the arrow head" msgstr "" -#: ../src/filters/voxelise.cpp:835 -msgid "Colour of isosurface" +#: ../src/backend/filters/annotation.cpp:620 +msgid "Line size" msgstr "" -#: ../src/filters/voxelise.cpp:843 -msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)" +#: ../src/backend/filters/annotation.cpp:624 +msgid "Thickness of line used to draw arrow stem" msgstr "" -#: ../src/filters/voxelise.cpp:1246 -msgid "Voxelisation aborted" +#: ../src/backend/filters/annotation.cpp:693 +msgid "Position A" msgstr "" -#: ../src/filters/voxelise.cpp:1248 -msgid "Out of memory" +#: ../src/backend/filters/annotation.cpp:697 +msgid "Location of first non-central vertex" msgstr "" -#: ../src/filters/voxelise.cpp:1250 -msgid "Unable to perform filter convolution" +#: ../src/backend/filters/annotation.cpp:701 +msgid "Origin " msgstr "" -#: ../src/filters/voxelise.cpp:1252 -msgid "Voxelisation bounds are invalid" +#: ../src/backend/filters/annotation.cpp:705 +msgid "Location of central vertex" msgstr "" -#: ../src/filters/externalProgram.cpp:499 -msgid "Command" +#: ../src/backend/filters/annotation.cpp:709 +msgid "Position B" msgstr "" -#: ../src/filters/externalProgram.cpp:502 -msgid "" -"Full command to send to operating system. See manual for escape sequence " -"meanings" +#: ../src/backend/filters/annotation.cpp:713 +msgid "Location of second non-central vertex" msgstr "" -#: ../src/filters/externalProgram.cpp:506 -msgid "Work Dir" +#: ../src/backend/filters/annotation.cpp:723 +msgid "Reading direction for angle text" msgstr "" -#: ../src/filters/externalProgram.cpp:509 -msgid "Directory to run the command in" +#: ../src/backend/filters/annotation.cpp:728 +msgid "Vector for up direction of angle text" msgstr "" -#: ../src/filters/externalProgram.cpp:519 -msgid "Cleanup input" +#: ../src/backend/filters/annotation.cpp:736 +msgid "Reflexive" msgstr "" -#: ../src/filters/externalProgram.cpp:522 -msgid "Erase input files when command completed" +#: ../src/backend/filters/annotation.cpp:739 +msgid "Measure interor (enabled) or exterior angle (disabled)" msgstr "" -#: ../src/filters/externalProgram.cpp:531 -msgid "Cache" +#: ../src/backend/filters/annotation.cpp:744 +msgid "Show Angle" msgstr "" -#: ../src/filters/externalProgram.cpp:534 -msgid "" -"Assume program does not alter its output, unless inputs from 3Depict are " -"altered" +#: ../src/backend/filters/annotation.cpp:748 +msgid "Display angle text (when enabled)" msgstr "" -#: ../src/filters/externalProgram.cpp:616 -msgid "Error processing command line" +#: ../src/backend/filters/annotation.cpp:758 +msgid "Size of angle text" msgstr "" -#: ../src/filters/externalProgram.cpp:618 -msgid "Unable to set working directory" +#: ../src/backend/filters/annotation.cpp:776 +msgid "Digit format" msgstr "" -#: ../src/filters/externalProgram.cpp:620 -msgid "Error saving posfile result for external program" +#: ../src/backend/filters/annotation.cpp:780 +msgid "" +"Format of angle text; # for numeral position, '.' for separator, eg ##.## " +"gives 12.34" msgstr "" -#: ../src/filters/externalProgram.cpp:622 -msgid "Error saving plot result for externalprogram" +#: ../src/backend/filters/annotation.cpp:786 +msgid "Sphere size" msgstr "" -#: ../src/filters/externalProgram.cpp:624 -msgid "Error creating temporary directory" +#: ../src/backend/filters/annotation.cpp:790 +msgid "Marker sphere size for manipulating tool" msgstr "" -#: ../src/filters/externalProgram.cpp:626 -msgid "Detected unusable number of columns in plot" +#: ../src/backend/filters/annotation.cpp:804 +msgid "Ruler beginning 3D location" msgstr "" -#: ../src/filters/externalProgram.cpp:628 -msgid "Unable to parse plot result from external program" +#: ../src/backend/filters/annotation.cpp:812 +msgid "Ruler finish 3D location" msgstr "" -#: ../src/filters/externalProgram.cpp:630 -msgid "Unable to load ions from external program" +#: ../src/backend/filters/annotation.cpp:845 +msgid "Fixed ticks" msgstr "" -#: ../src/filters/externalProgram.cpp:632 -msgid "Unable to perform commandline substitution" +#: ../src/backend/filters/annotation.cpp:848 +msgid "" +"Use fixed (enabled) number of text markers, or one every fixed distance " +"(disabled)" msgstr "" -#: ../src/filters/externalProgram.cpp:634 -msgid "Error executing external program" +#: ../src/backend/filters/annotation.cpp:855 +msgid "Num Ticks" msgstr "" -#: ../src/filters/rangeFile.cpp:131 -msgid "Pre-Allocate" +#: ../src/backend/filters/annotation.cpp:858 +msgid "Number of tick marks along ruler" msgstr "" -#: ../src/filters/rangeFile.cpp:245 ../src/filter.cpp:51 -msgid "Range" +#: ../src/backend/filters/annotation.cpp:865 +msgid "Tick Spacing" msgstr "" -#: ../src/filters/rangeFile.cpp:491 -msgid "File to use for range data" +#: ../src/backend/filters/annotation.cpp:868 +msgid "Distance between tick marks along ruler" msgstr "" -#: ../src/filters/rangeFile.cpp:503 -msgid "Drop unranged" +#: ../src/backend/filters/annotation.cpp:885 +msgid "Colour for ruler and ticks" msgstr "" -#: ../src/filters/rangeFile.cpp:505 -msgid "Remove unranged points when generating output" +#: ../src/backend/filters/ionDownsample.cpp:464 +msgid "By Count" msgstr "" -#: ../src/filters/rangeFile.cpp:525 -msgid "All Ions" +#: ../src/backend/filters/ionDownsample.cpp:467 +msgid "Sample up to a fixed number of ions" msgstr "" -#: ../src/filters/rangeFile.cpp:526 -msgid "Enable/disable all ions at once" +#: ../src/backend/filters/ionDownsample.cpp:473 +msgid "Per Species" msgstr "" -#: ../src/filters/rangeFile.cpp:535 -msgid "Species" +#: ../src/backend/filters/ionDownsample.cpp:477 +msgid "Use species specific (from ranging) sampling values" msgstr "" -#: ../src/filters/rangeFile.cpp:542 -msgid "IonID " +#: ../src/backend/filters/ionDownsample.cpp:482 +msgid "Sampling rates" msgstr "" -#: ../src/filters/rangeFile.cpp:543 -msgid "Enable/disable specified ion" +#: ../src/backend/filters/ionDownsample.cpp:505 +msgid "Sampling value for species" msgstr "" -#: ../src/filters/rangeFile.cpp:556 -msgid "Active Ion " +#: ../src/backend/filters/ionDownsample.cpp:517 +msgid "Output Count" msgstr "" -#: ../src/filters/rangeFile.cpp:558 -msgid "If true, ion is used in ouput" +#: ../src/backend/filters/ionDownsample.cpp:520 +msgid "Sample up to this value of points" msgstr "" -#: ../src/filters/rangeFile.cpp:572 -msgid "Colour " +#: ../src/backend/filters/ionDownsample.cpp:525 +msgid "Out Fraction" msgstr "" -#: ../src/filters/rangeFile.cpp:575 -msgid "Colour used to represent ion" +#: ../src/backend/filters/ionDownsample.cpp:529 +msgid "Sample this fraction of points" msgstr "" -#: ../src/filters/rangeFile.cpp:598 -msgid "All Ranges" +#: ../src/backend/filters/ionDownsample.cpp:677 +msgid "Downsample Aborted" msgstr "" -#: ../src/filters/rangeFile.cpp:599 -msgid "Enable/disable all ranges" +#: ../src/backend/filters/ionDownsample.cpp:679 +msgid "Insuffient memory for downsample" msgstr "" -#: ../src/filters/rangeFile.cpp:620 -msgid "Active Rng " +#: ../src/backend/filters/ionInfo.cpp:30 +msgid "Rectilinear" msgstr "" -#: ../src/filters/rangeFile.cpp:623 -msgid "" -"Enable/disable specified range (ion must also be enabled to activiate range)" +#: ../src/backend/filters/ionInfo.cpp:31 +msgid "Convex hull" msgstr "" -#: ../src/filters/rangeFile.cpp:627 -msgid "Ion " +#: ../src/backend/filters/ionInfo.cpp:195 +msgid "No ions" msgstr "" -#: ../src/filters/rangeFile.cpp:630 -msgid "Name of ion associate to this range" +#: ../src/backend/filters/ionInfo.cpp:233 +msgid "--Counts--" msgstr "" -#: ../src/filters/rangeFile.cpp:639 -msgid "Start rng " +#: ../src/backend/filters/ionInfo.cpp:245 +msgid "Total Ranged\t" msgstr "" -#: ../src/filters/rangeFile.cpp:642 -msgid "Start value for range" +#: ../src/backend/filters/ionInfo.cpp:250 +msgid "Total (incl. unranged)\t" msgstr "" -#: ../src/filters/rangeFile.cpp:647 -msgid "End rng " +#: ../src/backend/filters/ionInfo.cpp:263 +msgid "n/a" msgstr "" -#: ../src/filters/rangeFile.cpp:650 -msgid "Stopping value for range`" +#: ../src/backend/filters/ionInfo.cpp:273 +msgid "Unranged" msgstr "" -#: ../src/filters/rangeFile.cpp:948 -msgid "Ranging aborted by user" +#: ../src/backend/filters/ionInfo.cpp:289 +msgid "Number of points : " msgstr "" -#: ../src/filters/rangeFile.cpp:950 -msgid "Insufficient memory for range" +#: ../src/backend/filters/ionInfo.cpp:318 +msgid "Rectilinear Bounds : " msgstr "" -#: ../src/filters/ionColour.cpp:273 -msgid "Colour Map" +#: ../src/backend/filters/ionInfo.cpp:323 +msgid "Volume (len^3): " msgstr "" -#: ../src/filters/ionColour.cpp:277 -msgid "Colour scheme used to assign points colours by value" +#: ../src/backend/filters/ionInfo.cpp:339 +msgid "Convex Volume (len^3): " msgstr "" -#: ../src/filters/ionColour.cpp:285 -msgid "Show Bar" +#: ../src/backend/filters/ionInfo.cpp:341 +msgid "Unable to compute volume" msgstr "" -#: ../src/filters/ionColour.cpp:292 -msgid "Num Colours" +#: ../src/backend/filters/ionInfo.cpp:370 +msgid "Ranged Density (pts/vol):" msgstr "" -#: ../src/filters/ionColour.cpp:294 -msgid "Number of unique colours to use in colour map" +#: ../src/backend/filters/ionInfo.cpp:375 +msgid "Total Density (pts/vol):" msgstr "" -#: ../src/filters/ionColour.cpp:300 -msgid "Map start" +#: ../src/backend/filters/ionInfo.cpp:403 +msgid "Compositions" msgstr "" -#: ../src/filters/ionColour.cpp:301 -msgid "Assign points with this value to the first colour in map" +#: ../src/backend/filters/ionInfo.cpp:404 +msgid "Display compositional data for points in console" msgstr "" -#: ../src/filters/ionColour.cpp:308 -msgid "Map end" +#: ../src/backend/filters/ionInfo.cpp:408 +msgid "Counts" msgstr "" -#: ../src/filters/ionColour.cpp:309 -msgid "Assign points with this value to the last colour in map" +#: ../src/backend/filters/ionInfo.cpp:409 +msgid "Display count data for points in console" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:57 -#: ../src/filters/clusterAnalysis.cpp:981 -msgid "Size Distribution" +#: ../src/backend/filters/ionInfo.cpp:423 +msgid "Normalise count data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:58 -msgid "Chemistry Distribution" +#: ../src/backend/filters/ionInfo.cpp:432 +msgid "Volume" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:470 -msgid "No range data. Can't cluster." +#: ../src/backend/filters/ionInfo.cpp:435 +msgid "Compute volume for point data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:481 -msgid "" -"No ranges selected for cluster \"core\". Cannot continue with clustering." +#: ../src/backend/filters/ionInfo.cpp:450 +msgid "Select volume counting technique" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:493 -msgid "" -"No ranges selected for cluster \"bulk\". Cannot continue with clustering." +#: ../src/backend/filters/ionInfo.cpp:546 +msgid "Insufficient memory for operation" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:667 -msgid "Morphology Plot" +#: ../src/backend/filters/ionInfo.cpp:550 +msgid "Bug? Problem with qhull library, cannot run convex hull." msgstr "" -#: ../src/filters/clusterAnalysis.cpp:668 -msgid "\\lambda_1:\\lambda_2 ratio" +#: ../src/backend/filters/dataLoad.cpp:45 +msgid "POS Data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:669 -msgid "\\lambda_2:\\lambda_3 ratio" +#: ../src/backend/filters/dataLoad.cpp:46 +msgid "Text Data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:706 -msgid "No clusters had sufficient dimensionality to compute singular values" +#: ../src/backend/filters/dataLoad.cpp:225 +msgid " does not exist" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:763 -msgid "Found :" +#: ../src/backend/filters/dataLoad.cpp:262 +#: ../src/backend/filters/dataLoad.cpp:273 +#: ../src/backend/filters/dataLoad.cpp:293 +#: ../src/backend/filters/dataLoad.cpp:305 +msgid "Error loading file: " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:765 -msgid " clusters" +#: ../src/backend/filters/dataLoad.cpp:319 +msgid "Data file contained incorrect number of columns -- should be 4, was " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:833 -msgid "Compositions (fractional, core+bulk)" +#: ../src/backend/filters/dataLoad.cpp:372 +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/filters/clusterAnalysis.cpp:835 -msgid "Compositions (fractional, core only)" +#: ../src/backend/filters/dataLoad.cpp:379 +msgid "Loaded " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:853 -msgid "Frequencies (core+bulk)" +#: ../src/backend/filters/dataLoad.cpp:379 +msgid " Points" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:881 -msgid "Core Link + Erode" +#: ../src/backend/filters/dataLoad.cpp:407 +#: ../src/backend/filters/rangeFile.cpp:504 +msgid "File" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:889 -msgid "Cluster algorithm mode" +#: ../src/backend/filters/dataLoad.cpp:408 +msgid "File from which to load data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:898 -msgid "Core Classify Dist" +#: ../src/backend/filters/dataLoad.cpp:419 +msgid "File type" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:901 -msgid "Restrict only atoms by distance to be cluster sources" +#: ../src/backend/filters/dataLoad.cpp:421 +msgid "Type of file to be loaded" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:906 -msgid "Classify Knn Max" +#: ../src/backend/filters/dataLoad.cpp:435 +msgid "Entries per point" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:909 -msgid "" -"Require that the kth NN (this number) is within the classify distance, to be " -"a cluster source" +#: ../src/backend/filters/dataLoad.cpp:436 +msgid "Number of decimal values in file per 3D point (normally 4)" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:914 -msgid "Core Link Dist" +#: ../src/backend/filters/dataLoad.cpp:464 +msgid "Relative offset of each entry in file for point's X position" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:917 -msgid "Distance between clusters to allow linking" +#: ../src/backend/filters/dataLoad.cpp:472 +msgid "Relative offset of each entry in file for point's Y position" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:922 -msgid "Bulk Link (Envelope) Dist" +#: ../src/backend/filters/dataLoad.cpp:480 +msgid "Relative offset of each entry in file for point's Z position" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:925 +#: ../src/backend/filters/dataLoad.cpp:488 msgid "" -"Distance from core points that form cluster that is used to grab surrounding " -"bulk points" +"Relative offset of each entry in file to use for scalar value of 3D point" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:930 -msgid "Erode Dist" +#: ../src/backend/filters/dataLoad.cpp:491 +msgid "Value Label" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:933 -msgid "" -"Distance from unclustered material in which bulk points are eroded from " -"cluster" +#: ../src/backend/filters/dataLoad.cpp:495 +msgid "Name for the scalar value associated with each point" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:938 -msgid "Clustering Params" +#: ../src/backend/filters/dataLoad.cpp:498 +msgid "Format params." msgstr "" -#: ../src/filters/clusterAnalysis.cpp:945 -msgid "Count bulk" +#: ../src/backend/filters/dataLoad.cpp:504 +msgid "Enabled" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:948 -msgid "Include bulk ions in size distribution." +#: ../src/backend/filters/dataLoad.cpp:508 +msgid "Load this file?" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:954 -msgid "Size Cropping" +#: ../src/backend/filters/dataLoad.cpp:516 +msgid "Sample data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:957 -msgid "Perform removal of clusters based upon size distribution" +#: ../src/backend/filters/dataLoad.cpp:519 +msgid "" +"Perform random selection on file contents, instead of loading entire file" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:964 -msgid "Min Size" +#: ../src/backend/filters/dataLoad.cpp:526 +msgid "Load Limit (MB)" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:967 -msgid "Remove clusters below this size" +#: ../src/backend/filters/dataLoad.cpp:529 +msgid "Limit for size of data to load" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:972 -msgid "Max Size" +#: ../src/backend/filters/dataLoad.cpp:535 +msgid "Monitor" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:975 -msgid "Remove clusters above this size" +#: ../src/backend/filters/dataLoad.cpp:539 +msgid "" +"Watch file timestamp to track changes to file contents from other programs" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:984 -msgid "Show number of clusters as a function of cluster size" +#: ../src/backend/filters/dataLoad.cpp:541 +msgid "Load params." msgstr "" -#: ../src/filters/clusterAnalysis.cpp:989 -msgid "Log Scale" +#: ../src/backend/filters/dataLoad.cpp:551 +msgid "Default colour " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:992 -msgid "Use logarithmic scale for size distribution" +#: ../src/backend/filters/dataLoad.cpp:554 +msgid "Default colour for points, if not overridden by other filters" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:998 -msgid "Morphology Dist." +#: ../src/backend/filters/dataLoad.cpp:559 +msgid "Draw Size" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1001 -msgid "Create a plot showing cluster aspect ratio data" +#: ../src/backend/filters/dataLoad.cpp:562 +msgid "Default size for points, if not overridden by other filters" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1005 -msgid "Chemistry Dist." +#: ../src/backend/filters/spectrumPlot.cpp:125 +msgid "Extrema" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1008 -msgid "Create a plot showing chemistry for each cluster size" +#: ../src/backend/filters/spectrumPlot.cpp:174 +msgid "count" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1018 -msgid "Convert cluster counts to composition" +#: ../src/backend/filters/spectrumPlot.cpp:259 +msgid "Mixed data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1024 -msgid "Postprocess" +#: ../src/backend/filters/spectrumPlot.cpp:399 +msgid "Step size for spectrum" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1043 -msgid "If selected, use as \"core\" ion type (can make clusters)" +#: ../src/backend/filters/spectrumPlot.cpp:408 +msgid "Auto Min/max" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1048 -msgid "Core Ranges" +#: ../src/backend/filters/spectrumPlot.cpp:412 +msgid "Automatically compute spectrum upper and lower bound" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1060 -msgid "" -"If selected, use as \"bulk\" ion type (can be included in existing clusters)" +#: ../src/backend/filters/spectrumPlot.cpp:417 +msgid "Min" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1065 -msgid "Bulk Ranges" +#: ../src/backend/filters/spectrumPlot.cpp:420 +msgid "Starting position for spectrum" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1080 -msgid "Max. Sep + Erode" +#: ../src/backend/filters/spectrumPlot.cpp:425 +msgid "Max" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1719 -msgid "Clustering aborted" +#: ../src/backend/filters/spectrumPlot.cpp:428 +msgid "Ending position for spectrum" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1721 -msgid "No core ions for cluster" +#: ../src/backend/filters/spectrumPlot.cpp:436 +msgid "Logarithmic" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1723 -msgid "No bulk ions for cluster" +#: ../src/backend/filters/spectrumPlot.cpp:439 +msgid "Convert the plot to logarithmic mode" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1796 -msgid " --------------------------- Parameter selection notice ------------- " +#: ../src/backend/filters/spectrumPlot.cpp:461 +msgid "Visual style of plot" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1797 -msgid "You have specified a bulk distance larger than half your link distance." +#: ../src/backend/filters/spectrumPlot.cpp:474 +msgid "Colour of plotted spectrum" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1798 -msgid "" -"You can do this; thats OK, but the output is no longer independent of the " -"computational process;" +#: ../src/backend/filters/spectrumPlot.cpp:708 +msgid "Insufficient memory for spectrum filter." msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1799 -msgid "" -"This will be a problem in the case where two or more clusters can equally " -"lay claim to a \"bulk\" ion. " +#: ../src/backend/filters/spectrumPlot.cpp:710 +msgid "Bad bincount value in spectrum filter." msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1800 -msgid "" -" If your inter-cluster distance is sufficiently large (larger than your bulk " -"linking distance), then you can get away with this." +#: ../src/backend/filters/rangeFile.cpp:146 +msgid "Pre-Allocate" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1801 -msgid "" -" In theory it is possible to \"join\" the clusters, but this has not been " -"implemented for speed reasons." +#: ../src/backend/filters/rangeFile.cpp:260 ../src/backend/filter.cpp:46 +msgid "Range" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1802 -msgid "" -"If you want this, please contact the author, or just use the source to add " -"this in yourself." +#: ../src/backend/filters/rangeFile.cpp:506 +msgid "File to use for range data" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1803 -msgid "---------------------------------------------------------------------- " +#: ../src/backend/filters/rangeFile.cpp:518 +msgid "Drop unranged" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1832 -msgid "Build Core" +#: ../src/backend/filters/rangeFile.cpp:520 +msgid "Remove unranged points when generating output" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1850 -msgid "Classify Core" +#: ../src/backend/filters/rangeFile.cpp:540 +msgid "All Ions" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1943 -msgid "Build Bulk" +#: ../src/backend/filters/rangeFile.cpp:541 +msgid "Enable/disable all ions at once" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1963 -msgid "Core" +#: ../src/backend/filters/rangeFile.cpp:549 +msgid "Species" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2108 -msgid "Bulk" +#: ../src/backend/filters/rangeFile.cpp:556 +msgid "IonID " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2237 -msgid "Erode" +#: ../src/backend/filters/rangeFile.cpp:557 +msgid "Enable/disable specified ion" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2311 -msgid "Re-Collate" +#: ../src/backend/filters/rangeFile.cpp:570 +msgid "Active Ion " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2579 -#: ../src/filters/clusterAnalysis.cpp:2805 -msgid "Cluster Size" +#: ../src/backend/filters/rangeFile.cpp:572 +msgid "If true, ion is used in output" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2580 -#: ../src/filters/clusterAnalysis.cpp:2809 -msgid "Frequency" +#: ../src/backend/filters/rangeFile.cpp:586 +msgid "Colour " msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2807 -msgid "Composition" +#: ../src/backend/filters/rangeFile.cpp:589 +msgid "Colour used to represent ion" msgstr "" -#: ../src/glPane.cpp:638 -msgid "Use shift/ctrl-space or double tap to alter reset axis" +#: ../src/backend/filters/rangeFile.cpp:613 +msgid "All Ranges" msgstr "" -#: ../src/glPane.cpp:900 -msgid "Image progress" +#: ../src/backend/filters/rangeFile.cpp:614 +msgid "Enable/disable all ranges" msgstr "" -#: ../src/glPane.cpp:901 -msgid "Rendering tiles..." +#: ../src/backend/filters/rangeFile.cpp:632 +msgid "Active Rng " msgstr "" -#: ../src/glPane.cpp:917 -msgid "Tile " +#: ../src/backend/filters/rangeFile.cpp:635 +msgid "" +"Enable/disable specified range (ion must also be enabled to activiate range)" msgstr "" -#: ../src/glPane.cpp:1049 -msgid "Animation progress" +#: ../src/backend/filters/rangeFile.cpp:639 +msgid "Ion " msgstr "" -#: ../src/glPane.cpp:1050 -msgid "Rendering sequence..." +#: ../src/backend/filters/rangeFile.cpp:642 +msgid "Name of ion associate to this range" msgstr "" -#: ../src/glPane.cpp:1082 -msgid "Saving Image " +#: ../src/backend/filters/rangeFile.cpp:651 +msgid "Start rng " msgstr "" -#: ../src/filtertree.cpp:902 -msgid "WARNING: Skipping node " +#: ../src/backend/filters/rangeFile.cpp:654 +msgid "Start value for range" msgstr "" -#: ../src/filtertree.cpp:902 -msgid " as it was not recognised" +#: ../src/backend/filters/rangeFile.cpp:659 +msgid "End rng " msgstr "" -#: ../src/filtertree.cpp:940 -msgid "Error processing node: " +#: ../src/backend/filters/rangeFile.cpp:662 +msgid "Stopping value for range`" msgstr "" -#: ../src/filter.cpp:50 -msgid "Draw" +#: ../src/backend/filters/rangeFile.cpp:966 +msgid "Ranging aborted by user" msgstr "" -#: ../src/filter.cpp:52 -msgid "Voxel" +#: ../src/backend/filters/rangeFile.cpp:968 +msgid "Insufficient memory for range" msgstr "" -#: ../src/filtertreeAnalyse.cpp:78 +#: ../src/backend/filtertreeAnalyse.cpp:93 msgid "" "Parent filter has no output, but filter requires input -- there is no point " "in placing a child filter here." msgstr "" -#: ../src/filtertreeAnalyse.cpp:79 +#: ../src/backend/filtertreeAnalyse.cpp:94 msgid "Leaf-only filter with child" msgstr "" -#: ../src/filtertreeAnalyse.cpp:89 +#: ../src/backend/filtertreeAnalyse.cpp:104 msgid "" "Parent filters' output will be blocked by child, without use. Parent results " "will be dropped." msgstr "" -#: ../src/filtertreeAnalyse.cpp:90 ../src/filtertreeAnalyse.cpp:104 +#: ../src/backend/filtertreeAnalyse.cpp:105 +#: ../src/backend/filtertreeAnalyse.cpp:119 msgid "Bad parent->child pair" msgstr "" -#: ../src/filtertreeAnalyse.cpp:103 +#: ../src/backend/filtertreeAnalyse.cpp:118 msgid "" "First filter does not output anything useable by child filter. Child filter " "not useful." msgstr "" -#: ../src/filtertreeAnalyse.cpp:274 +#: ../src/backend/filtertreeAnalyse.cpp:291 msgid "Spatial results possibly altered" msgstr "" -#: ../src/filtertreeAnalyse.cpp:275 +#: ../src/backend/filtertreeAnalyse.cpp:292 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/filtertreeAnalyse.cpp:435 +#: ../src/backend/filtertreeAnalyse.cpp:453 msgid "Composition results possibly altered" msgstr "" -#: ../src/filtertreeAnalyse.cpp:436 +#: ../src/backend/filtertreeAnalyse.cpp:454 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/APTClasses.cpp:165 +#: ../src/backend/APT/APTClasses.cpp:32 msgid "Memory allocation failure on POS load" msgstr "" -#: ../src/APTClasses.cpp:166 +#: ../src/backend/APT/APTClasses.cpp:33 msgid "Error opening pos file" msgstr "" -#: ../src/APTClasses.cpp:167 +#: ../src/backend/APT/APTClasses.cpp:34 msgid "Pos file empty" msgstr "" -#: ../src/APTClasses.cpp:168 +#: ../src/backend/APT/APTClasses.cpp:35 msgid "Pos file size appears to have non-integer number of entries" msgstr "" -#: ../src/APTClasses.cpp:169 +#: ../src/backend/APT/APTClasses.cpp:36 msgid "Error reading from pos file (after open)" msgstr "" -#: ../src/APTClasses.cpp:170 +#: ../src/backend/APT/APTClasses.cpp:37 msgid "Error - Found NaN in pos file" msgstr "" -#: ../src/APTClasses.cpp:171 +#: ../src/backend/APT/APTClasses.cpp:38 msgid "Pos load aborted by interrupt." msgstr "" -#: ../src/APTClasses.cpp:188 +#: ../src/backend/APT/APTClasses.cpp:55 msgid "No numerical data found" msgstr "" -#: ../src/APTClasses.cpp:189 +#: ../src/backend/APT/APTClasses.cpp:56 msgid "Error re-opening file, after first scan" msgstr "" -#: ../src/APTClasses.cpp:190 +#: ../src/backend/APT/APTClasses.cpp:57 msgid "Unable to read file contents after open" msgstr "" -#: ../src/APTClasses.cpp:192 +#: ../src/backend/APT/APTClasses.cpp:59 msgid "Incorrect number of fields in file" msgstr "" -#: ../src/APTClasses.cpp:193 +#: ../src/backend/APT/APTClasses.cpp:60 msgid "Unable to allocate memory to store data" msgstr "" -#: ../src/APTClasses.cpp:198 +#: ../src/backend/APT/APTRanges.cpp:42 msgid "Error opening file, check name and permissions." msgstr "" -#: ../src/APTClasses.cpp:199 +#: ../src/backend/APT/APTRanges.cpp:43 msgid "" "Error interpreting range file header, expecting ion count and range count, " "respectively." msgstr "" -#: ../src/APTClasses.cpp:200 +#: ../src/backend/APT/APTRanges.cpp:44 msgid "" "Range file appears to be empty, check file is a proper range file and is not " "empty." msgstr "" -#: ../src/APTClasses.cpp:201 +#: ../src/backend/APT/APTRanges.cpp:45 msgid "Error reading the long name for ion." msgstr "" -#: ../src/APTClasses.cpp:202 +#: ../src/backend/APT/APTRanges.cpp:46 msgid "Error reading the short name for ion." msgstr "" -#: ../src/APTClasses.cpp:203 +#: ../src/backend/APT/APTRanges.cpp:47 msgid "" "Error reading colour data in the file, expecting 3 decimal values, space " "separated." msgstr "" -#: ../src/APTClasses.cpp:204 +#: ../src/backend/APT/APTRanges.cpp:48 msgid "" "Tried skipping to table separator line (line with dashes), but did not find " "it." msgstr "" -#: ../src/APTClasses.cpp:205 +#: ../src/backend/APT/APTRanges.cpp:49 msgid "" "Unexpected failure whilst trying to skip over range lead-in data (bit before " "range start value)" msgstr "" -#: ../src/APTClasses.cpp:206 +#: ../src/backend/APT/APTRanges.cpp:50 +msgid "" +"Range table had an incorrect number of entries, should be 2 or 3 + number of " +"ranges" +msgstr "" + +#: ../src/backend/APT/APTRanges.cpp:51 msgid "Unable to read range start and end values" msgstr "" -#: ../src/APTClasses.cpp:207 +#: ../src/backend/APT/APTRanges.cpp:52 msgid "Unable to read range table entry" msgstr "" -#: ../src/APTClasses.cpp:208 +#: ../src/backend/APT/APTRanges.cpp:53 msgid "" "Error reading file, unexpected format, are you sure it is a proper range " "file?" msgstr "" -#: ../src/APTClasses.cpp:209 +#: ../src/backend/APT/APTRanges.cpp:54 msgid "" "Too many ranges appeared to have range entries with no usable data (eg, all " "blank)" msgstr "" -#: ../src/APTClasses.cpp:210 +#: ../src/backend/APT/APTRanges.cpp:55 msgid "" "Range file appears to contain malformed data, check things like start and " "ends of m/c are not equal or flipped." msgstr "" -#: ../src/APTClasses.cpp:211 +#: ../src/backend/APT/APTRanges.cpp:56 msgid "Range file appears to be inconsistent (eg, overlapping ranges)" msgstr "" -#: ../src/APTClasses.cpp:212 +#: ../src/backend/APT/APTRanges.cpp:57 msgid "No ion name mapping found for multiple ion." msgstr "" -#: ../src/APTClasses.cpp:1554 +#: ../src/backend/APT/APTRanges.cpp:811 msgid "" "Range headings do not match order of the ions listed in the name " "specifications. The name specification ordering will be used when reading " @@ -4417,60 +4572,46 @@ "Check range-species associations actually match what you expect." msgstr "" -#: ../src/mathglPane.cpp:201 -msgid "No plots selected." +#: ../src/backend/filter.cpp:45 +msgid "Draw" msgstr "" -#: ../src/mathglPane.cpp:1063 -msgid "" -"Unable to allocate requested memory.\n" -" Try a lower resolution, or save as vector (SVG)." +#: ../src/backend/filter.cpp:47 +msgid "Voxel" msgstr "" -#: ../src/mathglPane.cpp:1065 -msgid "Plotting functions returned an error:\n" +#: ../src/backend/filters/transform.h:71 +msgid "Ion. Transform" msgstr "" -#: ../src/mathglPane.cpp:1067 -msgid "File readback check failed" +#: ../src/backend/filters/ionColour.h:60 +msgid "Spectral Colour" msgstr "" -#: ../src/mathglPane.cpp:1069 -msgid "Filesize during readback appears to be zero." +#: ../src/backend/filters/boundingBox.h:72 +msgid "Bound box" msgstr "" -#: ../src/filters/ionInfo.h:74 -msgid "Ion info" +#: ../src/backend/filters/ionDownsample.h:79 +msgid "Ion Sampler" msgstr "" -#: ../src/filters/dataLoad.h:114 -msgid "Pos Data" +#: ../src/backend/filters/ionInfo.h:91 +msgid "Ion info" msgstr "" -#: ../src/filters/ionDownsample.h:63 -msgid "Ion Sampler" +#: ../src/backend/filters/dataLoad.h:131 +msgid "Pos Data" msgstr "" -#: ../src/filters/ionColour.h:43 -msgid "Spectral Colour" +#: ../src/backend/filters/externalProgram.h:56 +msgid "Ext. Program" msgstr "" -#: ../src/filters/rangeFile.h:62 +#: ../src/backend/filters/rangeFile.h:79 msgid "Ranging" msgstr "" -#: ../src/filters/transform.h:54 -msgid "Ion. Transform" -msgstr "" - -#: ../src/filters/compositionProfile.h:86 +#: ../src/backend/filters/compositionProfile.h:110 msgid "Comp. Prof." msgstr "" - -#: ../src/filters/boundingBox.h:55 -msgid "Bound box" -msgstr "" - -#: ../src/filters/externalProgram.h:39 -msgid "Ext. Program" -msgstr "" Binary files /tmp/arveZAt5b_/3depict-0.0.12/translations/3Depict_de_DE.mo and /tmp/ZSARKCsiTI/3depict-0.0.13/translations/3Depict_de_DE.mo differ diff -Nru 3depict-0.0.12/translations/3Depict_de_DE.po 3depict-0.0.13/translations/3Depict_de_DE.po --- 3depict-0.0.12/translations/3Depict_de_DE.po 2012-11-24 21:10:10.000000000 +0000 +++ 3depict-0.0.13/translations/3Depict_de_DE.po 2013-04-05 21:34:28.000000000 +0000 @@ -10,775 +10,1496 @@ msgstr "" "Project-Id-Version: 3Depict\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-07-16 01:27+0100\n" +"POT-Creation-Date: 2013-04-05 23:27+0200\n" "PO-Revision-Date: 2012-07-09 08:21+0000\n" "Last-Translator: epix1234 \n" "Language-Team: German (Germany) (http://www.transifex.com/projects/p/3depict/" "language/de_DE/)\n" +"Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: ../src/configFile.cpp:190 -msgid "Config file present, but is not valid (root node test)" -msgstr "Konfigurationsdatei vorhanden, aber nicht gültig (root node test)" - -#: ../src/configFile.cpp:231 -msgid "Unable to interpret recent file entry" -msgstr "Kann den letzten Dateieintrag nicht interpretieren" - -#: ../src/configFile.cpp:271 -msgid "Unable to determine filter type in defaults listing." -msgstr "Kann den Filtertyp im Defaultslisting nicht bestimmen." - -#: ../src/configFile.cpp:572 -msgid "Online access for non win32/apple platforms is intentionally disabled, " -msgstr "" -"Onlinezugang für nicht Win32/apple systeme wurde absichtlich deaktiviert." - -#: ../src/configFile.cpp:573 -msgid "" -"regardless of the settings you use here. Use your package manager to keep up-" -"to-date" -msgstr "" -"Nutzen Sie Ihren Paketmanager um up-to-date zu sein unabhängig von den " -"Einstellungen die Sie hier verwenden" - -#: ../src/colourmap.cpp:234 -msgid "Jet" -msgstr "Jet" - -#: ../src/colourmap.cpp:235 -msgid "Hot" -msgstr "Heiss" - -#: ../src/colourmap.cpp:236 -msgid "Cold" -msgstr "Kalt" - -#: ../src/colourmap.cpp:237 -msgid "Grey" -msgstr "Grau" - -#: ../src/colourmap.cpp:238 -msgid "Cyclic" -msgstr "Cyclic" - -#: ../src/colourmap.cpp:239 -msgid "General" -msgstr "Allgemein" - -#: ../src/colourmap.cpp:240 -msgid "Blue" -msgstr "Blau" - -#: ../src/colourmap.cpp:241 -msgid "Pseudo-Random" -msgstr "Pseudo-Random" - -#: ../src/cameras.cpp:695 ../src/cameras.cpp:697 +#: ../src/gl/cameras.cpp:688 ../src/gl/cameras.cpp:690 msgid "Lock" msgstr "Sperren" -#: ../src/cameras.cpp:704 ../src/filters/ionClip.cpp:693 -#: ../src/filters/ionClip.cpp:709 ../src/filters/ionClip.cpp:725 -#: ../src/filters/ionClip.cpp:753 ../src/filters/compositionProfile.cpp:899 -#: ../src/filters/transform.cpp:1108 ../src/filters/transform.cpp:1123 -#: ../src/filters/transform.cpp:1141 ../src/filters/annotation.cpp:535 +#: ../src/gl/cameras.cpp:697 ../src/backend/filters/ionClip.cpp:523 +#: ../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/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 msgid "Origin" msgstr "Ursprung" -#: ../src/cameras.cpp:709 ../src/filters/spatialAnalysis.cpp:1455 +#: ../src/gl/cameras.cpp:702 ../src/backend/filters/spatialAnalysis.cpp:511 msgid "Target" msgstr "Ziel" -#: ../src/cameras.cpp:714 +#: ../src/gl/cameras.cpp:707 msgid "Up Dir." msgstr "Up Dir." -#: ../src/cameras.cpp:722 ../src/cameras.cpp:826 +#: ../src/gl/cameras.cpp:715 ../src/gl/cameras.cpp:819 msgid "Perspective" msgstr "Perspektivisch" -#: ../src/cameras.cpp:724 ../src/cameras.cpp:828 +#: ../src/gl/cameras.cpp:717 ../src/gl/cameras.cpp:821 msgid "Orthogonal" msgstr "Orthogonal" -#: ../src/cameras.cpp:728 +#: ../src/gl/cameras.cpp:721 msgid "Projection" msgstr "Projektion" -#: ../src/cameras.cpp:736 +#: ../src/gl/cameras.cpp:729 msgid "Field of View (deg)" msgstr "Bildausschnitt" -#: ../src/cameras.cpp:742 +#: ../src/gl/cameras.cpp:735 msgid "View size" msgstr "Anzeigegröße" -#: ../src/basics.cpp:56 ../src/APTClasses.cpp:187 +#: ../src/wxcomponents.cpp:428 ../src/gui/dialogs/ExportRngDialog.cpp:88 +#: ../src/gui/dialogs/prefDialog.cpp:108 +msgid "Param" +msgstr "Param." + +#: ../src/wxcomponents.cpp:429 ../src/gui/dialogs/ExportRngDialog.cpp:89 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:105 +#: ../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 +msgid "Value" +msgstr "Wert" + +#: ../src/wxcomponents.cpp:641 +msgid "Save Data..." +msgstr "Datei speichern..." + +#: ../src/wxcomponents.cpp:642 +msgid "Text File (*.txt)|*.txt|All Files (*)|*" +msgstr "Text Datei (*.txt)|*.txt|Alle Dateien (*)|*" + +#: ../src/wxcomponents.cpp:654 +msgid "Error saving file. Check output dir is writable." +msgstr "" +"Fehler beim Schreiben der Datei. Stellen Sie sicher, dass das " +"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 +msgid "Save error" +msgstr "Fehler speichern" + +#: ../src/common/basics.cpp:52 ../src/backend/APT/APTClasses.cpp:54 msgid "Error opening file" msgstr "Fehler beim Öffnen der Datei" -#: ../src/basics.cpp:57 +#: ../src/common/basics.cpp:53 msgid "Error whilst reading file contents" msgstr "Fehler beim Lesen des Dateiinhaltes" -#: ../src/basics.cpp:58 ../src/APTClasses.cpp:191 +#: ../src/common/basics.cpp:54 ../src/backend/APT/APTClasses.cpp:58 msgid "Error interpreting field in file" msgstr "Fehler beim Interpretieren eine Feldes in der Datei" -#: ../src/basics.cpp:59 +#: ../src/common/basics.cpp:55 msgid "Inconsistent number of columns found" msgstr "Inkonsistente Anzahl an Spalten gefunden" -#: ../src/basics.cpp:709 +#: ../src/common/basics.cpp:167 msgid "in the future?" msgstr "in Zukunft?" -#: ../src/basics.cpp:760 +#: ../src/common/basics.cpp:218 msgid "a decade ago" msgstr "vor zehn Jahren" -#: ../src/basics.cpp:761 +#: ../src/common/basics.cpp:219 msgid "a year ago" msgstr "vor einem Jahr" -#: ../src/basics.cpp:762 +#: ../src/common/basics.cpp:220 msgid "a month ago" msgstr "vor einem Monat" -#: ../src/basics.cpp:763 +#: ../src/common/basics.cpp:221 msgid "a week ago" msgstr "vor einer Woche" -#: ../src/basics.cpp:764 +#: ../src/common/basics.cpp:222 msgid "a day ago" msgstr "gestern" -#: ../src/basics.cpp:765 +#: ../src/common/basics.cpp:223 msgid "an hour ago" msgstr "vor einer Stunde" -#: ../src/basics.cpp:766 +#: ../src/common/basics.cpp:224 msgid "45 minutes ago" msgstr "vor 45 Minuten" -#: ../src/basics.cpp:767 +#: ../src/common/basics.cpp:225 msgid "30 minutes ago" msgstr "vor 30 Minuten" -#: ../src/basics.cpp:768 +#: ../src/common/basics.cpp:226 msgid "20 minutes ago" msgstr "vor 20 Minuten" -#: ../src/basics.cpp:769 +#: ../src/common/basics.cpp:227 msgid "15 minutes ago" msgstr "vor 15 Minuten" -#: ../src/basics.cpp:770 +#: ../src/common/basics.cpp:228 msgid "10 minutes ago" msgstr "vor 10 Minuten" -#: ../src/basics.cpp:771 +#: ../src/common/basics.cpp:229 msgid "5 minutes ago" msgstr "vor 5 Minuten" -#: ../src/basics.cpp:772 +#: ../src/common/basics.cpp:230 msgid "a minute ago" msgstr "vor einer Minute" -#: ../src/basics.cpp:773 +#: ../src/common/basics.cpp:231 msgid "30 seconds ago" msgstr "vor 30 Sekunden" -#: ../src/basics.cpp:774 +#: ../src/common/basics.cpp:232 msgid "10 seconds ago" msgstr "vor 10 Sekunden" -#: ../src/basics.cpp:775 +#: ../src/common/basics.cpp:233 msgid "a second ago" msgstr "vor einer Sekunde" -#: ../src/basics.cpp:780 +#: ../src/common/basics.cpp:238 msgid "a few decades ago" msgstr "vor einigen Dekaden" -#: ../src/basics.cpp:781 +#: ../src/common/basics.cpp:239 msgid "a few years ago" msgstr "vor einigen Jahren" -#: ../src/basics.cpp:782 +#: ../src/common/basics.cpp:240 msgid "a few months ago" msgstr "vor einigen Monaten" -#: ../src/basics.cpp:783 +#: ../src/common/basics.cpp:241 msgid "a few weeks ago" msgstr "vor einigen Wochen" -#: ../src/basics.cpp:784 +#: ../src/common/basics.cpp:242 msgid "a few days ago" msgstr "vor einigen Tagen" -#: ../src/basics.cpp:785 +#: ../src/common/basics.cpp:243 msgid "a few hours ago" msgstr "vor einigen Stunden" -#: ../src/basics.cpp:792 +#: ../src/common/basics.cpp:250 msgid "a few minutes ago" msgstr "vor einigen Minuten" -#: ../src/basics.cpp:795 +#: ../src/common/basics.cpp:253 msgid "a few seconds ago" msgstr "vor einigen Sekunden" -#: ../src/basics.cpp:822 +#: ../src/common/basics.cpp:280 msgid "moments ago" msgstr "kürzlich" -#: ../src/3Depict.cpp:153 -msgid "New camera name..." -msgstr "Neuer Kameraname..." +#: ../src/common/colourmap.cpp:234 +msgid "Jet" +msgstr "Jet" -#: ../src/3Depict.cpp:154 -msgid "New stash name...." -msgstr "Neuer Stashname..." +#: ../src/common/colourmap.cpp:235 +msgid "Hot" +msgstr "Heiss" -#: ../src/3Depict.cpp:171 ../src/filters/annotation.cpp:530 -#: ../src/filters/annotation.cpp:602 ../src/filters/annotation.h:81 -msgid "Annotation" -msgstr "Kommentar" +#: ../src/common/colourmap.cpp:236 +msgid "Cold" +msgstr "Kalt" -#: ../src/3Depict.cpp:172 -msgid "Bounding Box" -msgstr "Begrenzungs-Box" +#: ../src/common/colourmap.cpp:237 +msgid "Grey" +msgstr "Grau" -#: ../src/3Depict.cpp:173 ../src/filters/ionClip.h:49 -msgid "Clipping" -msgstr "Zuschneiden" +#: ../src/common/colourmap.cpp:238 +msgid "Cyclic" +msgstr "Cyclic" -#: ../src/3Depict.cpp:174 ../src/filters/clusterAnalysis.h:113 -msgid "Cluster Analysis" -msgstr "Clusteranalyse" +#: ../src/common/colourmap.cpp:239 +msgid "General" +msgstr "Allgemein" -#: ../src/3Depict.cpp:175 -msgid "Compos. Profiles" -msgstr "Konz.Profil" +#: ../src/common/colourmap.cpp:240 +msgid "Blue" +msgstr "Blau" -#: ../src/3Depict.cpp:176 -msgid "Downsampling" -msgstr "Datenreduktion" +#: ../src/common/colourmap.cpp:241 +msgid "Pseudo-Random" +msgstr "Pseudo-Random" -#: ../src/3Depict.cpp:177 -msgid "Extern. Prog." -msgstr "Ext. Progr." +#: ../src/gui/glPane.cpp:635 +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/3Depict.cpp:178 -msgid "Ion Colour" -msgstr "Ionenfarbe" +#: ../src/gui/glPane.cpp:893 +msgid "Image progress" +msgstr "Bild Fortschritt" -#: ../src/3Depict.cpp:179 -msgid "Ion Info" -msgstr "Ion Info" +#: ../src/gui/glPane.cpp:894 +msgid "Rendering tiles..." +msgstr "Rendering tiles..." -#: ../src/3Depict.cpp:180 -msgid "Ion Transform" -msgstr "Ionentransform." +#: ../src/gui/glPane.cpp:910 +msgid "Tile " +msgstr "Tile " -#: ../src/3Depict.cpp:181 ../src/filters/spectrumPlot.h:36 -msgid "Spectrum" -msgstr "Spektrum" +#: ../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 +msgid " of " +msgstr " von " -#: ../src/3Depict.cpp:182 -msgid "Range File" -msgstr "Rangedatei" +#: ../src/gui/glPane.cpp:1043 +msgid "Animation progress" +msgstr "Animation-Fortschritt" -#: ../src/3Depict.cpp:183 ../src/filters/spatialAnalysis.h:73 -msgid "Spat. Analysis" -msgstr "Räumliche Analyse" +#: ../src/gui/glPane.cpp:1044 +msgid "Rendering sequence..." +msgstr "Renderreihenfolge..." -#: ../src/3Depict.cpp:184 ../src/filters/voxelise.h:72 -msgid "Voxelisation" -msgstr "Voxelisation" +#: ../src/gui/glPane.cpp:1077 +msgid "Saving Image " +msgstr "Speichere Bild " -#: ../src/3Depict.cpp:469 ../src/3Depict.cpp:475 -msgid "" -"Unable to initialise the openGL (3D) panel. Program cannot start. Please " -"check your video drivers." -msgstr "" -"Kann das OpenGL (3D)-Panel nicht initialisieren. Das Programm kann nicht " -"gestartet werden. Bitte überprüfen Sie Ihren Video-Treiber." +#: ../src/gui/dialogs/ExportRngDialog.cpp:40 +msgid "Range Sources" +msgstr "Range Sources" -#: ../src/3Depict.cpp:470 -msgid "OpenGL Failed" -msgstr "OpenGL fehlgeschlagen" +#: ../src/gui/dialogs/ExportRngDialog.cpp:42 +msgid "Details" +msgstr "Details" -#: ../src/3Depict.cpp:494 -msgid "&Open...\tCtrl+O" -msgstr "&Öffnen...\tCtrl+O" +#: ../src/gui/dialogs/ExportRngDialog.cpp:53 +msgid "Source Filter" +msgstr "Source Filter" -#: ../src/3Depict.cpp:494 -msgid "Open state file" -msgstr "Statusdatei öffnen" +#: ../src/gui/dialogs/ExportRngDialog.cpp:54 +msgid "Ions" +msgstr "Ionen" -#: ../src/3Depict.cpp:495 -msgid "&Merge...\tCtrl+Shift+O" -msgstr "&Zusammenführen...\tCtrl+Shift+O" +#: ../src/gui/dialogs/ExportRngDialog.cpp:55 +#: ../src/backend/filters/rangeFile.cpp:666 +msgid "Ranges" +msgstr "Ranges" -#: ../src/3Depict.cpp:495 -msgid "Merge other file" -msgstr "Merge other file" +#: ../src/gui/dialogs/ExportRngDialog.cpp:90 +msgid "Value2" +msgstr "Wert2" -#: ../src/3Depict.cpp:499 -msgid "&Recent" -msgstr "&Letzte" +#: ../src/gui/dialogs/ExportRngDialog.cpp:97 +msgid "Ion Name" +msgstr "Ionenname" -#: ../src/3Depict.cpp:500 -msgid "&Save\tCtrl+S" -msgstr "&Speichern\tCtrl+S" +#: ../src/gui/dialogs/ExportRngDialog.cpp:98 +msgid "Num Ranges" +msgstr "Num Ranges" -#: ../src/3Depict.cpp:500 -msgid "Save state to file" -msgstr "Status in Datei speichern" +#: ../src/gui/dialogs/ExportRngDialog.cpp:116 ../src/backend/filter.cpp:43 +msgid "Ion" +msgstr "Ion" -#: ../src/3Depict.cpp:502 -msgid "Save &As...\tCtrl+Shift+S" -msgstr "Speichern &als...\tCtrl+Shift+S" +#: ../src/gui/dialogs/ExportRngDialog.cpp:117 +msgid "Range Start" +msgstr "Range Anfang" -#: ../src/3Depict.cpp:502 -msgid "Save current state to new file" -msgstr "Aktuellen Status als neue Datei speichern" +#: ../src/gui/dialogs/ExportRngDialog.cpp:118 +msgid "Range end" +msgstr "Range Ende" -#: ../src/3Depict.cpp:505 -msgid "&Plot...\tCtrl+P" -msgstr "&Plot...\tCtrl+P" +#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2090 +msgid "Save pos..." +msgstr "pos speichern..." -#: ../src/3Depict.cpp:505 -msgid "Export Current Plot" -msgstr "Aktuellen Plot exportieren" +#: ../src/gui/dialogs/ExportRngDialog.cpp:152 +msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*" +msgstr "ORNL Format RNG (*.rng)|*.rng|Alle Dateien (*)|*" -#: ../src/3Depict.cpp:506 -msgid "&Image...\tCtrl+I" -msgstr "&Bild...\tCtrl+I" +#: ../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 +msgid "Unable to save. Check output destination can be written to." +msgstr "" +"Speichern nicht möglich. Bitte überprüfen Sie ob der Ausgabepfad " +"schreibgeschützt ist." -#: ../src/3Depict.cpp:506 -msgid "Export Current 3D View" -msgstr "Aktuelle 3D Ansicht exportieren" +#: ../src/gui/dialogs/ExportRngDialog.cpp:236 +msgid "Export Range" +msgstr "Range exportieren" -#: ../src/3Depict.cpp:507 -msgid "Ion&s...\tCtrl+N" -msgstr "Ion&en...\tCtrl+N" +#: ../src/gui/dialogs/ExportRngDialog.cpp:241 +msgid "List of rangefiles in filter tree" +msgstr "Liste der Rangedateien im Filterbaum" -#: ../src/3Depict.cpp:507 -msgid "Export Ion Data" -msgstr "Ionendaten exportieren" +#: ../src/gui/dialogs/ExportRngDialog.cpp:243 +msgid "Detailed view of selected range" +msgstr "Detailierte Ansicht des ausgewählten Range" -#: ../src/3Depict.cpp:508 -msgid "Ran&ges...\tCtrl+G" -msgstr "Ran&ges...\tCtrl+G" +#: ../src/gui/dialogs/autosaveDialog.cpp:39 +msgid "Remove &All" +msgstr "" -#: ../src/3Depict.cpp:508 -msgid "Export Range Data" -msgstr "Rangedaten exportieren" +#: ../src/gui/dialogs/autosaveDialog.cpp:123 +msgid "Restore state?" +msgstr "" -#: ../src/3Depict.cpp:509 -msgid "Ani&mation...\tCtrl+M" -msgstr "Ani&mation...\tCtrl+M" +#: ../src/gui/dialogs/autosaveDialog.cpp:133 +msgid "Multiple autosave states were found; would you like to restore one?" +msgstr "" -#: ../src/3Depict.cpp:509 -msgid "Export Animation" -msgstr "Animation exportieren" +#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:392 +#: ../src/backend/filter.cpp:395 +msgid "Error" +msgstr "" -#: ../src/3Depict.cpp:510 -msgid "Pac&kage...\tCtrl+K" -msgstr "Pa&ket...\tCtrl+K" +#: ../src/gui/dialogs/filterErrorDialog.cpp:39 +msgid "Warning" +msgstr "" -#: ../src/3Depict.cpp:510 -msgid "Export analysis package" -msgstr "Analysepaket exportieren" +#: ../src/gui/dialogs/filterErrorDialog.cpp:42 +#: ../src/gui/dialogs/filterErrorDialog.cpp:52 +msgid "Filter Errors" +msgstr "" -#: ../src/3Depict.cpp:512 -msgid "&Export" -msgstr "&Exportieren" +#: ../src/gui/dialogs/StashDialog.cpp:44 +msgid "Stashes" +msgstr "" -#: ../src/3Depict.cpp:515 -msgid "&Quit\tCtrl+Q" -msgstr "&Beenden\tCtrl+Q" +#: ../src/gui/dialogs/StashDialog.cpp:47 +msgid "Stashed Tree" +msgstr "" -#: ../src/3Depict.cpp:515 ../src/3Depict.cpp:517 -msgid "Exit Program" -msgstr "Programm beenden" +#: ../src/gui/dialogs/StashDialog.cpp:49 +msgid "Properties" +msgstr "" -#: ../src/3Depict.cpp:517 -msgid "E&xit" -msgstr "E&xit" +#: ../src/gui/dialogs/StashDialog.cpp:85 +msgid "Stashed Trees" +msgstr "Stashed Trees" -#: ../src/3Depict.cpp:519 -msgid "&File" -msgstr "&Datei" +#: ../src/gui/dialogs/StashDialog.cpp:88 +msgid "Erase stashed item" +msgstr "" -#: ../src/3Depict.cpp:522 -msgid "&Background Colour...\tCtrl+B" -msgstr "&Hintergrundfarbe...\tCtrl+B" +#: ../src/gui/dialogs/StashDialog.cpp:89 +msgid "Filter view for current stash" +msgstr "Filteransicht für den aktuellen Stash" -#: ../src/3Depict.cpp:522 -msgid "Change background colour" -msgstr "Hintergrundfarbe ändern" +#: ../src/gui/dialogs/StashDialog.cpp:90 +msgid "Settings for selected filter in current stash" +msgstr "Einstellungen für den ausgewählten Stash" -#: ../src/3Depict.cpp:526 -msgid "&Control Pane\tF3" -msgstr "&Kontrollfenster\tF3" +#: ../src/gui/dialogs/StashDialog.cpp:91 +msgid "Available stashes" +msgstr "Verfügbare Stash" -#: ../src/3Depict.cpp:526 ../src/3Depict.cpp:529 -msgid "Toggle left control pane" -msgstr "Linkes Kontrollfenster ein/aus schalten" +#: ../src/gui/dialogs/StashDialog.cpp:152 +msgid "Stash Name" +msgstr "Stash Name" -#: ../src/3Depict.cpp:529 -msgid "&Control Pane\tAlt+C" -msgstr "&Kontrollfenster\tAlt+C" +#: ../src/gui/dialogs/StashDialog.cpp:153 +msgid "Filter Count" +msgstr "Filter Count" -#: ../src/3Depict.cpp:535 -msgid "&Raw Data Pane\tF4" -msgstr "&Rohdatenfenster\tF4" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:45 +msgid "Start Frame: " +msgstr "" -#: ../src/3Depict.cpp:535 ../src/3Depict.cpp:538 -msgid "Toggle raw data pane (bottom)" -msgstr "Rohdatenfenster (unten)" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:47 +msgid "From File" +msgstr "" -#: ../src/3Depict.cpp:538 -msgid "&Raw Data Pane\tAlt+R" -msgstr "&Rohdatenfenster\tAlt+R" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:50 +msgid "From Table" +msgstr "" -#: ../src/3Depict.cpp:542 -msgid "&Plot List\tF5" -msgstr "&Plot Liste\tF5" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:104 +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:350 +#: ../src/gui/dialogs/animateFilterDialog.cpp:191 +msgid "Frame" +msgstr "" -#: ../src/3Depict.cpp:542 ../src/3Depict.cpp:544 -msgid "Toggle plot list" -msgstr "Plotliste ein/aus schalten" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:240 +msgid "Select text file..." +msgstr "" -#: ../src/3Depict.cpp:544 -msgid "&Plot List\tAlt+P" -msgstr "&Plot Liste\tAlt+P" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:241 +msgid "Text files (*.txt)|*.txt;|All Files (*)|*" +msgstr "" -#: ../src/3Depict.cpp:550 -msgid "&Legend\tCtrl+L" -msgstr "&Legende\tCtrl+L" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:342 +msgid "String Keyframes" +msgstr "" -#: ../src/3Depict.cpp:550 -msgid "Toggle Legend display" -msgstr "Legende anzeigen ein/aus" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:344 +msgid "Frame at which to start string sequence" +msgstr "" -#: ../src/3Depict.cpp:552 -msgid "P&lot..." -msgstr "P&lot..." +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:345 +msgid "Frame offset for data start" +msgstr "" -#: ../src/3Depict.cpp:553 -msgid "&Axis\tCtrl+Shift+I" -msgstr "&Achsen\tCtrl+Shift+I" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:346 +msgid "File to use as string data source, one value per row" +msgstr "" -#: ../src/3Depict.cpp:553 -msgid "Toggle World Axis display" -msgstr "Hauptachsen ein/aus schalten" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:347 +msgid "Select file to use as data source" +msgstr "" -#: ../src/3Depict.cpp:558 -msgid "&Fullscreen mode\tF11" -msgstr "&Vollbildmodus\tF11" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:348 +msgid "Use table below for data source" +msgstr "" -#: ../src/3Depict.cpp:558 ../src/3Depict.cpp:560 -msgid "Next fullscreen mode: with toolbars" -msgstr "Nächster Vollbildmodus: ohne Werkzeugleisten" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:354 +msgid "Add new data rows to table, hold shift/cmd to insert multiple rows" +msgstr "" -#: ../src/3Depict.cpp:560 -msgid "&Fullscreen mode\tCtrl+Shift+F" -msgstr "&Vollbildmodus\tCtrl+Shift+F" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:355 +msgid "Remove selected strings from table" +msgstr "" -#: ../src/3Depict.cpp:565 -msgid "&Undo\tCtrl+Z" -msgstr "&Zurück\tCtrl+Z" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:356 +msgid "Abort value selection and return to previous window" +msgstr "" -#: ../src/3Depict.cpp:567 -msgid "&Redo\tCtrl+Y" -msgstr "&Wiederholen\tCtrl+Y" +#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:357 +msgid "Accept data values" +msgstr "" -#: ../src/3Depict.cpp:570 -msgid "&Preferences" -msgstr "&Voreinstellungen" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:56 +msgid "Keyframe Data" +msgstr "" -#: ../src/3Depict.cpp:572 -msgid "&Edit" -msgstr "&Bearbeiten" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:57 +msgid "Transition" +msgstr "" -#: ../src/3Depict.cpp:575 -msgid "&View" -msgstr "&Ansicht" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:60 +msgid "Step" +msgstr "" -#: ../src/3Depict.cpp:577 -msgid "&Help...\tCtrl+H" -msgstr "&Hilfe...\tCtrl+H" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:61 +msgid "Ramp" +msgstr "" -#: ../src/3Depict.cpp:577 -msgid "Show help files and documentation" -msgstr "Hilfedateien und Dokumentation anzeigen" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:64 +#: ../src/gui/dialogs/animateFilterDialog.cpp:1115 +msgid "Start Frame" +msgstr "" -#: ../src/3Depict.cpp:578 -msgid "&Contact..." -msgstr "&Kontakt..." +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:66 +#: ../src/gui/dialogs/animateFilterDialog.cpp:1116 +msgid "End Frame" +msgstr "" -#: ../src/3Depict.cpp:578 -msgid "Open contact page" -msgstr "Kontaktseite öffnen" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:69 +msgid "Initial Value" +msgstr "" -#: ../src/3Depict.cpp:580 -msgid "&About..." -msgstr "Über 3Depict..." +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:70 +msgid "startColour" +msgstr "" -#: ../src/3Depict.cpp:580 -msgid "Information about this program" -msgstr "Informationen zu diesem Programm" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:71 +msgid "Final Value" +msgstr "" -#: ../src/3Depict.cpp:581 -msgid "&Help" -msgstr "&Hilfe" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:72 +msgid "endColour" +msgstr "" -#: ../src/3Depict.cpp:583 -msgid "Stashed Filters" -msgstr "Zwischengelagerte Filter" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:235 +msgid "Key Frame : Colour" +msgstr "" -#: ../src/3Depict.cpp:588 -msgid "Data Filtering" -msgstr "Daten filtern" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:237 +msgid "Colour at the start of the transtition" +msgstr "" -#: ../src/3Depict.cpp:612 -msgid "Last Outputs" -msgstr "Letzte Ausgabe" +#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:238 +msgid "Colour at end of transition" +msgstr "" -#: ../src/3Depict.cpp:614 -msgid "Auto Refresh" +#: ../src/gui/dialogs/animateFilterDialog.cpp:91 +msgid "Oak-Ridge RNG" msgstr "" -"Autom.\n" -"aktualisieren" -#: ../src/3Depict.cpp:620 -msgid "Filter settings" -msgstr "Filtereinstellungen" +#: ../src/gui/dialogs/animateFilterDialog.cpp:92 +msgid "Cameca/Ametek RRNG" +msgstr "" -#: ../src/3Depict.cpp:622 -msgid "Camera Name" -msgstr "Kameraname" +#: ../src/gui/dialogs/animateFilterDialog.cpp:93 +msgid "Cameca/Ametek ENV" +msgstr "" -#: ../src/3Depict.cpp:628 -msgid "3D Post-processing" -msgstr "3D Nachbearbeitung" +#: ../src/gui/dialogs/animateFilterDialog.cpp:151 +msgid "Key frames" +msgstr "" -#: ../src/3Depict.cpp:630 -msgid "Enable Cropping" -msgstr "Zuschneiden aktivieren" +#: ../src/gui/dialogs/animateFilterDialog.cpp:152 +msgid "Output Data" +msgstr "" -#: ../src/3Depict.cpp:632 ../src/3Depict.cpp:643 -msgid "x-y" -msgstr "x-y" +#: ../src/gui/dialogs/animateFilterDialog.cpp:153 +msgid "Filters and properties" +msgstr "" -#: ../src/3Depict.cpp:633 ../src/3Depict.cpp:644 -msgid "x-z" -msgstr "x-z" +#: ../src/gui/dialogs/animateFilterDialog.cpp:159 +msgid "Dir : " +msgstr "" -#: ../src/3Depict.cpp:634 ../src/3Depict.cpp:645 -msgid "y-x" -msgstr "y-x" +#: ../src/gui/dialogs/animateFilterDialog.cpp:162 +msgid "Output only when refresh required" +msgstr "" -#: ../src/3Depict.cpp:635 ../src/3Depict.cpp:646 -msgid "y-z" -msgstr "y-z" +#: ../src/gui/dialogs/animateFilterDialog.cpp:164 +msgid "Data Types:" +msgstr "" -#: ../src/3Depict.cpp:636 ../src/3Depict.cpp:647 -msgid "z-x" -msgstr "z-x" +#: ../src/gui/dialogs/animateFilterDialog.cpp:165 +msgid "3D Images" +msgstr "" -#: ../src/3Depict.cpp:637 ../src/3Depict.cpp:648 -msgid "z-y" -msgstr "z-y" +#: ../src/gui/dialogs/animateFilterDialog.cpp:166 +msgid "File Prefix: " +msgstr "" -#: ../src/3Depict.cpp:652 -msgid "Use camera coordinates" -msgstr "Verwende Kamerakoordinaten" +#: ../src/gui/dialogs/animateFilterDialog.cpp:168 +msgid "Size : " +msgstr "" -#: ../src/3Depict.cpp:653 -msgid "dX" -msgstr "dX" +#: ../src/gui/dialogs/animateFilterDialog.cpp:170 +msgid "..." +msgstr "" -#: ../src/3Depict.cpp:655 -msgid "dY" -msgstr "dY" +#: ../src/gui/dialogs/animateFilterDialog.cpp:171 +msgid "Point data" +msgstr "" -#: ../src/3Depict.cpp:657 -msgid "dZ" -msgstr "dZ" +#: ../src/gui/dialogs/animateFilterDialog.cpp:172 +msgid "Plots" +msgstr "" -#: ../src/3Depict.cpp:659 -msgid "Enable Anaglyphic Stereo" -msgstr "Anaglyphic Stereo aktivieren" +#: ../src/gui/dialogs/animateFilterDialog.cpp:173 +msgid "Voxel data" +msgstr "" -#: ../src/3Depict.cpp:660 -msgid "Flip Channels" -msgstr "Kanäle tauschen" +#: ../src/gui/dialogs/animateFilterDialog.cpp:174 +msgid "Range files" +msgstr "" -#: ../src/3Depict.cpp:661 -msgid "Anaglyph Mode" -msgstr "Anaglyphmodus" +#: ../src/gui/dialogs/animateFilterDialog.cpp:175 +msgid "Format" +msgstr "" -#: ../src/3Depict.cpp:663 -msgid "Red-Blue" -msgstr "Rot-Blau" +#: ../src/gui/dialogs/animateFilterDialog.cpp:638 +msgid "transition frame" +msgstr "" -#: ../src/3Depict.cpp:664 -msgid "Red-Green" -msgstr "Rot-Grün" +#: ../src/gui/dialogs/animateFilterDialog.cpp:638 +#: ../src/gui/mainFrame.cpp:1538 +msgid "Frame count" +msgstr "Bildanzahl" -#: ../src/3Depict.cpp:665 -msgid "Red-Cyan" -msgstr "Rot-Zyan" +#: ../src/gui/dialogs/animateFilterDialog.cpp:710 +msgid "Key frame : Colour" +msgstr "" -#: ../src/3Depict.cpp:666 -msgid "Green-Magenta" -msgstr "Grün-Magenta" +#: ../src/gui/dialogs/animateFilterDialog.cpp:763 +msgid "File existed, but was unable to read or interpret file contents." +msgstr "" -#: ../src/3Depict.cpp:670 -msgid "Baseline Separation" -msgstr "Basislinienabstand" +#: ../src/gui/dialogs/animateFilterDialog.cpp:764 +msgid "String load failed" +msgstr "" -#: ../src/3Depict.cpp:672 -msgid "Smooth && translucent objects" -msgstr "Glatte && durchsichtige Objekte" +#: ../src/gui/dialogs/animateFilterDialog.cpp:785 +msgid "Keyframe : decimal" +msgstr "" -#: ../src/3Depict.cpp:674 -msgid "3D lighting" -msgstr "3D Beleuchtung" +#: ../src/gui/dialogs/animateFilterDialog.cpp:794 +msgid "Keyframe : integer" +msgstr "" -#: ../src/3Depict.cpp:676 -msgid "Fast and weak randomisation." -msgstr "Schnelle aber schwache Randomisierung" +#: ../src/gui/dialogs/animateFilterDialog.cpp:803 +msgid "Keyframe : 3D Point" +msgstr "" -#: ../src/3Depict.cpp:678 -msgid "Filter caching" -msgstr "Filter zwischenspeichern" +#: ../src/gui/dialogs/animateFilterDialog.cpp:929 +msgid "Select or create new folder" +msgstr "" -#: ../src/3Depict.cpp:680 -msgid "Max. Ram usage (%)" -msgstr "Max. RAM-Nutzung (%)" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1105 +msgid "Export Animation" +msgstr "Animation exportieren" -#: ../src/3Depict.cpp:684 ../src/dialogs/prefDialog.cpp:88 -msgid "Plot List" -msgstr "Plotliste" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1106 +msgid "Select filter" +msgstr "" -#: ../src/3Depict.cpp:734 ../src/filters/transform.cpp:1061 -msgid "Type" -msgstr "Type" +#: ../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 +msgid "Property" +msgstr "Eigenschaft" -#: ../src/3Depict.cpp:735 -msgid "Num" -msgstr "Num" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1110 +msgid "Select property" +msgstr "" -#: ../src/3Depict.cpp:800 -msgid "Warning: Your configuration file appears to be invalid:\n" -msgstr "Warnung: Ihre Konfigurationsdatei scheint ungültig zu sein.\n" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1112 +#: ../src/gui/dialogs/animateFilterDialog.cpp:1132 +msgid "Filter" +msgstr "" -#: ../src/3Depict.cpp:801 -msgid "\tConfig Load: " -msgstr "\tConfig Load: " +#: ../src/gui/dialogs/animateFilterDialog.cpp:1114 +#: ../src/backend/filters/transform.cpp:1180 +#: ../src/backend/filters/annotation.cpp:535 +msgid "Mode" +msgstr "" -#: ../src/3Depict.cpp:1035 ../src/3Depict.cpp:1085 -msgid "Select Data or State File..." -msgstr "Daten oder Statusdatei auswählen..." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1117 +msgid "Keyframe table" +msgstr "" -#: ../src/3Depict.cpp:1036 -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 (*)|*" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1118 +msgid "Remove the selected keyframe from the table" msgstr "" -"Lesbare Dateien (*.xml, *.pos, *.txt,*.csv)|*.xml;*.pos;*.txt;*.csv|POS " -"Datei (*.pos)|*.pos|XML Status Datei (*.xml)|*.xml|Text Dateien (*.txt/csv)|" -"*.txt;*.csv|Alle Dateien (*)|*" -#: ../src/3Depict.cpp:1070 ../src/3Depict.cpp:1454 -msgid "Loaded file." -msgstr "Loaded file." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1119 +msgid "Enter where the animation frames will be exported to" +msgstr "" -#: ../src/3Depict.cpp:1086 -msgid "" -"3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|" -"XML State File (*.xml)|*.xml|All Files (*)|*" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1120 +msgid "Browse to directory where the animation frames will be exported to" msgstr "" -"3Depictdateien (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS Datei (*.pos)|*." -"pos|XML Status Datei (*.xml)|*.xml|All Files (*)|*" -#: ../src/3Depict.cpp:1105 -msgid "Merged file." -msgstr "Datei zusammengeführt." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1122 +msgid "Enter a descriptive name for output files" +msgstr "" -#: ../src/3Depict.cpp:1222 -msgid "Tip: You can use ⌘ (command) to merge" -msgstr "Tip: Sie können ⌘ (command) zum Zusammenführen verwenden" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1123 +msgid "Enter the target resoltuion (image size)" +msgstr "" -#: ../src/3Depict.cpp:1224 -msgid "Tip: You can use ctrl to merge" -msgstr "Tip: Sie können strg zum Zusammen führen verwenden" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1125 +msgid "Select frame for property display" +msgstr "" -#: ../src/3Depict.cpp:1273 -msgid "" -"Error loading state file.\n" -"See console for more info." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1126 +msgid "Enter frame number to change frame (eg 1/20)" msgstr "" -"Fehler beim Laden der Statusdatei.\n" -"Konsole für mehr Informationen." -#: ../src/3Depict.cpp:1274 -msgid "Load error" -msgstr "Fehler beim Laden" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1127 +msgid "Save point data (POS files) in output folder?" +msgstr "" -#: ../src/3Depict.cpp:1298 -msgid "" -"This state file contains filters that can be unsafe to run\n" -"Do you wish to remove these before continuing?." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1128 +msgid "Save plots (as text files) in output folder?" msgstr "" -"Diese Statusdatei enthält Filter deren Anwendung möglicherweise unsicher " -"ist. Wollen Sie diese entfernen." -#: ../src/3Depict.cpp:1299 -msgid "Security warning" -msgstr "Sicherheitswarnung" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1129 +msgid "Save voxel data (raw files) in output folder?" +msgstr "" -#: ../src/3Depict.cpp:1489 ../src/3Depict.cpp:1640 ../src/3Depict.cpp:1733 -#: ../src/3Depict.cpp:1825 ../src/3Depict.cpp:1942 ../src/3Depict.cpp:2064 -#: ../src/dialogs/ExportRngDialog.cpp:167 -msgid "Unable to save. Check output destination can be written to." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1130 +msgid "Save range files in output folder?" msgstr "" -"Speichern nicht möglich. Bitte überprüfen Sie ob der Ausgabepfad " -"schreibgeschützt ist." -#: ../src/3Depict.cpp:1492 ../src/3Depict.cpp:1587 ../src/3Depict.cpp:1643 -#: ../src/3Depict.cpp:1736 ../src/3Depict.cpp:1828 ../src/3Depict.cpp:1845 -#: ../src/3Depict.cpp:1945 ../src/3Depict.cpp:2067 -#: ../src/dialogs/ExportRngDialog.cpp:170 ../src/wxcomponents.cpp:497 -msgid "Save error" -msgstr "Fehler speichern" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1135 +msgid "Animation parameters for current frame" +msgstr "" -#: ../src/3Depict.cpp:1517 -msgid "No plot available. Please create a plot before exporting." -msgstr "Kein Plot vefügbar. Plot muss vor dem Exportieren erzeugt werden." +#: ../src/gui/dialogs/animateFilterDialog.cpp:1136 +msgid "Abort animation" +msgstr "" -#: ../src/3Depict.cpp:1519 ../src/3Depict.cpp:1573 -msgid "Unable to save" -msgstr "Speichern nicht möglich" +#: ../src/gui/dialogs/animateFilterDialog.cpp:1137 +msgid "Run Animation" +msgstr "" + +#: ../src/gui/dialogs/animateFilterDialog.cpp:1208 +msgid "Filter view" +msgstr "" + +#: ../src/gui/dialogs/animateFilterDialog.cpp:1209 +msgid "Frame view" +msgstr "" + +#: ../src/gui/dialogs/resolutionDialog.cpp:46 +msgid "Width :" +msgstr "" + +#: ../src/gui/dialogs/resolutionDialog.cpp:48 +msgid "Height :" +msgstr "" + +#: ../src/gui/dialogs/resolutionDialog.cpp:50 +msgid "Lock Aspect" +msgstr "" + +#: ../src/gui/dialogs/resolutionDialog.cpp:54 +#: ../src/gui/dialogs/prefDialog.cpp:82 +msgid "Reset" +msgstr "Zurücksetzen" + +#: ../src/gui/dialogs/resolutionDialog.cpp:462 +msgid "Resolution Selection" +msgstr "" + +#: ../src/gui/dialogs/ExportPos.cpp:75 +msgid "Export:" +msgstr "Exportieren:" + +#: ../src/gui/dialogs/ExportPos.cpp:76 +#: ../src/backend/filters/boundingBox.cpp:528 +msgid "Visible" +msgstr "Sichtbar" + +#: ../src/gui/dialogs/ExportPos.cpp:77 +msgid "Selected Data" +msgstr "Daten auswählen" + +#: ../src/gui/dialogs/ExportPos.cpp:79 +msgid "Available Data" +msgstr "Verfügbare Daten" + +#: ../src/gui/dialogs/ExportPos.cpp:85 +msgid "Selection" +msgstr "Auswahl" + +#: ../src/gui/dialogs/ExportPos.cpp:110 ../src/gui/dialogs/ExportPos.cpp:113 +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/spectrumPlot.cpp:240 +msgid "Count" +msgstr "Anzahl" + +#: ../src/gui/dialogs/ExportPos.cpp:450 +msgid "Export Pos Data" +msgstr "POS Daten exportieren" + +#: ../src/gui/dialogs/ExportPos.cpp:453 +msgid "Tree of filters, select leaves to show ion data." +msgstr "" + +#: ../src/gui/dialogs/ExportPos.cpp:455 +msgid "Add all data from all filters" +msgstr "" + +#: ../src/gui/dialogs/ExportPos.cpp:456 +msgid "Add all data from currently selected filter" +msgstr "" + +#: ../src/gui/dialogs/ExportPos.cpp:457 +msgid "Add selected data from currently selected filter" +msgstr "" + +#: ../src/gui/dialogs/prefDialog.cpp:66 ../src/gui/dialogs/prefDialog.cpp:541 +msgid "Preferences" +msgstr "Voreinstellungen" + +#: ../src/gui/dialogs/prefDialog.cpp:73 +msgid "Online Updates" +msgstr "Online Updates" + +#: ../src/gui/dialogs/prefDialog.cpp:75 +msgid "Panel Display" +msgstr "Panel Display" + +#: ../src/gui/dialogs/prefDialog.cpp:76 +msgid "Camera Speed" +msgstr "Kamerageschwindigkeit" + +#: ../src/gui/dialogs/prefDialog.cpp:77 +msgid "Filter Defaults" +msgstr "Filtervoreinstellungen" + +#: ../src/gui/dialogs/prefDialog.cpp:78 +msgid "Available Filters" +msgstr "Verfügbare Filter" + +#: ../src/gui/dialogs/prefDialog.cpp:81 +msgid "Reset All" +msgstr "Alle zurücksetzen" + +#: ../src/gui/dialogs/prefDialog.cpp:84 +msgid "Show all panels" +msgstr "Zeige alle Fenster" + +#: ../src/gui/dialogs/prefDialog.cpp:85 +msgid "Remember last" +msgstr "Zuletzt verwendet" + +#: ../src/gui/dialogs/prefDialog.cpp:86 +msgid "Show Selected" +msgstr "Zeige Auswahl" + +#: ../src/gui/dialogs/prefDialog.cpp:89 +msgid "Control Pane" +msgstr "Kontrollfenster" + +#: ../src/gui/dialogs/prefDialog.cpp:90 +msgid "Raw Data Panel" +msgstr "Rohdatenfenster" + +#: ../src/gui/dialogs/prefDialog.cpp:91 ../src/gui/mainFrame.cpp:618 +msgid "Plot List" +msgstr "Plotliste" + +#: ../src/gui/dialogs/prefDialog.cpp:93 +msgid "Periodically notify about available updates" +msgstr "" + +#: ../src/gui/dialogs/prefDialog.cpp:95 +msgid "Move Rate" +msgstr "Bewegungsgeschwindigkeit" + +#: ../src/gui/dialogs/prefDialog.cpp:96 ../src/gui/dialogs/prefDialog.cpp:100 +msgid "(slow)" +msgstr "(langsam)" + +#: ../src/gui/dialogs/prefDialog.cpp:98 ../src/gui/dialogs/prefDialog.cpp:102 +msgid "(fast)" +msgstr "(schnell)" + +#: ../src/gui/dialogs/prefDialog.cpp:99 +msgid "Zoom Rate" +msgstr "Zoomgeschwindigkeit" + +#: ../src/gui/dialogs/prefDialog.cpp:449 +msgid "Notice" +msgstr "Notiz" + +#: ../src/gui/dialogs/prefDialog.cpp:452 +msgid "For security reasons, defaults are not modifiable for this filter" +msgstr "" +"Aus Sicherheitsgründen können die Voreinstellungen für diesen Filter nicht " +"geändert werden." + +#: ../src/gui/dialogs/prefDialog.cpp:482 +msgid "Show all panels when starting program" +msgstr "Zeige alle Fenster beim Programmstart" + +#: ../src/gui/dialogs/prefDialog.cpp:485 +msgid "Show panels visible at last shutdown when starting program" +msgstr "Beim Programmstart zuletzt eingeschaltete Fenster anzeigen." + +#: ../src/gui/dialogs/prefDialog.cpp:492 +msgid "Show selected panels when starting program" +msgstr "Zeige ausgewählte Fenster beim Programmstart" + +#: ../src/gui/dialogs/prefDialog.cpp:543 +msgid "Set the method of panel layout when starting the program" +msgstr "" + +#: ../src/gui/dialogs/prefDialog.cpp:546 +msgid "" +"Lets the program check the internet to see if updates to the program version " +"are available, then notifies you about updates now and again." +msgstr "" +"Lässt das Programm via Internet überprüfen ob Updates für diese " +"Programmversion verfügbar sind. Danach informiert es über die neuen Updates." + +#: ../src/gui/dialogs/prefDialog.cpp:548 +msgid "Camera translation, orbit and swivel rates. " +msgstr "" + +#: ../src/gui/dialogs/prefDialog.cpp:549 +msgid "Camera zooming rate." +msgstr "Zoomgeschwindigkeit der Kamera" + +#: ../src/gui/dialogs/prefDialog.cpp:551 +msgid "Reset the filter initial values back to program defaults" +msgstr "" + +#: ../src/gui/dialogs/prefDialog.cpp:552 +msgid "Reset all filter initial values back to program defaults" +msgstr "" + +#: ../src/gui/dialogs/prefDialog.cpp:614 +msgid "Pref" +msgstr "Pref" + +#: ../src/gui/dialogs/prefDialog.cpp:615 +msgid "Startup" +msgstr "Startup" + +#: ../src/gui/dialogs/prefDialog.cpp:616 +msgid "Camera" +msgstr "Kamera" + +#: ../src/gui/mainFrame.cpp:88 +msgid "New camera name..." +msgstr "Neuer Kameraname..." + +#: ../src/gui/mainFrame.cpp:89 +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 +msgid "Annotation" +msgstr "Kommentar" + +#: ../src/gui/mainFrame.cpp:106 +msgid "Bounding Box" +msgstr "Begrenzungs-Box" + +#: ../src/gui/mainFrame.cpp:107 ../src/backend/filters/ionClip.h:66 +msgid "Clipping" +msgstr "Zuschneiden" + +#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/clusterAnalysis.h:132 +msgid "Cluster Analysis" +msgstr "Clusteranalyse" + +#: ../src/gui/mainFrame.cpp:109 +msgid "Compos. Profiles" +msgstr "Konz.Profil" + +#: ../src/gui/mainFrame.cpp:110 +msgid "Downsampling" +msgstr "Datenreduktion" + +#: ../src/gui/mainFrame.cpp:111 +msgid "Extern. Prog." +msgstr "Ext. Progr." + +#: ../src/gui/mainFrame.cpp:112 +msgid "Ion Colour" +msgstr "Ionenfarbe" + +#: ../src/gui/mainFrame.cpp:113 +msgid "Ion Info" +msgstr "Ion Info" + +#: ../src/gui/mainFrame.cpp:114 +msgid "Ion Transform" +msgstr "Ionentransform." + +#: ../src/gui/mainFrame.cpp:115 ../src/backend/filters/spectrumPlot.h:53 +msgid "Spectrum" +msgstr "Spektrum" + +#: ../src/gui/mainFrame.cpp:116 +msgid "Range File" +msgstr "Rangedatei" + +#: ../src/gui/mainFrame.cpp:117 ../src/backend/filters/spatialAnalysis.h:142 +msgid "Spat. Analysis" +msgstr "Räumliche Analyse" + +#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/voxelise.h:89 +msgid "Voxelisation" +msgstr "Voxelisation" + +#: ../src/gui/mainFrame.cpp:403 +msgid "OpenGL Failed" +msgstr "OpenGL fehlgeschlagen" + +#: ../src/gui/mainFrame.cpp:404 ../src/gui/mainFrame.cpp:406 +msgid "" +"Unable to initialise the openGL (3D) panel. Program cannot start. Please " +"check your video drivers." +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 +msgid "&Open...\tCtrl+O" +msgstr "&Öffnen...\tCtrl+O" + +#: ../src/gui/mainFrame.cpp:426 +msgid "Open state file" +msgstr "Statusdatei öffnen" + +#: ../src/gui/mainFrame.cpp:427 +msgid "&Merge...\tCtrl+Shift+O" +msgstr "&Zusammenführen...\tCtrl+Shift+O" + +#: ../src/gui/mainFrame.cpp:427 +msgid "Merge other file" +msgstr "Merge other file" + +#: ../src/gui/mainFrame.cpp:431 +msgid "&Recent" +msgstr "&Letzte" + +#: ../src/gui/mainFrame.cpp:432 +msgid "&Save\tCtrl+S" +msgstr "&Speichern\tCtrl+S" + +#: ../src/gui/mainFrame.cpp:432 +msgid "Save state to file" +msgstr "Status in Datei speichern" + +#: ../src/gui/mainFrame.cpp:434 +msgid "Save &As...\tCtrl+Shift+S" +msgstr "Speichern &als...\tCtrl+Shift+S" + +#: ../src/gui/mainFrame.cpp:434 +msgid "Save current state to new file" +msgstr "Aktuellen Status als neue Datei speichern" + +#: ../src/gui/mainFrame.cpp:437 +msgid "&Plot...\tCtrl+P" +msgstr "&Plot...\tCtrl+P" + +#: ../src/gui/mainFrame.cpp:437 +msgid "Export Current Plot" +msgstr "Aktuellen Plot exportieren" + +#: ../src/gui/mainFrame.cpp:438 +msgid "&Image...\tCtrl+I" +msgstr "&Bild...\tCtrl+I" + +#: ../src/gui/mainFrame.cpp:438 +msgid "Export Current 3D View" +msgstr "Aktuelle 3D Ansicht exportieren" + +#: ../src/gui/mainFrame.cpp:439 +msgid "Ion&s...\tCtrl+N" +msgstr "Ion&en...\tCtrl+N" + +#: ../src/gui/mainFrame.cpp:439 +msgid "Export Ion Data" +msgstr "Ionendaten exportieren" + +#: ../src/gui/mainFrame.cpp:440 +msgid "Ran&ges...\tCtrl+G" +msgstr "Ran&ges...\tCtrl+G" + +#: ../src/gui/mainFrame.cpp:440 +msgid "Export Range Data" +msgstr "Rangedaten exportieren" + +#: ../src/gui/mainFrame.cpp:441 +msgid "&Animate Filters...\tCtrl+A" +msgstr "" + +#: ../src/gui/mainFrame.cpp:441 +msgid "Export Animated Filter" +msgstr "" + +#: ../src/gui/mainFrame.cpp:442 +msgid "Ani&mate Camera...\tCtrl+M" +msgstr "" + +#: ../src/gui/mainFrame.cpp:442 +msgid "Export Animated Camera" +msgstr "" + +#: ../src/gui/mainFrame.cpp:443 +msgid "Pac&kage...\tCtrl+K" +msgstr "Pa&ket...\tCtrl+K" + +#: ../src/gui/mainFrame.cpp:443 +msgid "Export analysis package" +msgstr "Analysepaket exportieren" + +#: ../src/gui/mainFrame.cpp:445 +msgid "&Export" +msgstr "&Exportieren" + +#: ../src/gui/mainFrame.cpp:448 +msgid "&Quit\tCtrl+Q" +msgstr "&Beenden\tCtrl+Q" + +#: ../src/gui/mainFrame.cpp:448 ../src/gui/mainFrame.cpp:450 +msgid "Exit Program" +msgstr "Programm beenden" + +#: ../src/gui/mainFrame.cpp:450 +msgid "E&xit" +msgstr "E&xit" + +#: ../src/gui/mainFrame.cpp:452 +msgid "&File" +msgstr "&Datei" + +#: ../src/gui/mainFrame.cpp:456 +msgid "&Background Colour...\tCtrl+B" +msgstr "&Hintergrundfarbe...\tCtrl+B" + +#: ../src/gui/mainFrame.cpp:456 +msgid "Change background colour" +msgstr "Hintergrundfarbe ändern" + +#: ../src/gui/mainFrame.cpp:460 +msgid "&Control Pane\tF3" +msgstr "&Kontrollfenster\tF3" + +#: ../src/gui/mainFrame.cpp:460 ../src/gui/mainFrame.cpp:463 +msgid "Toggle left control pane" +msgstr "Linkes Kontrollfenster ein/aus schalten" + +#: ../src/gui/mainFrame.cpp:463 +msgid "&Control Pane\tAlt+C" +msgstr "&Kontrollfenster\tAlt+C" + +#: ../src/gui/mainFrame.cpp:469 +msgid "&Raw Data Pane\tF4" +msgstr "&Rohdatenfenster\tF4" + +#: ../src/gui/mainFrame.cpp:469 ../src/gui/mainFrame.cpp:472 +msgid "Toggle raw data pane (bottom)" +msgstr "Rohdatenfenster (unten)" + +#: ../src/gui/mainFrame.cpp:472 +msgid "&Raw Data Pane\tAlt+R" +msgstr "&Rohdatenfenster\tAlt+R" + +#: ../src/gui/mainFrame.cpp:476 +msgid "&Plot List\tF5" +msgstr "&Plot Liste\tF5" + +#: ../src/gui/mainFrame.cpp:476 ../src/gui/mainFrame.cpp:478 +msgid "Toggle plot list" +msgstr "Plotliste ein/aus schalten" + +#: ../src/gui/mainFrame.cpp:478 +msgid "&Plot List\tAlt+P" +msgstr "&Plot Liste\tAlt+P" + +#: ../src/gui/mainFrame.cpp:484 +msgid "&Legend\tCtrl+L" +msgstr "&Legende\tCtrl+L" + +#: ../src/gui/mainFrame.cpp:484 +msgid "Toggle Legend display" +msgstr "Legende anzeigen ein/aus" + +#: ../src/gui/mainFrame.cpp:486 +msgid "P&lot..." +msgstr "P&lot..." + +#: ../src/gui/mainFrame.cpp:487 +msgid "&Axis\tCtrl+Shift+I" +msgstr "&Achsen\tCtrl+Shift+I" + +#: ../src/gui/mainFrame.cpp:487 +msgid "Toggle World Axis display" +msgstr "Hauptachsen ein/aus schalten" + +#: ../src/gui/mainFrame.cpp:492 +msgid "&Fullscreen mode\tF11" +msgstr "&Vollbildmodus\tF11" + +#: ../src/gui/mainFrame.cpp:492 ../src/gui/mainFrame.cpp:494 +msgid "Next fullscreen mode: with toolbars" +msgstr "Nächster Vollbildmodus: ohne Werkzeugleisten" + +#: ../src/gui/mainFrame.cpp:494 +msgid "&Fullscreen mode\tCtrl+Shift+F" +msgstr "&Vollbildmodus\tCtrl+Shift+F" + +#: ../src/gui/mainFrame.cpp:499 +msgid "&Undo\tCtrl+Z" +msgstr "&Zurück\tCtrl+Z" + +#: ../src/gui/mainFrame.cpp:501 +msgid "&Redo\tCtrl+Y" +msgstr "&Wiederholen\tCtrl+Y" + +#: ../src/gui/mainFrame.cpp:504 +msgid "&Preferences" +msgstr "&Voreinstellungen" + +#: ../src/gui/mainFrame.cpp:506 +msgid "&Edit" +msgstr "&Bearbeiten" + +#: ../src/gui/mainFrame.cpp:509 +msgid "&View" +msgstr "&Ansicht" + +#: ../src/gui/mainFrame.cpp:511 +msgid "&Help...\tCtrl+H" +msgstr "&Hilfe...\tCtrl+H" + +#: ../src/gui/mainFrame.cpp:511 +msgid "Show help files and documentation" +msgstr "Hilfedateien und Dokumentation anzeigen" + +#: ../src/gui/mainFrame.cpp:512 +msgid "&Contact..." +msgstr "&Kontakt..." + +#: ../src/gui/mainFrame.cpp:512 +msgid "Open contact page" +msgstr "Kontaktseite öffnen" + +#: ../src/gui/mainFrame.cpp:514 +msgid "&About..." +msgstr "Über 3Depict..." + +#: ../src/gui/mainFrame.cpp:514 +msgid "Information about this program" +msgstr "Informationen zu diesem Programm" + +#: ../src/gui/mainFrame.cpp:515 +msgid "&Help" +msgstr "&Hilfe" + +#: ../src/gui/mainFrame.cpp:517 +msgid "Stashed Filters" +msgstr "Zwischengelagerte Filter" + +#: ../src/gui/mainFrame.cpp:522 +msgid "Data Filtering" +msgstr "Daten filtern" + +#: ../src/gui/mainFrame.cpp:546 +msgid "Last Outputs" +msgstr "Letzte Ausgabe" + +#: ../src/gui/mainFrame.cpp:548 +msgid "Auto Refresh" +msgstr "" +"Autom.\n" +"aktualisieren" + +#: ../src/gui/mainFrame.cpp:554 +msgid "Filter settings" +msgstr "Filtereinstellungen" + +#: ../src/gui/mainFrame.cpp:556 +msgid "Camera Name" +msgstr "Kameraname" + +#: ../src/gui/mainFrame.cpp:562 +msgid "3D Post-processing" +msgstr "3D Nachbearbeitung" + +#: ../src/gui/mainFrame.cpp:564 +msgid "Enable Cropping" +msgstr "Zuschneiden aktivieren" + +#: ../src/gui/mainFrame.cpp:566 ../src/gui/mainFrame.cpp:577 +msgid "x-y" +msgstr "x-y" + +#: ../src/gui/mainFrame.cpp:567 ../src/gui/mainFrame.cpp:578 +msgid "x-z" +msgstr "x-z" + +#: ../src/gui/mainFrame.cpp:568 ../src/gui/mainFrame.cpp:579 +msgid "y-x" +msgstr "y-x" + +#: ../src/gui/mainFrame.cpp:569 ../src/gui/mainFrame.cpp:580 +msgid "y-z" +msgstr "y-z" + +#: ../src/gui/mainFrame.cpp:570 ../src/gui/mainFrame.cpp:581 +msgid "z-x" +msgstr "z-x" + +#: ../src/gui/mainFrame.cpp:571 ../src/gui/mainFrame.cpp:582 +msgid "z-y" +msgstr "z-y" + +#: ../src/gui/mainFrame.cpp:586 +msgid "Use camera coordinates" +msgstr "Verwende Kamerakoordinaten" + +#: ../src/gui/mainFrame.cpp:587 +msgid "dX" +msgstr "dX" + +#: ../src/gui/mainFrame.cpp:589 +msgid "dY" +msgstr "dY" + +#: ../src/gui/mainFrame.cpp:591 +msgid "dZ" +msgstr "dZ" + +#: ../src/gui/mainFrame.cpp:593 +msgid "Enable Anaglyphic Stereo" +msgstr "Anaglyphic Stereo aktivieren" + +#: ../src/gui/mainFrame.cpp:594 +msgid "Flip Channels" +msgstr "Kanäle tauschen" + +#: ../src/gui/mainFrame.cpp:595 +msgid "Anaglyph Mode" +msgstr "Anaglyphmodus" + +#: ../src/gui/mainFrame.cpp:597 +msgid "Red-Blue" +msgstr "Rot-Blau" + +#: ../src/gui/mainFrame.cpp:598 +msgid "Red-Green" +msgstr "Rot-Grün" + +#: ../src/gui/mainFrame.cpp:599 +msgid "Red-Cyan" +msgstr "Rot-Zyan" + +#: ../src/gui/mainFrame.cpp:600 +msgid "Green-Magenta" +msgstr "Grün-Magenta" + +#: ../src/gui/mainFrame.cpp:604 +msgid "Baseline Separation" +msgstr "Basislinienabstand" + +#: ../src/gui/mainFrame.cpp:606 +msgid "Smooth && translucent objects" +msgstr "Glatte && durchsichtige Objekte" + +#: ../src/gui/mainFrame.cpp:608 +msgid "3D lighting" +msgstr "3D Beleuchtung" + +#: ../src/gui/mainFrame.cpp:610 +msgid "Fast and weak randomisation." +msgstr "Schnelle aber schwache Randomisierung" + +#: ../src/gui/mainFrame.cpp:612 +msgid "Filter caching" +msgstr "Filter zwischenspeichern" + +#: ../src/gui/mainFrame.cpp:614 +msgid "Max. Ram usage (%)" +msgstr "Max. RAM-Nutzung (%)" + +#: ../src/gui/mainFrame.cpp:671 +msgid "Type" +msgstr "Type" + +#: ../src/gui/mainFrame.cpp:672 +msgid "Num" +msgstr "Num" + +#: ../src/gui/mainFrame.cpp:683 +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 +msgid "\tConfig Load: " +msgstr "\tConfig Load: " + +#: ../src/gui/mainFrame.cpp:885 ../src/gui/mainFrame.cpp:933 +msgid "Select Data or State File..." +msgstr "Daten oder Statusdatei auswählen..." + +#: ../src/gui/mainFrame.cpp:886 +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 "" +"Lesbare Dateien (*.xml, *.pos, *.txt,*.csv)|*.xml;*.pos;*.txt;*.csv|POS " +"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 +msgid "Loaded file." +msgstr "Loaded file." + +#: ../src/gui/mainFrame.cpp:934 +msgid "" +"3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|" +"XML State File (*.xml)|*.xml|All Files (*)|*" +msgstr "" +"3Depictdateien (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS Datei (*.pos)|*." +"pos|XML Status Datei (*.xml)|*.xml|All Files (*)|*" + +#: ../src/gui/mainFrame.cpp:945 +msgid "Merged file." +msgstr "Datei zusammengeführt." + +#: ../src/gui/mainFrame.cpp:1047 +msgid "Tip: You can use ⌘ (command) to merge" +msgstr "Tip: Sie können ⌘ (command) zum Zusammenführen verwenden" + +#: ../src/gui/mainFrame.cpp:1049 +msgid "Tip: You can use ctrl to merge" +msgstr "Tip: Sie können strg zum Zusammen führen verwenden" + +#: ../src/gui/mainFrame.cpp:1097 +msgid "Load error" +msgstr "Fehler beim Laden" + +#: ../src/gui/mainFrame.cpp:1098 +msgid "" +"Error loading state file.\n" +"See console for more info." +msgstr "" +"Fehler beim Laden der Statusdatei.\n" +"Konsole für mehr Informationen." + +#: ../src/gui/mainFrame.cpp:1120 +msgid "" +"This state file contains filters that can be unsafe to run\n" +"Do you wish to remove these before continuing?." +msgstr "" +"Diese Statusdatei enthält Filter deren Anwendung möglicherweise unsicher " +"ist. Wollen Sie diese entfernen." + +#: ../src/gui/mainFrame.cpp:1121 +msgid "Security warning" +msgstr "Sicherheitswarnung" + +#: ../src/gui/mainFrame.cpp:1330 ../src/gui/mainFrame.cpp:1429 +#: ../src/gui/mainFrame.cpp:1792 +msgid "Unable to save" +msgstr "Speichern nicht möglich" + +#: ../src/gui/mainFrame.cpp:1331 +msgid "No plot available. Please create a plot before exporting." +msgstr "Kein Plot vefügbar. Plot muss vor dem Exportieren erzeugt werden." -#: ../src/3Depict.cpp:1526 +#: ../src/gui/mainFrame.cpp:1335 msgid "Save plot..." msgstr "Plot speichern..." -#: ../src/3Depict.cpp:1527 +#: ../src/gui/mainFrame.cpp:1336 msgid "" "By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*." "svg|PNG File (*.png)|*.png|All Files (*)|*" @@ -786,47 +1507,52 @@ "Dateierweiterung (svg,png)|*.svg;*.png|Skalierbare Vektorgrafik (*.svg)|*." "svg|PNG Datei (*.png)|*.png|Alle Dateien (*)|*" -#: ../src/3Depict.cpp:1556 ../src/3Depict.cpp:1609 ../src/3Depict.cpp:1666 +#: ../src/gui/mainFrame.cpp:1392 +msgid "Select type for save" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1392 +msgid "Choose file type" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1414 ../src/gui/mainFrame.cpp:1457 +#: ../src/gui/mainFrame.cpp:1504 msgid "Choose resolution" msgstr "Auflösung auswählen" -#: ../src/3Depict.cpp:1571 +#: ../src/gui/mainFrame.cpp:1430 msgid "Unknown file extension. Please use \"svg\" or \"png\"" msgstr "Unbekannte Dateierweiterung. Bitte verwenden Sie \"svg\" oder \"png\"" -#: ../src/3Depict.cpp:1593 +#: ../src/gui/mainFrame.cpp:1441 msgid "Saved plot: " msgstr "Gespeicherter Plot:" -#: ../src/3Depict.cpp:1600 ../src/3Depict.cpp:1658 +#: ../src/gui/mainFrame.cpp:1448 ../src/gui/mainFrame.cpp:1496 msgid "Save Image..." msgstr "Speichere Bild..." -#: ../src/3Depict.cpp:1601 ../src/3Depict.cpp:1659 +#: ../src/gui/mainFrame.cpp:1449 ../src/gui/mainFrame.cpp:1497 msgid "PNG File (*.png)|*.png|All Files (*)|*" msgstr "PNG Datei (*.png)|*.png|Alle Dateien (*)|*" -#: ../src/3Depict.cpp:1624 +#: ../src/gui/mainFrame.cpp:1472 ../src/gui/mainFrame.cpp:1521 +msgid "Program limitation" +msgstr "Programmeinschränkung" + +#: ../src/gui/mainFrame.cpp:1473 msgid "" "Limitation on the screenshot dimension; please ensure that both width and " "height exceed the initial values,\n" -" or that they are smaller than the initial values.\n" +" or that they are both smaller than the initial values.\n" " If this bothers you, please submit a bug." msgstr "" -"Beschränkung der Screenshot Dimensionen; stellen Sie bitte sicher, dass " -"Breite und Höhe die ursprünglichen Werte überschreiten, oder dass diese " -"kleiner als die ursprünglichen Werte sind. Sollte Sie dies stören, melden " -"Sie bitte einen Bug." - -#: ../src/3Depict.cpp:1625 ../src/3Depict.cpp:1685 -msgid "Program limitation" -msgstr "Programmeinschränkung" -#: ../src/3Depict.cpp:1649 ../src/3Depict.cpp:1743 +#: ../src/gui/mainFrame.cpp:1487 ../src/gui/mainFrame.cpp:1570 msgid "Saved 3D View :" msgstr "Gespeicherte 3D Ansicht" -#: ../src/3Depict.cpp:1684 +#: ../src/gui/mainFrame.cpp:1522 msgid "" "Limitation on the screenshot dimension; please ensure that both width and " "height exceed the initial values,\n" @@ -838,39 +1564,100 @@ "kleiner als die ursprünglichen Werte sind. Sollte Sie dies stören, melden " "Sie bitte einen Bug." -#: ../src/3Depict.cpp:1707 +#: ../src/gui/mainFrame.cpp:1538 msgid "Number of frames" msgstr "Bilderanzahl" -#: ../src/3Depict.cpp:1707 -msgid "Frame count" -msgstr "Bildanzahl" +#: ../src/gui/mainFrame.cpp:1678 +msgid "Cannot animate with no filters." +msgstr "" + +#: ../src/gui/mainFrame.cpp:1725 +msgid "Filter property change failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1727 +msgid "Filter change error" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1750 +msgid "Refresh failed on frame :" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1752 +msgid "Refresh failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1778 +msgid "Scene generation failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1779 +msgid "Unable to generate scene for frame " +msgstr "" + +#: ../src/gui/mainFrame.cpp:1793 +msgid "Image save failed for frame " +msgstr "" + +#: ../src/gui/mainFrame.cpp:1818 +msgid "Ion save failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1819 +msgid "Unable to save ions for frame " +msgstr "" + +#: ../src/gui/mainFrame.cpp:1850 +msgid "Plot save failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1851 +msgid "Unable to save plot or frame " +msgstr "" + +#: ../src/gui/mainFrame.cpp:1892 +msgid "Range save failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1893 +msgid "Unable to save range for frame " +msgstr "" + +#: ../src/gui/mainFrame.cpp:1922 +msgid "Voxel save failed" +msgstr "" + +#: ../src/gui/mainFrame.cpp:1923 +msgid "Unable to save voxels for frame " +msgstr "" -#: ../src/3Depict.cpp:1754 ../src/3Depict.cpp:1870 ../src/3Depict.cpp:1972 +#: ../src/gui/mainFrame.cpp:1969 ../src/gui/mainFrame.cpp:2076 +#: ../src/gui/mainFrame.cpp:2173 msgid "No filters means no data to export" msgstr "Keine Filter bedeutet keine Daten zum Exportieren" -#: ../src/3Depict.cpp:1760 +#: ../src/gui/mainFrame.cpp:1975 msgid "Package name" msgstr "Paketname" -#: ../src/3Depict.cpp:1761 +#: ../src/gui/mainFrame.cpp:1976 msgid "Package directory name" msgstr "Paketverzeichnis" -#: ../src/3Depict.cpp:1763 +#: ../src/gui/mainFrame.cpp:1978 msgid "AnalysisPackage" msgstr "Analysepaket" -#: ../src/3Depict.cpp:1775 +#: ../src/gui/mainFrame.cpp:1990 msgid "Package folder already exists, won't overwrite." msgstr "Paketverzeichnis existiert bereits. Werde es nicht überschreiben." -#: ../src/3Depict.cpp:1776 +#: ../src/gui/mainFrame.cpp:1991 msgid "Not available" msgstr "Nicht verfügbar" -#: ../src/3Depict.cpp:1807 +#: ../src/gui/mainFrame.cpp:2022 msgid "" "Package folder creation failed\n" "check writing to this location is possible." @@ -878,154 +1665,151 @@ "Anlegen des Paketverzeichnisses fehlgeschlagen\n" "Überprüfen Sie ob der angegenbene Ort schreibgeschützt ist." -#: ../src/3Depict.cpp:1808 +#: ../src/gui/mainFrame.cpp:2023 msgid "Folder creation failed" msgstr "Anlegen des Ordners ist fehlgeschlagen" -#: ../src/3Depict.cpp:1835 +#: ../src/gui/mainFrame.cpp:2045 msgid "Copying" msgstr "kopiere" -#: ../src/3Depict.cpp:1836 +#: ../src/gui/mainFrame.cpp:2046 msgid "Copying referenced files" msgstr "Copying referenced files" -#: ../src/3Depict.cpp:1844 +#: ../src/gui/mainFrame.cpp:2054 msgid "Error copying file" msgstr "Fehler beim Kopieren der Datei" -#: ../src/3Depict.cpp:1859 +#: ../src/gui/mainFrame.cpp:2065 msgid "Saved package: " msgstr "Gespeicherte Pakete: " -#: ../src/3Depict.cpp:1880 +#: ../src/gui/mainFrame.cpp:2086 msgid "Export" msgstr "Exportieren" -#: ../src/3Depict.cpp:1884 ../src/dialogs/ExportRngDialog.cpp:151 -msgid "Save pos..." -msgstr "pos speichern..." - -#: ../src/3Depict.cpp:1885 +#: ../src/gui/mainFrame.cpp:2091 msgid "POS Data (*.pos)|*.pos|All Files (*)|*" msgstr "POS-Daten (*.pos)|*.pos|All Files (*)|*" -#: ../src/3Depict.cpp:1913 ../src/3Depict.cpp:2017 +#: ../src/gui/mainFrame.cpp:2119 ../src/gui/mainFrame.cpp:2218 msgid "File already exists, overwrite?" msgstr "Datei existiert bereits. Überschreiben?" -#: ../src/3Depict.cpp:1914 ../src/3Depict.cpp:2018 ../src/3Depict.cpp:2044 +#: ../src/gui/mainFrame.cpp:2120 ../src/gui/mainFrame.cpp:2219 +#: ../src/gui/mainFrame.cpp:2245 msgid "Overwrite?" msgstr "Überschreiben?" -#: ../src/3Depict.cpp:1951 +#: ../src/gui/mainFrame.cpp:2152 msgid "Saved ions: " msgstr "Gespeicherte Ionen:" -#: ../src/3Depict.cpp:1976 +#: ../src/gui/mainFrame.cpp:2177 msgid "Export Ranges" msgstr "Range exportieren" -#: ../src/3Depict.cpp:1999 +#: ../src/gui/mainFrame.cpp:2200 msgid "Save state..." msgstr "Speichere Status..." -#: ../src/3Depict.cpp:2000 +#: ../src/gui/mainFrame.cpp:2201 msgid "XML state file (*.xml)|*.xml|All Files (*)|*" msgstr "" -#: ../src/3Depict.cpp:2043 +#: ../src/gui/mainFrame.cpp:2244 msgid "Files have been referred to using relative paths. Keep relative paths?" msgstr "" "Auf Dateien wurde mit relativen Pfaden verwiesen. Relative Pfade beibehalten?" -#: ../src/3Depict.cpp:2080 +#: ../src/gui/mainFrame.cpp:2276 msgid "Saved state: " msgstr "Gespeicherter Status: " -#: ../src/3Depict.cpp:2416 +#: ../src/gui/mainFrame.cpp:2612 msgid "Manual not found locally. Launching web browser" msgstr "Anleitung konnte lokal nicht gefunden werden. Starte Webbrowser" -#: ../src/3Depict.cpp:2425 +#: ../src/gui/mainFrame.cpp:2621 msgid "Opening contact page in external web browser" msgstr "Öffne Kontaktseite in externem Browser" -#: ../src/3Depict.cpp:2437 +#: ../src/gui/mainFrame.cpp:2633 msgid "No filter stashes to edit." msgstr "Keine Filterstashes zum Bearbeiten." -#: ../src/3Depict.cpp:2441 +#: ../src/gui/mainFrame.cpp:2637 msgid "Filter Stashes" msgstr "Filter Stashes" -#: ../src/3Depict.cpp:2470 +#: ../src/gui/mainFrame.cpp:2666 msgid "Quick and dirty analysis for point data." msgstr "\"Quick and dirty\" Analyse von Punktdaten." -#: ../src/3Depict.cpp:2480 +#: ../src/gui/mainFrame.cpp:2676 msgid "Compiled with wx Version: " msgstr "Kompiliert mit wx Version: " -#: ../src/3Depict.cpp:2501 +#: ../src/gui/mainFrame.cpp:2697 msgid "Press enter to store new stash" msgstr "Eingabe drücken um neuen Filterstash zu speichern" -#: ../src/3Depict.cpp:2507 +#: ../src/gui/mainFrame.cpp:2703 msgid "Press enter to restore stash" msgstr "Eingabe drücken um Stash wiederherzustellen" -#: ../src/3Depict.cpp:2545 +#: ../src/gui/mainFrame.cpp:2738 msgid "Unable to create stash, selection invalid" msgstr "Stash kann nicht erstellt werden, Auswahl ungültig" -#: ../src/3Depict.cpp:2557 +#: ../src/gui/mainFrame.cpp:2746 msgid "Created new filter tree stash" msgstr "Neuer Filterstash wurde erzeugt" -#: ../src/3Depict.cpp:2680 +#: ../src/gui/mainFrame.cpp:2868 msgid "Filter type not a data source - can't be at tree base" msgstr "" -#: ../src/3Depict.cpp:2851 +#: ../src/gui/mainFrame.cpp:3026 msgid "Moving - Hold ⌘ (command) to copy" msgstr "Verschieben - Halte ⌘ (command) um zu kopieren" -#: ../src/3Depict.cpp:2853 +#: ../src/gui/mainFrame.cpp:3028 msgid "Moving - Hold control to copy" msgstr "Verschieben - Halte Strg zum kopieren" -#: ../src/3Depict.cpp:3124 +#: ../src/gui/mainFrame.cpp:3284 msgid "Press enter to store new camera" msgstr "Eingabe drücken um neue Kamera zu speichern" -#: ../src/3Depict.cpp:3126 +#: ../src/gui/mainFrame.cpp:3286 msgid "Press enter to restore camera" msgstr "Eingabe drücken um Kamera wiederherzustellen" -#: ../src/3Depict.cpp:3151 ../src/3Depict.cpp:3188 +#: ../src/gui/mainFrame.cpp:3311 ../src/gui/mainFrame.cpp:3348 msgid "Restored camera: " msgstr "Wiederhergestellte Kamera: " -#: ../src/3Depict.cpp:3169 +#: ../src/gui/mainFrame.cpp:3329 msgid "Stored camera: " msgstr "Gespeicherte Kamera: " -#: ../src/3Depict.cpp:3250 +#: ../src/gui/mainFrame.cpp:3406 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/3Depict.cpp:3252 +#: ../src/gui/mainFrame.cpp:3408 msgid "Load data source (file->open) before choosing a new filter" msgstr "Lade Datenquelle (Datei->öffnen) vor dem Auswählen eines neuen Filters" -#: ../src/3Depict.cpp:3273 +#: ../src/gui/mainFrame.cpp:3429 msgid "Select RNG File..." msgstr "RNG Datei auswählen..." -#: ../src/3Depict.cpp:3274 +#: ../src/gui/mainFrame.cpp:3430 msgid "" "Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|" "Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*" @@ -1033,93 +1817,88 @@ "Rangedatei (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|" "Environment Datei (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|Alle Dateien (*)|*" -#: ../src/3Depict.cpp:3294 +#: ../src/gui/mainFrame.cpp:3450 msgid "Failed reading range file." msgstr "Fehler beim Lesen der Rangedatei." -#: ../src/3Depict.cpp:3299 +#: ../src/gui/mainFrame.cpp:3454 msgid "Error loading file" msgstr "Fehler beim Laden der Datei" -#: ../src/3Depict.cpp:3369 ../src/3Depict.cpp:3435 ../src/3Depict.cpp:4718 -#: ../src/3Depict.cpp:5248 +#: ../src/gui/mainFrame.cpp:3510 ../src/gui/mainFrame.cpp:3563 +#: ../src/gui/mainFrame.cpp:4946 ../src/gui/mainFrame.cpp:5481 msgid "Cons." msgstr "Kons." -#: ../src/3Depict.cpp:3406 +#: ../src/gui/mainFrame.cpp:3540 msgid "Refresh Aborted." msgstr "Aktualisieren abgebrochen" -#: ../src/3Depict.cpp:3439 +#: ../src/gui/mainFrame.cpp:3567 msgid "*Cons." msgstr "" -#: ../src/3Depict.cpp:3441 +#: ../src/gui/mainFrame.cpp:3569 msgid "§Cons." msgstr "§Kons." -#: ../src/3Depict.cpp:3552 +#: ../src/gui/mainFrame.cpp:3680 msgid "Autosave complete." msgstr "Autosave beendet." -#: ../src/3Depict.cpp:3712 +#: ../src/gui/mainFrame.cpp:3835 msgid "Aborted." msgstr "Abgebrochen" -#: ../src/3Depict.cpp:3738 ../src/3Depict.cpp:3742 ../src/3Depict.cpp:3755 -#: ../src/glPane.cpp:895 ../src/glPane.cpp:1060 -msgid " of " -msgstr " von " - -#: ../src/3Depict.cpp:3753 +#: ../src/gui/mainFrame.cpp:3876 msgid "Updated." msgstr "Updated." -#: ../src/3Depict.cpp:3759 +#: ../src/gui/mainFrame.cpp:3882 msgid "\\% Done (Esc aborts)" msgstr "\\% fertig (Esc abbrechen)" -#: ../src/3Depict.cpp:3761 +#: ../src/gui/mainFrame.cpp:3884 msgid "\\% Done" msgstr "\\% fertig" -#: ../src/3Depict.cpp:4010 ../src/3Depict.cpp:4017 +#: ../src/gui/mainFrame.cpp:4133 ../src/gui/mainFrame.cpp:4140 msgid "Next Fullscreen mode: none" msgstr "Nächster Vollbildmodus: keiner" -#: ../src/3Depict.cpp:4013 +#: ../src/gui/mainFrame.cpp:4136 msgid "Next Fullscreen mode: complete" msgstr "Nächster Vollbildmodus: vollständig" -#: ../src/3Depict.cpp:4021 +#: ../src/gui/mainFrame.cpp:4144 msgid "Next Fullscreen mode: with toolbars" msgstr "Nächster Vollbildmodus: mit Werkzeugleisten" -#: ../src/3Depict.cpp:4037 +#: ../src/gui/mainFrame.cpp:4160 msgid "Next Mode: No fullscreen" msgstr "Nächster Modus: Kein Vollbild" -#: ../src/3Depict.cpp:4041 +#: ../src/gui/mainFrame.cpp:4164 msgid "Next Mode: fullscreen w/o toolbar" msgstr "Nächster Modus: Vollbild ohne Werkzeugleiste" -#: ../src/3Depict.cpp:4045 +#: ../src/gui/mainFrame.cpp:4168 msgid "Next Mode: fullscreen with toolbar" msgstr "Nächster Modus: Vollbild mit Werkzeugleiste" -#: ../src/3Depict.cpp:4083 -msgid "Use shift-click to force full refresh" -msgstr "Verwende shift-click um komplettes Aktualisieren zu erzwingen" +#: ../src/gui/mainFrame.cpp:4209 +msgid "Tip: You can shift-click to force full refresh, if required" +msgstr "Tipp: Verwende shift-click um komplettes Aktualisieren zu erzwingen" -#: ../src/3Depict.cpp:4346 +#: ../src/gui/mainFrame.cpp:4461 msgid "No data to save" msgstr "Keine Daten zum Sichern" -#: ../src/3Depict.cpp:4457 +#: ../src/gui/mainFrame.cpp:4572 msgid "Aborting..." msgstr "Abbrechen..." -#: ../src/3Depict.cpp:4463 +#: ../src/gui/mainFrame.cpp:4578 msgid "" "Waiting for refresh to abort. Exiting could lead to the program " "backgrounding. Exit anyway? " @@ -1127,70 +1906,70 @@ "Waiting for refresh to abort. Exiting could lead to the program " "backgrounding. Exit anyway? " -#: ../src/3Depict.cpp:4464 ../src/3Depict.cpp:4484 +#: ../src/gui/mainFrame.cpp:4579 ../src/gui/mainFrame.cpp:4601 msgid "Confirmation request" msgstr "Bestätigungsabfrage" -#: ../src/3Depict.cpp:4483 +#: ../src/gui/mainFrame.cpp:4600 msgid "Are you sure you wish to exit 3Depict?" msgstr "Sind Sie sicher, dass Sie 3Depict beenden wollen?" -#: ../src/3Depict.cpp:4746 +#: ../src/gui/mainFrame.cpp:4974 msgid "Update Notice: New version " msgstr "Updatenotiz: Neue Version " -#: ../src/3Depict.cpp:4746 +#: ../src/gui/mainFrame.cpp:4974 msgid " found online." msgstr " online gefunden." -#: ../src/3Depict.cpp:4750 +#: ../src/gui/mainFrame.cpp:4978 msgid "Online Check: " msgstr "Überprüfe online:" -#: ../src/3Depict.cpp:4750 +#: ../src/gui/mainFrame.cpp:4978 msgid " is up-to-date." msgstr "ist up-to-date." -#: ../src/3Depict.cpp:4842 +#: ../src/gui/mainFrame.cpp:5068 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/3Depict.cpp:4843 +#: ../src/gui/mainFrame.cpp:5069 msgid "Autosave" msgstr "Automatisch speichern" -#: ../src/3Depict.cpp:4850 +#: ../src/gui/mainFrame.cpp:5076 msgid "Unable to load autosave file.." msgstr "Kann Autosavedatei nicht laden.." -#: ../src/3Depict.cpp:5028 +#: ../src/gui/mainFrame.cpp:5261 msgid "List of available filters" msgstr "Liste der verfügbaren Filter" -#: ../src/3Depict.cpp:5029 +#: ../src/gui/mainFrame.cpp:5262 msgid "Tree of data filters" msgstr "" -#: ../src/3Depict.cpp:5030 +#: ../src/gui/mainFrame.cpp:5263 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/3Depict.cpp:5033 +#: ../src/gui/mainFrame.cpp:5266 msgid "" -"Enable/Disable \"Alpha blending\" (transparency) in rendering system. This " -"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." +"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." -#: ../src/3Depict.cpp:5034 +#: ../src/gui/mainFrame.cpp:5267 msgid "" "Enable/Disable lighting calculations in rendering, for objects that request " "this. Lighting provides important depth cues for objects comprised of 3D " @@ -1201,7 +1980,7 @@ "umrandete Objekte. Deaktivieren erlaubt u.U. schnelleres Rendern bei " "komplizierten Szenen." -#: ../src/3Depict.cpp:5035 +#: ../src/gui/mainFrame.cpp:5268 msgid "" "Enable/Disable weak randomisation (Galois linear feedback shift register). " "Strong randomisation uses a much slower random selection method, but " @@ -1213,51 +1992,41 @@ "Auswahlmethode bietet dafür aber einen besseren Schutz gegen unbeabsichtigte " "Korrelationen und wird für die endgültige Analyse empfohlen." -#: ../src/3Depict.cpp:5036 +#: ../src/gui/mainFrame.cpp:5269 msgid "" -"Enable/Disable caching of intermediate results during filter updates. This " -"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." - -#: ../src/3Depict.cpp:5040 ../src/3Depict.cpp:5045 -msgid "Property" -msgstr "Eigenschaft" - -#: ../src/3Depict.cpp:5041 ../src/3Depict.cpp:5046 -#: ../src/filters/dataLoad.cpp:461 ../src/dialogs/ExportRngDialog.cpp:89 -#: ../src/dialogs/prefDialog.cpp:106 ../src/wxcomponents.cpp:267 -msgid "Value" -msgstr "Wert" +"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." -#: ../src/3Depict.cpp:5047 +#: ../src/gui/mainFrame.cpp:5280 msgid "Camera data information" msgstr "Kamerainformation" -#: ../src/3Depict.cpp:5051 +#: ../src/gui/mainFrame.cpp:5284 msgid "Enable/disable visual effects on final 3D output" msgstr "Ein/Ausschalten von visuellen Effekten in der finalen 3D Ausgabe." -#: ../src/3Depict.cpp:5053 +#: ../src/gui/mainFrame.cpp:5286 msgid "Enable cropping post-process effect" msgstr "Cropping post-Prozess Effect einschalten" -#: ../src/3Depict.cpp:5056 +#: ../src/gui/mainFrame.cpp:5289 msgid "" "Colour based 3D effect enable/disable - requires appropriate colour filter " "3D glasses." msgstr "" "Farbbasierte 3D-Effekte ein/ausschalten - erfordert geeignete 3D-Brillen" -#: ../src/3Depict.cpp:5057 +#: ../src/gui/mainFrame.cpp:5290 msgid "Glasses colour mode" msgstr "Brillenfarbmodus" -#: ../src/3Depict.cpp:5059 +#: ../src/gui/mainFrame.cpp:5292 msgid "" "Level of separation between left and right images, which sets 3D depth to " "visual distortion tradeoff" @@ -1265,536 +2034,787 @@ "Level of separation between left and right images, which sets 3D depth to " "visual distortion tradeoff" -#: ../src/3Depict.cpp:5063 +#: ../src/gui/mainFrame.cpp:5296 msgid "X" msgstr "X" -#: ../src/3Depict.cpp:5064 +#: ../src/gui/mainFrame.cpp:5297 msgid "Y" msgstr "Y" -#: ../src/3Depict.cpp:5065 +#: ../src/gui/mainFrame.cpp:5298 msgid "Save raw data to file" msgstr "Speichere Rohdaten in Datei" -#: ../src/3Depict.cpp:5066 +#: ../src/gui/mainFrame.cpp:5299 msgid "Copy raw data to clipboard" msgstr "Kopiere Rohdaten in die Zwischenablage" -#: ../src/3Depict.cpp:5067 -msgid "Manage \"stashed\" data." +#: ../src/gui/mainFrame.cpp:5300 +msgid "Manage \"stashed\" data." +msgstr "" + +#: ../src/gui/mainFrame.cpp:5301 +msgid "Program text output" +msgstr "Programm Textausgabe" + +#: ../src/gui/mainFrame.cpp:5302 +msgid "Select active camera, or type to create new named camera" +msgstr "" + +#: ../src/gui/mainFrame.cpp:5303 +msgid "Remove the selected camera" +msgstr "Ausgewählte Kamera entfernen" + +#: ../src/gui/mainFrame.cpp:5304 +msgid "Perform cropping from coordinate frame of camera" +msgstr "" + +#: ../src/gui/mainFrame.cpp:5305 +msgid "" +"Set the maximum amount of RAM to use in order to speed repeat computations" +msgstr "" + +#: ../src/gui/mainFrame.cpp:5306 +msgid "Collapse the filter tree" +msgstr "" + +#: ../src/gui/mainFrame.cpp:5307 +msgid "Expand the filter tree" +msgstr "" + +#: ../src/gui/mainFrame.cpp:5308 +msgid "Process the filter tree, hold shift to purge cached filter data" +msgstr "" + +#: ../src/gui/mainFrame.cpp:5447 +msgid "Crop" +msgstr "Zuschneiden" + +#: ../src/gui/mainFrame.cpp:5448 +msgid "Stereo" +msgstr "Stereo" + +#: ../src/gui/mainFrame.cpp:5459 +msgid "Data" +msgstr "Daten" + +#: ../src/gui/mainFrame.cpp:5460 +msgid "Cam" +msgstr "Cam" + +#: ../src/gui/mainFrame.cpp:5461 +msgid "Post" +msgstr "Post" + +#: ../src/gui/mainFrame.cpp:5462 +msgid "Tools" +msgstr "Werkz." + +#: ../src/gui/mainFrame.cpp:5479 ../src/backend/filter.cpp:44 +msgid "Plot" +msgstr "Plot" + +#: ../src/gui/mainFrame.cpp:5480 +msgid "Raw" +msgstr "Roh" + +#: ../src/gui/mathglPane.cpp:203 +msgid "No plots selected." +msgstr "Kein Plot ausgewählt." + +#: ../src/gui/mathglPane.cpp:1125 +msgid "" +"Unable to allocate requested memory.\n" +" Try a lower resolution, or save as vector (SVG)." +msgstr "" +"Kann den notwendigen Speicher nicht zuordnen. Versuche eine geringer " +"Auflösung oder speichere als Vektografik (svg)." + +#: ../src/gui/mathglPane.cpp:1127 +msgid "Plotting functions returned an error:\n" +msgstr "Plot-Funktion meldete einen Fehler:\n" + +#: ../src/gui/mathglPane.cpp:1129 +msgid "File readback check failed" +msgstr "File readback check failed" + +#: ../src/gui/mathglPane.cpp:1131 +msgid "Filesize during readback appears to be zero." +msgstr "Filesize during readback appears to be zero." + +#: ../src/3Depict.cpp:77 +msgid "displays this message" +msgstr "zeigt diese Nachricht" + +#: ../src/3Depict.cpp:79 +msgid "inputfile" +msgstr "Eingabedatei" + +#: ../src/3Depict.cpp:88 +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 +msgid "File : " +msgstr "Datei : " + +#: ../src/3Depict.cpp:374 +msgid " does not exist. Skipping" +msgstr " existiert nicht. Überspringe" + +#: ../src/backend/configFile.cpp:186 +msgid "Config file present, but is not valid (root node test)" +msgstr "Konfigurationsdatei vorhanden, aber nicht gültig (root node test)" + +#: ../src/backend/configFile.cpp:227 +msgid "Unable to interpret recent file entry" +msgstr "Kann den letzten Dateieintrag nicht interpretieren" + +#: ../src/backend/configFile.cpp:267 +msgid "Unable to determine filter type in defaults listing." +msgstr "Kann den Filtertyp im Defaultslisting nicht bestimmen." + +#: ../src/backend/configFile.cpp:568 +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 +msgid "" +"regardless of the settings you use here. Use your package manager to keep up-" +"to-date" msgstr "" +"Nutzen Sie Ihren Paketmanager um up-to-date zu sein unabhängig von den " +"Einstellungen die Sie hier verwenden" -#: ../src/3Depict.cpp:5068 -msgid "Program text output" -msgstr "Programm Textausgabe" +#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:96 +msgid "None" +msgstr "Keiner" -#: ../src/3Depict.cpp:5069 -msgid "Select active camera, or type to create new named camera" -msgstr "" +#: ../src/backend/plot.cpp:31 +msgid "Moving avg." +msgstr "Gleit.Durchschn." -#: ../src/3Depict.cpp:5070 -msgid "Remove the selected camera" -msgstr "Ausgewählte Kamera entfernen" +#: ../src/backend/plot.cpp:35 +msgid "Lines" +msgstr "Linien" -#: ../src/3Depict.cpp:5071 -msgid "Perform cropping from coordinate frame of camera" -msgstr "" +#: ../src/backend/plot.cpp:36 +msgid "Bars" +msgstr "Block" -#: ../src/3Depict.cpp:5072 -msgid "" -"Set the maximum amount of RAM to use in order to speed repeat computations" -msgstr "" +#: ../src/backend/plot.cpp:37 +msgid "Steps" +msgstr "Stufen" -#: ../src/3Depict.cpp:5073 -msgid "Collapse the filter tree" -msgstr "" +#: ../src/backend/plot.cpp:38 +msgid "Stem" +msgstr "Stem" -#: ../src/3Depict.cpp:5074 -msgid "Expand the filter tree" -msgstr "" +#: ../src/backend/plot.cpp:39 +msgid "Points" +msgstr "Punkte" -#: ../src/3Depict.cpp:5075 -msgid "Process the filter tree, hold shift to purge cached filter data" +#: ../src/backend/plot.cpp:619 ../src/backend/plot.cpp:627 +msgid "Multiple data types" msgstr "" -#: ../src/3Depict.cpp:5214 -msgid "Crop" -msgstr "Zuschneiden" +#: ../src/backend/plot.cpp:783 +msgid "Mixed log/non-log:" +msgstr "Gemischt log/nicht-log" -#: ../src/3Depict.cpp:5215 -msgid "Stereo" -msgstr "Stereo" +#: ../src/backend/plot.cpp:1227 +msgid "error" +msgstr "Fehler" -#: ../src/3Depict.cpp:5226 -msgid "Data" -msgstr "Daten" +#: ../src/backend/filtertree.cpp:952 +msgid "WARNING: Skipping node " +msgstr "WARNUNG: Skipping node " -#: ../src/3Depict.cpp:5227 -msgid "Cam" -msgstr "Cam" +#: ../src/backend/filtertree.cpp:952 +msgid " as it was not recognised" +msgstr " wurde nicht erkannt." -#: ../src/3Depict.cpp:5228 -msgid "Post" -msgstr "Post" +#: ../src/backend/filtertree.cpp:990 +msgid "Error processing node: " +msgstr "Fehler beim Verarbeiten von Node: " -#: ../src/3Depict.cpp:5229 -msgid "Tools" -msgstr "Werkz." +#: ../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/3Depict.cpp:5246 -msgid "Spec." -msgstr "Plot" +#: ../src/backend/viscontrol.cpp:1089 +msgid "Failed to allocate parser" +msgstr "Kann Parser nicht zuordnen" -#: ../src/3Depict.cpp:5247 -msgid "Raw" -msgstr "Roh" +#: ../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/3Depict.cpp:5306 -msgid "displays this message" -msgstr "zeigt diese Nachricht" +#: ../src/backend/viscontrol.cpp:1132 +msgid "Base state node missing. Is this really a state XML file??" +msgstr "" -#: ../src/3Depict.cpp:5308 -msgid "inputfile" -msgstr "Eingabedatei" +#: ../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/3Depict.cpp:5317 +#: ../src/backend/viscontrol.cpp:1167 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" +"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/3Depict.cpp:5584 -msgid "File : " -msgstr "Datei : " +#: ../src/backend/viscontrol.cpp:1174 +msgid "Unable to find the \"writer\" node" +msgstr "Kann \"writer\" node nicht finden" -#: ../src/3Depict.cpp:5584 -msgid " does not exist. Skipping" -msgstr " existiert nicht. Überspringe" +#: ../src/backend/viscontrol.cpp:1184 +msgid "Unable to find the \"backcolour\" node." +msgstr "Unable to find the \"backcolour\" node." -#: ../src/filters/ionDownsample.cpp:449 -msgid "By Count" -msgstr "Nach Anzahl" +#: ../src/backend/viscontrol.cpp:1191 +msgid "\"backcolour\" node missing \"r\" value." +msgstr "\"backcolour\" node fehlt \"r\" Wert." -#: ../src/filters/ionDownsample.cpp:456 -msgid "Per Species" -msgstr "Nach Spezies" +#: ../src/backend/viscontrol.cpp:1196 +msgid "Unable to interpret \"backColour\" node's \"r\" value." +msgstr "Kann \"backColour\" node's \"r\" Wert nicht interpretieren." -#: ../src/filters/ionDownsample.cpp:502 -msgid "Output Count" -msgstr "Ausgabe Anzahl" +#: ../src/backend/viscontrol.cpp:1204 +msgid "\"backcolour\" node missing \"g\" value." +msgstr "\"backcolour\" node fehlt \"g\" Wert." -#: ../src/filters/ionDownsample.cpp:508 -msgid "Out Fraction" -msgstr "Ausgabe Anteil" +#: ../src/backend/viscontrol.cpp:1210 +msgid "Unable to interpret \"backColour\" node's \"g\" value." +msgstr "Kann \"backColour\" node's \"g\" Wert nicht interpretieren." -#: ../src/filters/ionDownsample.cpp:661 -msgid "Downsample Aborted" -msgstr "Datenreduktion abgebrochen" +#: ../src/backend/viscontrol.cpp:1218 +msgid "\"backcolour\" node missing \"b\" value." +msgstr "\"backcolour\" node fehlt \"b\" Wert." -#: ../src/filters/ionDownsample.cpp:663 -msgid "Insuffient memory for downsample" -msgstr "Nicht genug Speicher zur Datenreduktion" +#: ../src/backend/viscontrol.cpp:1224 +msgid "Unable to interpret \"backColour\" node's \"b\" value." +msgstr "Kann \"backColour\" node's \"b\" Wert nicht interpretieren." -#: ../src/filters/ionClip.cpp:49 -msgid "Sphere" -msgstr "Kugel" +#: ../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/filters/ionClip.cpp:50 -msgid "Plane" -msgstr "Ebene" +#: ../src/backend/viscontrol.cpp:1258 +msgid "Unable to find or interpret \"showaxis\" node" +msgstr "Kann \"showaxis\" node nicht interpretieren" -#: ../src/filters/ionClip.cpp:51 -msgid "Cylinder" -msgstr "Zylinder" +#: ../src/backend/viscontrol.cpp:1267 +msgid "Unable to locate \"filtertree\" node." +msgstr "Kann \"filtertree\" node nicht finden." -#: ../src/filters/ionClip.cpp:52 -msgid "Aligned box" -msgstr "Ausgerichtete Box" +#: ../src/backend/viscontrol.cpp:1283 +msgid "Cameras section missing \"active\" node." +msgstr "Cameras section fehlt \"active\" node." -#: ../src/filters/ionClip.cpp:671 -msgid "Primitive" -msgstr "Primitiv" +#: ../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/filters/ionClip.cpp:677 ../src/filters/compositionProfile.cpp:885 -msgid "Show Primitive" -msgstr "Zeige Primitiv" +#: ../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/filters/ionClip.cpp:682 -msgid "Invert Clip" -msgstr "Invertiere Clip" +#: ../src/backend/viscontrol.cpp:1317 +msgid "Failed to interpret camera state for camera : " +msgstr "" -#: ../src/filters/ionClip.cpp:698 ../src/filters/ionClip.cpp:743 -#: ../src/filters/compositionProfile.cpp:917 -msgid "Radius" -msgstr "Radius" +#: ../src/backend/viscontrol.cpp:1325 +msgid "Unable to interpret the camera type for camera : " +msgstr "Kann den Kameratype nicht interpretieren für :" -#: ../src/filters/ionClip.cpp:714 -msgid "Plane Normal" -msgstr "Plane Normal" +#: ../src/backend/viscontrol.cpp:1361 +msgid "Unable to locate stash name for stash " +msgstr "Kann den Stashnamen für Stash nicht finden" -#: ../src/filters/ionClip.cpp:730 ../src/filters/compositionProfile.cpp:904 -#: ../src/filters/transform.cpp:1146 -msgid "Axis" -msgstr "Achse" +#: ../src/backend/viscontrol.cpp:1368 +msgid "Empty stash name for stash " +msgstr "Leerer Stashname für Stash" -#: ../src/filters/ionClip.cpp:738 ../src/filters/compositionProfile.cpp:912 -msgid "Lock Axis Mag." -msgstr "Achsen Vergr. sperren" +#: ../src/backend/viscontrol.cpp:1374 +msgid "For stash " +msgstr "Für Stash " -#: ../src/filters/ionClip.cpp:758 -msgid "Corner offset" -msgstr "Corner offset" +#: ../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/filters/ionClip.cpp:1026 -msgid "Insufficient memory for clip" +#: ../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/filters/ionClip.cpp:1028 -msgid "Clip Aborted" +#: ../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/filters/compositionProfile.cpp:485 -msgid "Distance" -msgstr "Abstand" +#: ../src/backend/filters/externalProgram.cpp:513 +msgid "Command" +msgstr "Befehl" -#: ../src/filters/compositionProfile.cpp:493 -msgid "Fraction" -msgstr "Anteil" +#: ../src/backend/filters/externalProgram.cpp:516 +msgid "" +"Full command to send to operating system. See manual for escape sequence " +"meanings" +msgstr "" -#: ../src/filters/compositionProfile.cpp:495 -msgid "Density (\\#.len^3)" -msgstr "Dichte (\\#.len^3)" +#: ../src/backend/filters/externalProgram.cpp:520 +msgid "Work Dir" +msgstr "Arbeitsverzeichnis" -#: ../src/filters/compositionProfile.cpp:498 -#: ../src/filters/spectrumPlot.cpp:224 ../src/filters/spatialAnalysis.cpp:844 -#: ../src/filters/spatialAnalysis.cpp:917 ../src/dialogs/ExportPos.cpp:107 -#: ../src/dialogs/ExportPos.cpp:110 -msgid "Count" -msgstr "Anzahl" +#: ../src/backend/filters/externalProgram.cpp:523 +msgid "Directory to run the command in" +msgstr "" -#: ../src/filters/compositionProfile.cpp:522 -msgid "Freq. Profile" -msgstr "Häufigkeitsprofil" +#: ../src/backend/filters/externalProgram.cpp:533 +msgid "Cleanup input" +msgstr "Bereinige Eingabe" -#: ../src/filters/compositionProfile.cpp:595 -msgid "Too many bins in comp. profile." -msgstr "Zu viele Bins im Konzentrationsprofil." +#: ../src/backend/filters/externalProgram.cpp:536 +msgid "Erase input files when command completed" +msgstr "" -#: ../src/filters/compositionProfile.cpp:597 -msgid "Not enough memory for comp. profile." -msgstr "Nicht genug Speicher für Konz.-Profil." +#: ../src/backend/filters/externalProgram.cpp:545 +msgid "Cache" +msgstr "Zwischenspeicher" -#: ../src/filters/compositionProfile.cpp:599 -msgid "Aborted composition prof." -msgstr "Konzentrationspr. abgebr." +#: ../src/backend/filters/externalProgram.cpp:548 +msgid "" +"Assume program does not alter its output, unless inputs from 3Depict are " +"altered" +msgstr "" -#: ../src/filters/compositionProfile.cpp:878 -msgid "Primitive Type (0-" -msgstr "Primitive Art (0-" +#: ../src/backend/filters/externalProgram.cpp:630 +msgid "Error processing command line" +msgstr "Fehler beim Ausführen der Kommandozeile" -#: ../src/filters/compositionProfile.cpp:928 -msgid "Fixed Bin Num" -msgstr "Fix. Bin-Anz." +#: ../src/backend/filters/externalProgram.cpp:632 +msgid "Unable to set working directory" +msgstr "Kann Arbeitsverzeichnis nicht festlegen" -#: ../src/filters/compositionProfile.cpp:934 -#: ../src/filters/spatialAnalysis.cpp:1374 -msgid "Num Bins" -msgstr "Bin-Anz." +#: ../src/backend/filters/externalProgram.cpp:634 +msgid "Error saving posfile result for external program" +msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm" -#: ../src/filters/compositionProfile.cpp:941 -msgid "Bin width" -msgstr "Bin-Breite" +#: ../src/backend/filters/externalProgram.cpp:636 +msgid "Error saving plot result for externalprogram" +msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm" -#: ../src/filters/compositionProfile.cpp:948 -#: ../src/filters/clusterAnalysis.cpp:996 ../src/filters/ionInfo.cpp:521 -msgid "Normalise" -msgstr "Normalisieren" +#: ../src/backend/filters/externalProgram.cpp:638 +msgid "Error creating temporary directory" +msgstr "Fehler beim Anlegen des temporären Verzeichnisses" -#: ../src/filters/compositionProfile.cpp:980 -#: ../src/filters/spectrumPlot.cpp:432 -msgid "Plot Type" -msgstr "Plot Type" +#: ../src/backend/filters/externalProgram.cpp:640 +msgid "Detected unusable number of columns in plot" +msgstr "Detected unusable number of columns in plot" -#: ../src/filters/compositionProfile.cpp:990 ../src/filters/voxelise.cpp:800 -#: ../src/filters/annotation.cpp:773 -msgid "Colour" -msgstr "Farbe" +#: ../src/backend/filters/externalProgram.cpp:642 +msgid "Unable to parse plot result from external program" +msgstr "Unable to parse plot result from external program" -#: ../src/filters/compositionProfile.cpp:1011 -msgid "Err. Estimator" -msgstr "Fehlerschätzer" +#: ../src/backend/filters/externalProgram.cpp:644 +msgid "Unable to load ions from external program" +msgstr "Kann Ionen von externem Programm nicht laden" -#: ../src/filters/compositionProfile.cpp:1019 -msgid "Avg. Window" -msgstr "" +#: ../src/backend/filters/externalProgram.cpp:646 +msgid "Unable to perform commandline substitution" +msgstr "Unable to perform commandline substitution" -#: ../src/filters/rangeFile.cpp:131 -msgid "Pre-Allocate" -msgstr "" +#: ../src/backend/filters/externalProgram.cpp:648 +msgid "Error executing external program" +msgstr "Fehler beim Ausführen von externem Programm" -#: ../src/filters/rangeFile.cpp:245 ../src/filter.cpp:51 -msgid "Range" -msgstr "Range" +#: ../src/backend/filters/ionClip.cpp:59 +#: ../src/backend/filters/compositionProfile.cpp:43 +msgid "Sphere" +msgstr "Kugel" -#: ../src/filters/rangeFile.cpp:497 ../src/filters/dataLoad.cpp:397 -msgid "File" -msgstr "Datei" +#: ../src/backend/filters/ionClip.cpp:60 +msgid "Plane" +msgstr "Ebene" -#: ../src/filters/rangeFile.cpp:507 -msgid "Drop unranged" -msgstr "Nicht gerangete ausschalten" +#: ../src/backend/filters/ionClip.cpp:61 +#: ../src/backend/filters/compositionProfile.cpp:42 +msgid "Cylinder" +msgstr "Zylinder" -#: ../src/filters/rangeFile.cpp:534 -msgid "All Ions" -msgstr "Alle Ionen" +#: ../src/backend/filters/ionClip.cpp:62 +msgid "Aligned box" +msgstr "Ausgerichtete Box" -#: ../src/filters/rangeFile.cpp:544 -msgid "IonID " -msgstr "IonID " +#: ../src/backend/filters/ionClip.cpp:492 +msgid "Primitive" +msgstr "Primitiv" -#: ../src/filters/rangeFile.cpp:554 -msgid "Active Ion " -msgstr "Actives Ion " +#: ../src/backend/filters/ionClip.cpp:495 +msgid "Shape of clipping object" +msgstr "" -#: ../src/filters/rangeFile.cpp:567 -msgid "Colour " -msgstr "Farbe" +#: ../src/backend/filters/ionClip.cpp:501 +#: ../src/backend/filters/compositionProfile.cpp:916 +msgid "Show Primitive" +msgstr "Zeige Primitiv" -#: ../src/filters/rangeFile.cpp:593 -msgid "All Ranges" -msgstr "Alle Range" +#: ../src/backend/filters/ionClip.cpp:504 +msgid "Display the 3D interaction object" +msgstr "" -#: ../src/filters/rangeFile.cpp:619 -msgid "Active Rng " -msgstr "Activer Rng " +#: ../src/backend/filters/ionClip.cpp:509 +msgid "Invert Clip" +msgstr "Invertiere Clip" -#: ../src/filters/rangeFile.cpp:624 -msgid "Ion " -msgstr "Ion " +#: ../src/backend/filters/ionClip.cpp:512 +msgid "" +"Switch between retaining points inside (false) and outside (true) of " +"primitive" +msgstr "" -#: ../src/filters/rangeFile.cpp:635 -msgid "Start rng " -msgstr "Start rng " +#: ../src/backend/filters/ionClip.cpp:526 +#: ../src/backend/filters/compositionProfile.cpp:975 +msgid "Position for centre of sphere" +msgstr "" -#: ../src/filters/rangeFile.cpp:640 -msgid "End rng " -msgstr "End rng " +#: ../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/spatialAnalysis.cpp:610 +msgid "Radius" +msgstr "Radius" -#: ../src/filters/rangeFile.cpp:959 -msgid "Ranging aborted by user" -msgstr "Ranging durch User abgebrochen" +#: ../src/backend/filters/ionClip.cpp:534 +#: ../src/backend/filters/compositionProfile.cpp:983 +msgid "Radius of sphere" +msgstr "" -#: ../src/filters/rangeFile.cpp:961 -msgid "Insufficient memory for range" -msgstr "Nicht genug Speicher für Range" +#: ../src/backend/filters/ionClip.cpp:548 +msgid "Position that plane passes through" +msgstr "" -#: ../src/filters/spectrumPlot.cpp:109 -msgid "Extrema" -msgstr "Extrema" +#: ../src/backend/filters/ionClip.cpp:553 +msgid "Plane Normal" +msgstr "Plane Normal" -#: ../src/filters/spectrumPlot.cpp:158 -msgid "count" -msgstr "Anzahl" +#: ../src/backend/filters/ionClip.cpp:556 +msgid "Perpendicular direction for plane" +msgstr "" -#: ../src/filters/spectrumPlot.cpp:243 -msgid "Mixed data" +#: ../src/backend/filters/ionClip.cpp:570 +msgid "Centre of cylinder" msgstr "" -#: ../src/filters/spectrumPlot.cpp:384 -msgid "bin width" -msgstr "Bin-Breite" +#: ../src/backend/filters/ionClip.cpp:575 +#: ../src/backend/filters/compositionProfile.cpp:939 +#: ../src/backend/filters/spatialAnalysis.cpp:601 +#: ../src/backend/filters/transform.cpp:1323 +msgid "Axis" +msgstr "Achse" -#: ../src/filters/spectrumPlot.cpp:393 -msgid "Auto Min/max" -msgstr "Auto Min/max" +#: ../src/backend/filters/ionClip.cpp:578 +msgid "Positive vector for cylinder" +msgstr "" -#: ../src/filters/spectrumPlot.cpp:398 -msgid "Min" -msgstr "Min" +#: ../src/backend/filters/ionClip.cpp:586 +#: ../src/backend/filters/compositionProfile.cpp:950 +msgid "Lock Axis Mag." +msgstr "Achsen Vergr. sperren" -#: ../src/filters/spectrumPlot.cpp:403 -msgid "Max" -msgstr "Max" +#: ../src/backend/filters/ionClip.cpp:589 +msgid "Prevent changing length of cylinder during 3D interaction" +msgstr "" -#: ../src/filters/spectrumPlot.cpp:411 -msgid "Logarithmic" -msgstr "Logarithmisch" +#: ../src/backend/filters/ionClip.cpp:597 +#: ../src/backend/filters/compositionProfile.cpp:961 +#: ../src/backend/filters/spatialAnalysis.cpp:613 +msgid "Radius of cylinder" +msgstr "" -#: ../src/filters/spectrumPlot.cpp:442 -msgid "colour" -msgstr "Farbe" +#: ../src/backend/filters/ionClip.cpp:610 +msgid "Centre of axis aligned box" +msgstr "" -#: ../src/filters/spectrumPlot.cpp:682 -msgid "Insufficient memory for spectrum filter." -msgstr "Nicht genügend Speicher für Spektrumfilter" +#: ../src/backend/filters/ionClip.cpp:615 +msgid "Corner offset" +msgstr "Corner offset" -#: ../src/filters/spectrumPlot.cpp:684 -msgid "Bad bincount value in spectrum filter." -msgstr "Falsche Binanzahl im Spektrumfilter." +#: ../src/backend/filters/ionClip.cpp:618 +msgid "Vector to corner of box" +msgstr "" -#: ../src/filters/clusterAnalysis.cpp:57 -#: ../src/filters/clusterAnalysis.cpp:970 +#: ../src/backend/filters/clusterAnalysis.cpp:74 +#: ../src/backend/filters/clusterAnalysis.cpp:998 msgid "Size Distribution" msgstr "Größenverteilung" -#: ../src/filters/clusterAnalysis.cpp:58 +#: ../src/backend/filters/clusterAnalysis.cpp:75 msgid "Chemistry Distribution" msgstr "Chemische Verteilung" -#: ../src/filters/clusterAnalysis.cpp:476 +#: ../src/backend/filters/clusterAnalysis.cpp:487 msgid "No range data. Can't cluster." msgstr "Keine Rangedaten. Clusteranalyse nicht möglich." -#: ../src/filters/clusterAnalysis.cpp:487 +#: ../src/backend/filters/clusterAnalysis.cpp:498 msgid "" "No ranges selected for cluster \"core\". Cannot continue with clustering." msgstr "" "Kein Range für cluster \"core\" ausgewählt. Kann mit Clusteranalyse nicht " "weitermachen." -#: ../src/filters/clusterAnalysis.cpp:499 +#: ../src/backend/filters/clusterAnalysis.cpp:510 msgid "" "No ranges selected for cluster \"bulk\". Cannot continue with clustering." msgstr "" "Kein Range für \"bulk\" ausgewählt. Kann mit Clusteranalyse nicht " "weitermachen." -#: ../src/filters/clusterAnalysis.cpp:673 +#: ../src/backend/filters/clusterAnalysis.cpp:684 msgid "Morphology Plot" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:674 +#: ../src/backend/filters/clusterAnalysis.cpp:685 msgid "\\lambda_1:\\lambda_2 ratio" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:675 +#: ../src/backend/filters/clusterAnalysis.cpp:686 msgid "\\lambda_2:\\lambda_3 ratio" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:712 +#: ../src/backend/filters/clusterAnalysis.cpp:723 msgid "No clusters had sufficient dimensionality to compute singular values" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:769 +#: ../src/backend/filters/clusterAnalysis.cpp:780 msgid "Found :" msgstr "Gefunden:" -#: ../src/filters/clusterAnalysis.cpp:771 +#: ../src/backend/filters/clusterAnalysis.cpp:782 msgid " clusters" msgstr " Cluster" -#: ../src/filters/clusterAnalysis.cpp:839 +#: ../src/backend/filters/clusterAnalysis.cpp:850 msgid "Compositions (fractional, core+bulk)" msgstr "Zusammensetzungen (fractional, core+bulk)" -#: ../src/filters/clusterAnalysis.cpp:841 +#: ../src/backend/filters/clusterAnalysis.cpp:852 msgid "Compositions (fractional, core only)" msgstr "Zusammensetzungen (fractional, core only)" -#: ../src/filters/clusterAnalysis.cpp:859 +#: ../src/backend/filters/clusterAnalysis.cpp:870 msgid "Frequencies (core+bulk)" msgstr "Häufigkeiten (core+bulk)" -#: ../src/filters/clusterAnalysis.cpp:891 +#: ../src/backend/filters/clusterAnalysis.cpp:898 msgid "Core Link + Erode" msgstr "Core Link + Erode" -#: ../src/filters/clusterAnalysis.cpp:895 -#: ../src/filters/clusterAnalysis.cpp:903 -#: ../src/filters/spatialAnalysis.cpp:1319 ../src/filters/ionInfo.cpp:546 +#: ../src/backend/filters/clusterAnalysis.cpp:902 +#: ../src/backend/filters/spatialAnalysis.cpp:360 +#: ../src/backend/filters/ionInfo.cpp:447 msgid "Algorithm" msgstr "Algorithmus" -#: ../src/filters/clusterAnalysis.cpp:910 +#: ../src/backend/filters/clusterAnalysis.cpp:906 +msgid "Cluster algorithm mode" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:915 msgid "Core Classify Dist" msgstr "Core Classify Dist" -#: ../src/filters/clusterAnalysis.cpp:915 +#: ../src/backend/filters/clusterAnalysis.cpp:918 +msgid "Restrict only atoms by distance to be cluster sources" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:923 msgid "Classify Knn Max" msgstr "Classify Knn Max" -#: ../src/filters/clusterAnalysis.cpp:920 +#: ../src/backend/filters/clusterAnalysis.cpp:926 +msgid "" +"Require that the kth NN (this number) is within the classify distance, to be " +"a cluster source" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:931 msgid "Core Link Dist" msgstr "Core Link Dist" -#: ../src/filters/clusterAnalysis.cpp:925 +#: ../src/backend/filters/clusterAnalysis.cpp:934 +msgid "Distance between clusters to allow linking" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:939 msgid "Bulk Link (Envelope) Dist" msgstr "Bulk Link (Envelope) Dist" -#: ../src/filters/clusterAnalysis.cpp:930 +#: ../src/backend/filters/clusterAnalysis.cpp:942 +msgid "" +"Distance from core points that form cluster that is used to grab surrounding " +"bulk points" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:947 msgid "Erode Dist" msgstr "Erode Dist" -#: ../src/filters/clusterAnalysis.cpp:938 +#: ../src/backend/filters/clusterAnalysis.cpp:950 +msgid "" +"Distance from unclustered material in which bulk points are eroded from " +"cluster" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:955 msgid "Clustering Params" msgstr "Cluster Parameter" -#: ../src/filters/clusterAnalysis.cpp:945 +#: ../src/backend/filters/clusterAnalysis.cpp:962 msgid "Count bulk" msgstr "Bulk mitrechnen" -#: ../src/filters/clusterAnalysis.cpp:951 +#: ../src/backend/filters/clusterAnalysis.cpp:965 +msgid "Include bulk ions in size distribution." +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:971 msgid "Size Cropping" msgstr "Größeneinschrankungen" -#: ../src/filters/clusterAnalysis.cpp:958 +#: ../src/backend/filters/clusterAnalysis.cpp:974 +msgid "Perform removal of clusters based upon size distribution" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:981 msgid "Min Size" msgstr "Min Größe" -#: ../src/filters/clusterAnalysis.cpp:963 +#: ../src/backend/filters/clusterAnalysis.cpp:984 +msgid "Remove clusters below this size" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:989 msgid "Max Size" msgstr "Max Größe" -#: ../src/filters/clusterAnalysis.cpp:976 +#: ../src/backend/filters/clusterAnalysis.cpp:992 +msgid "Remove clusters above this size" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1001 +msgid "Show number of clusters as a function of cluster size" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1007 msgid "Log Scale" msgstr "Log. Skala" -#: ../src/filters/clusterAnalysis.cpp:983 -msgid "Morphology Dist." +#: ../src/backend/filters/clusterAnalysis.cpp:1010 +msgid "Use logarithmic scale for size distribution" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:988 +#: ../src/backend/filters/clusterAnalysis.cpp:1026 msgid "Chemistry Dist." msgstr "Chemistry Dist." -#: ../src/filters/clusterAnalysis.cpp:1005 +#: ../src/backend/filters/clusterAnalysis.cpp:1029 +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/ionInfo.cpp:419 +msgid "Normalise" +msgstr "Normalisieren" + +#: ../src/backend/filters/clusterAnalysis.cpp:1039 +msgid "Convert cluster counts to composition" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1045 msgid "Postprocess" msgstr "Postprozess" -#: ../src/filters/clusterAnalysis.cpp:1031 +#: ../src/backend/filters/clusterAnalysis.cpp:1064 +msgid "If selected, use as \"core\" ion type (can make clusters)" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1069 msgid "Core Ranges" msgstr "Core Ranges" -#: ../src/filters/clusterAnalysis.cpp:1052 +#: ../src/backend/filters/clusterAnalysis.cpp:1081 +msgid "" +"If selected, use as \"bulk\" ion type (can be included in existing clusters)" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1086 msgid "Bulk Ranges" msgstr "Bulk Ranges" -#: ../src/filters/clusterAnalysis.cpp:1068 +#: ../src/backend/filters/clusterAnalysis.cpp:1101 msgid "Max. Sep + Erode" msgstr "Max. Sep + Erode" -#: ../src/filters/clusterAnalysis.cpp:1707 +#: ../src/backend/filters/clusterAnalysis.cpp:1730 msgid "Clustering aborted" msgstr "Clustering abgebrochen" -#: ../src/filters/clusterAnalysis.cpp:1709 +#: ../src/backend/filters/clusterAnalysis.cpp:1732 msgid "No core ions for cluster" msgstr "Keine Kernionen für Cluster" -#: ../src/filters/clusterAnalysis.cpp:1711 +#: ../src/backend/filters/clusterAnalysis.cpp:1734 msgid "No bulk ions for cluster" msgstr "Keine Bulkionen für Cluster" -#: ../src/filters/clusterAnalysis.cpp:1784 +#: ../src/backend/filters/clusterAnalysis.cpp:1812 msgid " --------------------------- Parameter selection notice ------------- " msgstr " --------------------------- Parameterauswahl Notiz ------------- " -#: ../src/filters/clusterAnalysis.cpp:1785 +#: ../src/backend/filters/clusterAnalysis.cpp:1813 msgid "You have specified a bulk distance larger than half your link distance." msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1786 +#: ../src/backend/filters/clusterAnalysis.cpp:1814 msgid "" "You can do this; thats OK, but the output is no longer independent of the " "computational process;" @@ -1802,1625 +2822,1898 @@ "Sie könne das machen, das ist in Ordnung, aber die Ausgabe ist nicht länger " "unabhängig vom Berechnungsprozess" -#: ../src/filters/clusterAnalysis.cpp:1787 +#: ../src/backend/filters/clusterAnalysis.cpp:1815 msgid "" "This will be a problem in the case where two or more clusters can equally " "lay claim to a \"bulk\" ion. " msgstr "" -"Dies ist ein Problem wenn zwei oder mehrere Cluster auf dasselbe \"bulk\" " -"Ion Anspruch erheben. " +"Dies ist ein Problem wenn zwei oder mehrere Cluster auf dasselbe \"bulk\" " +"Ion Anspruch erheben. " + +#: ../src/backend/filters/clusterAnalysis.cpp:1816 +msgid "" +" If your inter-cluster distance is sufficiently large (larger than your bulk " +"linking distance), then you can get away with this." +msgstr "" +" If your inter-cluster distance is sufficiently large (larger than your bulk " +"linking distance), then you can get away with this." + +#: ../src/backend/filters/clusterAnalysis.cpp:1817 +msgid "" +" In theory it is possible to \"join\" the clusters, but this has not been " +"implemented for speed reasons." +msgstr "" +"Theoretisch ist es möglich die Cluster zu 'verbinden', dies wurde jedoch aus " +"Gescheindigkeitsgründen nicht implementiert." + +#: ../src/backend/filters/clusterAnalysis.cpp:1818 +msgid "" +"If you want this, please contact the author, or just use the source to add " +"this in yourself." +msgstr "" +"Sollten Sie dies wollen, kontaktieren Sie den Autor oder verwenden Sie den " +"Sourcecode um es selbst hinzuzufügen." + +#: ../src/backend/filters/clusterAnalysis.cpp:1819 +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 +msgid "Collate" +msgstr "Abgleichen" + +#: ../src/backend/filters/clusterAnalysis.cpp:1848 +msgid "Build Core" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1866 +msgid "Classify Core" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1959 +msgid "Build Bulk" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:1979 +msgid "Core" +msgstr "Kern" + +#: ../src/backend/filters/clusterAnalysis.cpp:2124 +msgid "Bulk" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:2254 +msgid "Erode" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:2328 +msgid "Re-Collate" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:2596 +#: ../src/backend/filters/clusterAnalysis.cpp:2823 +msgid "Cluster Size" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:2597 +#: ../src/backend/filters/clusterAnalysis.cpp:2827 +msgid "Frequency" +msgstr "" + +#: ../src/backend/filters/clusterAnalysis.cpp:2825 +msgid "Composition" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:84 +msgid "None (Raw count)" +msgstr "Keine (Roh count)" + +#: ../src/backend/filters/voxelise.cpp:85 +msgid "Volume (Density)" +msgstr "Volumen (Dichte)" + +#: ../src/backend/filters/voxelise.cpp:86 +msgid "All Ions (conc)" +msgstr "Alle Ionen (Konz)" + +#: ../src/backend/filters/voxelise.cpp:87 +msgid "Ratio (Num/Denom)" +msgstr "Verhältnis (Zähler/Nenner)" + +#: ../src/backend/filters/voxelise.cpp:91 +msgid "Point Cloud" +msgstr "Punktwolke" + +#: ../src/backend/filters/voxelise.cpp:92 +msgid "Isosurface" +msgstr "Isosurface" + +#: ../src/backend/filters/voxelise.cpp:97 +msgid "Gaussian (2𝜎)" +msgstr "Gauss (2𝜎)" + +#: ../src/backend/filters/voxelise.cpp:101 +msgid "Zero" +msgstr "Null" + +#: ../src/backend/filters/voxelise.cpp:102 +msgid "Bounce" +msgstr "Bounce" + +#: ../src/backend/filters/voxelise.cpp:543 +msgid "Voxel Limits (min,max): (" +msgstr "Voxel Grenzen (min,max): (" + +#: ../src/backend/filters/voxelise.cpp:592 +msgid "Fixed width" +msgstr "Fixe Breite" + +#: ../src/backend/filters/voxelise.cpp:596 +msgid "If true, use fixed size voxels, otherwise use fixed count" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:602 +msgid "Bin width x" +msgstr "Bin-Breite x" + +#: ../src/backend/filters/voxelise.cpp:606 +msgid "Voxel size in X direction" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:610 +msgid "Bin width y" +msgstr "Bin-Breite y" + +#: ../src/backend/filters/voxelise.cpp:613 +msgid "Voxel size in Y direction" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:619 +msgid "Bin width z" +msgstr "Bin-Breite Z" + +#: ../src/backend/filters/voxelise.cpp:622 +msgid "Voxel size in Z direction" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:629 +msgid "Num bins x" +msgstr "Anzahl Bins x" + +#: ../src/backend/filters/voxelise.cpp:633 +msgid "Number of voxels to use in X direction" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:638 +msgid "Num bins y" +msgstr "Anzahl Bins y" + +#: ../src/backend/filters/voxelise.cpp:641 +msgid "Number of voxels to use in Y direction" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:647 +msgid "Num bins z" +msgstr "Anzahl Bins z" + +#: ../src/backend/filters/voxelise.cpp:649 +msgid "Number of voxels to use in Z direction" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:670 +msgid "Normalise by" +msgstr "Normalisieren mit" + +#: ../src/backend/filters/voxelise.cpp:673 +msgid "Method to use to normalise scalar value in each voxel" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:676 +msgid "Computation" +msgstr "" + +#: ../src/backend/filters/voxelise.cpp:683 +msgid "Numerator" +msgstr "Zähler" + +#: ../src/backend/filters/voxelise.cpp:686 +msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value" +msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1788 -msgid "" -" If your inter-cluster distance is sufficiently large (larger than your bulk " -"linking distance), then you can get away with this." +#: ../src/backend/filters/voxelise.cpp:706 +msgid "Enable this ion for numerator" msgstr "" -" If your inter-cluster distance is sufficiently large (larger than your bulk " -"linking distance), then you can get away with this." -#: ../src/filters/clusterAnalysis.cpp:1789 -msgid "" -" In theory it is possible to \"join\" the clusters, but this has not been " -"implemented for speed reasons." +#: ../src/backend/filters/voxelise.cpp:717 +msgid "Denominator" +msgstr "Nenner" + +#: ../src/backend/filters/voxelise.cpp:720 +msgid "Parameter \"b\" used in fraction (a/b) to get voxel value" msgstr "" -"Theoretisch ist es möglich die Cluster zu 'verbinden', dies wurde jedoch aus " -"Gescheindigkeitsgründen nicht implementiert." -#: ../src/filters/clusterAnalysis.cpp:1790 -msgid "" -"If you want this, please contact the author, or just use the source to add " -"this in yourself." +#: ../src/backend/filters/voxelise.cpp:736 +msgid "Enable this ion for denominator contribution" msgstr "" -"Sollten Sie dies wollen, kontaktieren Sie den Autor oder verwenden Sie den " -"Sourcecode um es selbst hinzuzufügen." -#: ../src/filters/clusterAnalysis.cpp:1791 -msgid "---------------------------------------------------------------------- " -msgstr "---------------------------------------------------------------------- " +#: ../src/backend/filters/voxelise.cpp:757 +#: ../src/backend/filters/voxelise.cpp:792 +msgid "Filtering" +msgstr "Filtern" -#: ../src/filters/clusterAnalysis.cpp:1801 ../src/filters/transform.cpp:892 -#: ../src/filters/spatialAnalysis.cpp:278 -#: ../src/filters/spatialAnalysis.cpp:590 -#: ../src/filters/spatialAnalysis.cpp:979 -msgid "Collate" -msgstr "Abgleichen" +#: ../src/backend/filters/voxelise.cpp:761 +msgid "Smoothing method to use on voxels" +msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1820 -msgid "Build Core" +#: ../src/backend/filters/voxelise.cpp:764 +msgid "Processing" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1838 -msgid "Classify Core" +#: ../src/backend/filters/voxelise.cpp:770 +msgid "Kernel Bins" +msgstr "Kernel Bins" + +#: ../src/backend/filters/voxelise.cpp:774 +msgid "Number of bins in convolution kernel" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1931 -msgid "Build Bulk" +#: ../src/backend/filters/voxelise.cpp:785 +msgid "Exterior values" +msgstr "Exterior values" + +#: ../src/backend/filters/voxelise.cpp:788 +msgid "Method to use to treat boundaries of voxel data for convolution" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:1951 -msgid "Core" -msgstr "Kern" +#: ../src/backend/filters/voxelise.cpp:806 +msgid "Representation" +msgstr "Representation" -#: ../src/filters/clusterAnalysis.cpp:2096 -msgid "Bulk" +#: ../src/backend/filters/voxelise.cpp:809 +msgid "3D display method" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2225 -msgid "Erode" +#: ../src/backend/filters/voxelise.cpp:812 +#: ../src/backend/filters/compositionProfile.cpp:1070 +#: ../src/backend/filters/boundingBox.cpp:656 +#: ../src/backend/filters/dataLoad.cpp:565 +msgid "Appearance" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2299 -msgid "Re-Collate" +#: ../src/backend/filters/voxelise.cpp:819 +msgid "Spot size" +msgstr "Spot size" + +#: ../src/backend/filters/voxelise.cpp:822 +msgid "Size of the spots to use for display" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2566 -#: ../src/filters/clusterAnalysis.cpp:2792 -msgid "Cluster Size" +#: ../src/backend/filters/voxelise.cpp:827 +#: ../src/backend/filters/voxelise.cpp:858 +msgid "Transparency" +msgstr "Transparenz" + +#: ../src/backend/filters/voxelise.cpp:830 +msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2567 -#: ../src/filters/clusterAnalysis.cpp:2796 -msgid "Frequency" +#: ../src/backend/filters/voxelise.cpp:838 +msgid "Isovalue" +msgstr "Isovalue" + +#: ../src/backend/filters/voxelise.cpp:841 +msgid "Scalar value to show as isosurface" msgstr "" -#: ../src/filters/clusterAnalysis.cpp:2794 -msgid "Composition" +#: ../src/backend/filters/voxelise.cpp:850 +#: ../src/backend/filters/compositionProfile.cpp:1061 +#: ../src/backend/filters/annotation.cpp:882 +#: ../src/backend/filters/spectrumPlot.cpp:471 +msgid "Colour" +msgstr "Farbe" + +#: ../src/backend/filters/voxelise.cpp:853 +msgid "Colour of isosurface" msgstr "" -#: ../src/filters/dataLoad.cpp:32 -msgid "POS Data" -msgstr "Pos-Daten" +#: ../src/backend/filters/voxelise.cpp:861 +msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)" +msgstr "" -#: ../src/filters/dataLoad.cpp:33 -msgid "Text Data" -msgstr "Text-Daten" +#: ../src/backend/filters/voxelise.cpp:1264 +msgid "Voxelisation aborted" +msgstr "Voxelisation abgebrochen" -#: ../src/filters/dataLoad.cpp:212 -msgid " does not exist" -msgstr " existiert nicht" +#: ../src/backend/filters/voxelise.cpp:1266 +msgid "Out of memory" +msgstr "Zu wenig Speicher" -#: ../src/filters/dataLoad.cpp:249 ../src/filters/dataLoad.cpp:260 -#: ../src/filters/dataLoad.cpp:280 ../src/filters/dataLoad.cpp:292 -msgid "Error loading file: " -msgstr "Fehler beim Laden der Datei: " +#: ../src/backend/filters/voxelise.cpp:1268 +msgid "Unable to perform filter convolution" +msgstr "Kann Filter convolution nicht durchführen" -#: ../src/filters/dataLoad.cpp:306 -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/voxelise.cpp:1270 +msgid "Voxelisation bounds are invalid" +msgstr "Voxelisation Grenzen sin ungültig" -#: ../src/filters/dataLoad.cpp:359 -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" +#: ../src/backend/filters/ionColour.cpp:289 +msgid "Colour Map" +msgstr "Farbtabelle" + +#: ../src/backend/filters/ionColour.cpp:293 +msgid "Colour scheme used to assign points colours by value" msgstr "" -"Warnung: Eine oder mehrere Grenzen der geladenen Daten erreichen das Limit " -"der numerischen Stabilität des internen Datentyps (Größenordnung zu groß). " -"Erwägen Sie die Daten vor dem Laden zu skalieren. " -#: ../src/filters/dataLoad.cpp:366 -msgid "Loaded " -msgstr "Geladen " +#: ../src/backend/filters/ionColour.cpp:301 +msgid "Show Bar" +msgstr "Zeige Balken" -#: ../src/filters/dataLoad.cpp:366 -msgid " Points" -msgstr " Punkte" +#: ../src/backend/filters/ionColour.cpp:308 +msgid "Num Colours" +msgstr "" -#: ../src/filters/dataLoad.cpp:408 -msgid "File type" -msgstr "Dateityp" +#: ../src/backend/filters/ionColour.cpp:310 +msgid "Number of unique colours to use in colour map" +msgstr "" -#: ../src/filters/dataLoad.cpp:424 -msgid "Number of columns" -msgstr "Anzahl der Spalten" +#: ../src/backend/filters/ionColour.cpp:316 +msgid "Map start" +msgstr "" -#: ../src/filters/dataLoad.cpp:465 -msgid "Value Label" +#: ../src/backend/filters/ionColour.cpp:317 +msgid "Assign points with this value to the first colour in map" msgstr "" -#: ../src/filters/dataLoad.cpp:477 -msgid "Enabled" -msgstr "Aktiviert" +#: ../src/backend/filters/ionColour.cpp:324 +msgid "Map end" +msgstr "" -#: ../src/filters/dataLoad.cpp:486 -msgid "Sample data" +#: ../src/backend/filters/ionColour.cpp:325 +msgid "Assign points with this value to the last colour in map" msgstr "" -#: ../src/filters/dataLoad.cpp:493 -msgid "Load Limit (MB)" -msgstr "Ladelimit (MB)" +#: ../src/backend/filters/ionColour.cpp:425 +#: ../src/backend/filters/transform.cpp:1577 +#: ../src/backend/filters/ionInfo.cpp:548 +msgid "Aborted" +msgstr "Abgebrochen" -#: ../src/filters/dataLoad.cpp:499 -msgid "Monitor" -msgstr "Monitor" +#: ../src/backend/filters/compositionProfile.cpp:449 +msgid "Distance" +msgstr "Abstand" -#: ../src/filters/dataLoad.cpp:512 -msgid "Default colour " -msgstr "Bevorzugte Farbe " +#: ../src/backend/filters/compositionProfile.cpp:457 +msgid "Fraction" +msgstr "Anteil" -#: ../src/filters/dataLoad.cpp:517 -msgid "Draw Size" -msgstr "Draw Size" +#: ../src/backend/filters/compositionProfile.cpp:459 +msgid "Density (\\#.len^3)" +msgstr "Dichte (\\#.len^3)" -#: ../src/filters/boundingBox.cpp:39 -msgid "Box only" +#: ../src/backend/filters/compositionProfile.cpp:486 +msgid "Freq. Profile" +msgstr "Häufigkeitsprofil" + +#: ../src/backend/filters/compositionProfile.cpp:584 +msgid "Too many bins in comp. profile." +msgstr "Zu viele Bins im Konzentrationsprofil." + +#: ../src/backend/filters/compositionProfile.cpp:586 +msgid "Not enough memory for comp. profile." +msgstr "Nicht genug Speicher für Konz.-Profil." + +#: ../src/backend/filters/compositionProfile.cpp:588 +msgid "Aborted composition prof." +msgstr "Konzentrationspr. abgebr." + +#: ../src/backend/filters/compositionProfile.cpp:905 +msgid "Primitive type" msgstr "" -#: ../src/filters/boundingBox.cpp:40 -msgid "Tick" +#: ../src/backend/filters/compositionProfile.cpp:909 +msgid "Basic shape to use for profile" msgstr "" -#: ../src/filters/boundingBox.cpp:41 -msgid "Dimension" +#: ../src/backend/filters/compositionProfile.cpp:920 +msgid "Display the 3D composition profile interaction object" msgstr "" -#: ../src/filters/boundingBox.cpp:512 ../src/dialogs/ExportPos.cpp:72 -msgid "Visible" -msgstr "Sichtbar" +#: ../src/backend/filters/compositionProfile.cpp:934 +#: ../src/backend/filters/spatialAnalysis.cpp:596 +msgid "Position for centre of cylinder" +msgstr "" -#: ../src/filters/boundingBox.cpp:526 -msgid "Style" +#: ../src/backend/filters/compositionProfile.cpp:942 +msgid "Vector between ends of cylinder" msgstr "" -#: ../src/filters/boundingBox.cpp:544 -msgid "Fixed Tick Num" -msgstr "Fixed Tick Num" +#: ../src/backend/filters/compositionProfile.cpp:953 +msgid "Prevent length of cylinder changing during interaction" +msgstr "" -#: ../src/filters/boundingBox.cpp:553 -msgid "Num X" -msgstr "Num X" +#: ../src/backend/filters/compositionProfile.cpp:993 +msgid "Fixed Bin Num" +msgstr "Fix. Bin-Anz." -#: ../src/filters/boundingBox.cpp:558 -msgid "Num Y" -msgstr "Num Y" +#: ../src/backend/filters/compositionProfile.cpp:996 +msgid "" +"If true, use a fixed number of bins for profile, otherwise use fixed step " +"size" +msgstr "" -#: ../src/filters/boundingBox.cpp:563 -msgid "Num Z" -msgstr "Num Z" +#: ../src/backend/filters/compositionProfile.cpp:1002 +#: ../src/backend/filters/spatialAnalysis.cpp:420 +#: ../src/backend/filters/spatialAnalysis.cpp:569 +msgid "Num Bins" +msgstr "Bin-Anz." -#: ../src/filters/boundingBox.cpp:569 -msgid "Spacing X" -msgstr "X-Abstand" +#: ../src/backend/filters/compositionProfile.cpp:1007 +msgid "Number of bins to use for profile" +msgstr "" -#: ../src/filters/boundingBox.cpp:574 -msgid "Spacing Y" -msgstr "Y-Abstand" +#: ../src/backend/filters/compositionProfile.cpp:1012 +#: ../src/backend/filters/spectrumPlot.cpp:395 +msgid "Bin width" +msgstr "Bin-Breite" -#: ../src/filters/boundingBox.cpp:579 -msgid "Spacing Z" -msgstr "Z-Abstand" +#: ../src/backend/filters/compositionProfile.cpp:1018 +msgid "Size of each bin in profile" +msgstr "" -#: ../src/filters/boundingBox.cpp:597 -msgid "Box Colour" -msgstr "Box Farbe" +#: ../src/backend/filters/compositionProfile.cpp:1027 +msgid "Convert bin counts into relative frequencies in each bin" +msgstr "" -#: ../src/filters/boundingBox.cpp:605 -msgid "Line thickness" -msgstr "Linienbreite" +#: ../src/backend/filters/compositionProfile.cpp:1048 +#: ../src/backend/filters/spectrumPlot.cpp:458 +msgid "Plot Type" +msgstr "Plot Type" -#: ../src/filters/boundingBox.cpp:614 ../src/filters/annotation.cpp:736 -msgid "Font Size" -msgstr "Schriftgröße" +#: ../src/backend/filters/compositionProfile.cpp:1051 +msgid "Visual style for plot" +msgstr "" -#: ../src/filters/voxelise.cpp:66 -msgid "None (Raw count)" -msgstr "Keine (Roh count)" +#: ../src/backend/filters/compositionProfile.cpp:1064 +msgid "Colour of plot" +msgstr "" -#: ../src/filters/voxelise.cpp:67 -msgid "Volume (Density)" -msgstr "Volumen (Dichte)" +#: ../src/backend/filters/compositionProfile.cpp:1080 +msgid "Err. Estimator" +msgstr "Fehlerschätzer" -#: ../src/filters/voxelise.cpp:68 -msgid "All Ions (conc)" -msgstr "Alle Ionen (Konz)" +#: ../src/backend/filters/compositionProfile.cpp:1083 +msgid "Method of estimating error associated with each bin" +msgstr "" -#: ../src/filters/voxelise.cpp:69 -msgid "Ratio (Num/Denom)" -msgstr "Verhältnis (Zähler/Nenner)" +#: ../src/backend/filters/compositionProfile.cpp:1090 +msgid "Avg. Window" +msgstr "" -#: ../src/filters/voxelise.cpp:73 -msgid "Point Cloud" -msgstr "Punktwolke" +#: ../src/backend/filters/compositionProfile.cpp:1093 +msgid "Number of bins to include in moving average filter" +msgstr "" -#: ../src/filters/voxelise.cpp:74 -msgid "Isosurface" -msgstr "Isosurface" +#: ../src/backend/filters/compositionProfile.cpp:1097 +msgid "Error analysis" +msgstr "" -#: ../src/filters/voxelise.cpp:78 ../src/plot.cpp:39 -msgid "None" -msgstr "Keiner" +#: ../src/backend/filters/spatialAnalysis.cpp:72 +msgid "Local Density" +msgstr "Lokale Dichte" -#: ../src/filters/voxelise.cpp:79 -msgid "Gaussian (2𝜎)" -msgstr "Gauss (2𝜎)" +#: ../src/backend/filters/spatialAnalysis.cpp:73 +msgid "Density Filtering" +msgstr "" -#: ../src/filters/voxelise.cpp:83 -msgid "Zero" -msgstr "Null" +#: ../src/backend/filters/spatialAnalysis.cpp:74 +msgid "Radial Distribution" +msgstr "Radial Distribution" -#: ../src/filters/voxelise.cpp:84 -msgid "Bounce" -msgstr "Bounce" +#: ../src/backend/filters/spatialAnalysis.cpp:75 +msgid "Axial Distribution" +msgstr "" -#: ../src/filters/voxelise.cpp:520 -msgid "Voxel Limits (min,max): (" -msgstr "Voxel Grenzen (min,max): (" +#: ../src/backend/filters/spatialAnalysis.cpp:79 +msgid "Fixed Neighbour Count" +msgstr "Fixed Neighbour Count" -#: ../src/filters/voxelise.cpp:573 -msgid "Fixed width" -msgstr "Fixe Breite" +#: ../src/backend/filters/spatialAnalysis.cpp:80 +msgid "Fixed Radius" +msgstr "Fixierter Radius" -#: ../src/filters/voxelise.cpp:581 -msgid "Bin width x" -msgstr "Bin-Breite x" +#: ../src/backend/filters/spatialAnalysis.cpp:363 +msgid "Spatial analysis algorithm to use" +msgstr "" -#: ../src/filters/voxelise.cpp:586 -msgid "Bin width y" -msgstr "Bin-Breite y" +#: ../src/backend/filters/spatialAnalysis.cpp:385 +msgid "Stop Mode" +msgstr "" -#: ../src/filters/voxelise.cpp:591 -msgid "Bin width z" -msgstr "Bin-Breite Z" +#: ../src/backend/filters/spatialAnalysis.cpp:388 +msgid "Method to use to terminate algorithm when examining each point" +msgstr "" -#: ../src/filters/voxelise.cpp:598 -msgid "Num bins x" -msgstr "Anzahl Bins x" +#: ../src/backend/filters/spatialAnalysis.cpp:395 +msgid "NN Max" +msgstr "NN Max" -#: ../src/filters/voxelise.cpp:603 -msgid "Num bins y" -msgstr "Anzahl Bins y" +#: ../src/backend/filters/spatialAnalysis.cpp:398 +msgid "Maximum number of neighbours to examine" +msgstr "" -#: ../src/filters/voxelise.cpp:608 -msgid "Num bins z" -msgstr "Anzahl Bins z" +#: ../src/backend/filters/spatialAnalysis.cpp:404 +msgid "Dist Max" +msgstr "Abst. Max." -#: ../src/filters/voxelise.cpp:629 -msgid "Normalise by" -msgstr "Normalisieren mit" +#: ../src/backend/filters/spatialAnalysis.cpp:407 +msgid "Maximum distance from each point for search" +msgstr "" -#: ../src/filters/voxelise.cpp:646 -msgid "Numerator" -msgstr "Zähler" +#: ../src/backend/filters/spatialAnalysis.cpp:423 +#: ../src/backend/filters/spatialAnalysis.cpp:572 +msgid "Number of bins for output 1D RDF plot" +msgstr "" -#: ../src/filters/voxelise.cpp:679 -msgid "Denominator" -msgstr "Nenner" +#: ../src/backend/filters/spatialAnalysis.cpp:432 +msgid "Surface Remove" +msgstr "" -#: ../src/filters/voxelise.cpp:720 -msgid "Filtering" -msgstr "Filtern" +#: ../src/backend/filters/spatialAnalysis.cpp:435 +msgid "" +"Exclude surface as part of source to minimise bias in RDF (at cost of " +"increased noise)" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:442 +msgid "Remove Dist" +msgstr "" -#: ../src/filters/voxelise.cpp:729 -msgid "Kernel Bins" -msgstr "Kernel Bins" +#: ../src/backend/filters/spatialAnalysis.cpp:445 +msgid "Minimum distance to remove from surface" +msgstr "" -#: ../src/filters/voxelise.cpp:742 -msgid "Exterior values" -msgstr "Exterior values" +#: ../src/backend/filters/spatialAnalysis.cpp:456 +#: ../src/backend/filters/spatialAnalysis.cpp:581 +msgid "Plot colour " +msgstr "Plotfarbe " -#: ../src/filters/voxelise.cpp:769 -msgid "Representation" -msgstr "Representation" +#: ../src/backend/filters/spatialAnalysis.cpp:459 +#: ../src/backend/filters/spatialAnalysis.cpp:584 +msgid "Colour of output plot" +msgstr "" -#: ../src/filters/voxelise.cpp:778 -msgid "Spot size" -msgstr "Spot size" +#: ../src/backend/filters/spatialAnalysis.cpp:478 +msgid "Source" +msgstr "Quelle" -#: ../src/filters/voxelise.cpp:783 ../src/filters/voxelise.cpp:805 -msgid "Transparency" -msgstr "Transparenz" +#: ../src/backend/filters/spatialAnalysis.cpp:481 +msgid "Ions to use for initiating RDF search" +msgstr "" -#: ../src/filters/voxelise.cpp:791 -msgid "Isovalue" -msgstr "Isovalue" +#: ../src/backend/filters/spatialAnalysis.cpp:497 +msgid "Enable/disable ion as source" +msgstr "" -#: ../src/filters/voxelise.cpp:1216 -msgid "Voxelisation aborted" -msgstr "Voxelisation abgebrochen" +#: ../src/backend/filters/spatialAnalysis.cpp:514 +msgid "Enable/disable all ions as target" +msgstr "" -#: ../src/filters/voxelise.cpp:1218 -msgid "Out of memory" -msgstr "Zu wenig Speicher" +#: ../src/backend/filters/spatialAnalysis.cpp:529 +msgid "Enable/disable this ion as target" +msgstr "" -#: ../src/filters/voxelise.cpp:1220 -msgid "Unable to perform filter convolution" -msgstr "Kann Filter convolution nicht durchführen" +#: ../src/backend/filters/spatialAnalysis.cpp:542 +msgid "Cutoff" +msgstr "" -#: ../src/filters/voxelise.cpp:1222 -msgid "Voxelisation bounds are invalid" -msgstr "Voxelisation Grenzen sin ungültig" +#: ../src/backend/filters/spatialAnalysis.cpp:545 +msgid "Remove points with local density above/below this value" +msgstr "" -#: ../src/filters/ionColour.cpp:278 -msgid "Colour Map" -msgstr "Farbtabelle" +#: ../src/backend/filters/spatialAnalysis.cpp:555 +msgid "Retain Upper" +msgstr "" -#: ../src/filters/ionColour.cpp:288 -msgid "Show Bar" -msgstr "Zeige Balken" +#: ../src/backend/filters/spatialAnalysis.cpp:558 +msgid "Retain either points with density above (enabled) or below cutoff" +msgstr "" -#: ../src/filters/ionColour.cpp:294 -msgid "Num Colours" +#: ../src/backend/filters/spatialAnalysis.cpp:604 +msgid "Vector between centre and end of cylinder" msgstr "" -#: ../src/filters/ionColour.cpp:301 -msgid "Map start" +#: ../src/backend/filters/spatialAnalysis.cpp:622 +msgid "Alg. Params." msgstr "" -#: ../src/filters/ionColour.cpp:306 -msgid "Map end" +#: ../src/backend/filters/spatialAnalysis.cpp:1016 +msgid "Spatial analysis aborted by user" +msgstr "Spatial analysis aborted by user" + +#: ../src/backend/filters/spatialAnalysis.cpp:1018 +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 +msgid "Build" msgstr "" -#: ../src/filters/ionColour.cpp:409 ../src/filters/transform.cpp:1383 -#: ../src/filters/ionInfo.cpp:649 -msgid "Aborted" -msgstr "Abgebrochen" +#: ../src/backend/filters/spatialAnalysis.cpp:1504 +#: ../src/backend/filters/spatialAnalysis.cpp:1558 +msgid "Surface" +msgstr "Oberfläche" -#: ../src/filters/externalProgram.cpp:504 -msgid "Command" -msgstr "Befehl" +#: ../src/backend/filters/spatialAnalysis.cpp:1598 +#: ../src/backend/filters/spatialAnalysis.cpp:1820 +#: ../src/backend/filters/spatialAnalysis.cpp:2116 +msgid "Analyse" +msgstr "Analyse" -#: ../src/filters/externalProgram.cpp:508 -msgid "Work Dir" -msgstr "Arbeitsverzeichnis" +#: ../src/backend/filters/spatialAnalysis.cpp:1655 +#: ../src/backend/filters/spatialAnalysis.cpp:1724 +msgid "Radial Distance" +msgstr "Radialer Abstand" -#: ../src/filters/externalProgram.cpp:523 -msgid "Cleanup input" -msgstr "Bereinige Eingabe" +#: ../src/backend/filters/spatialAnalysis.cpp:1659 +msgid "NN Freq." +msgstr "NN Freq." -#: ../src/filters/externalProgram.cpp:531 -msgid "Cache" -msgstr "Zwischenspeicher" +#: ../src/backend/filters/spatialAnalysis.cpp:1715 +msgid "Warning, " +msgstr "Warnung, " -#: ../src/filters/externalProgram.cpp:616 -msgid "Error processing command line" -msgstr "Fehler beim Ausführen der Kommandozeile" +#: ../src/backend/filters/spatialAnalysis.cpp:1716 +msgid "" +" points were unable to find neighbour points that exceeded the search " +"radius, and thus terminated prematurely" +msgstr "" +" Punkte konnten keine Nachbapunkte die den Suchradius überschritten finden " +"und beendeten vorzeitig." -#: ../src/filters/externalProgram.cpp:618 -msgid "Unable to set working directory" -msgstr "Kann Arbeitsverzeichnis nicht festlegen" +#: ../src/backend/filters/spatialAnalysis.cpp:1726 +msgid " RDF" +msgstr " RDF" -#: ../src/filters/externalProgram.cpp:620 -msgid "Error saving posfile result for external program" -msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm" +#: ../src/backend/filters/spatialAnalysis.cpp:2016 +#: ../src/backend/filters/spatialAnalysis.cpp:2322 +msgid "Number Density (\\#/Vol^3)" +msgstr "Number Density (\\#/Vol^3)" -#: ../src/filters/externalProgram.cpp:622 -msgid "Error saving plot result for externalprogram" -msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm" +#: ../src/backend/filters/spatialAnalysis.cpp:2043 +#: ../src/backend/filters/spatialAnalysis.cpp:2347 +msgid "Warning," +msgstr "Warnung," -#: ../src/filters/externalProgram.cpp:624 -msgid "Error creating temporary directory" -msgstr "Fehler beim Anlegen des temporären Verzeichnisses" +#: ../src/backend/filters/spatialAnalysis.cpp:2044 +#: ../src/backend/filters/spatialAnalysis.cpp:2348 +msgid " points were un-analysable. These have been dropped" +msgstr " points were un-analysable. These have been dropped" -#: ../src/filters/externalProgram.cpp:626 -msgid "Detected unusable number of columns in plot" -msgstr "Detected unusable number of columns in plot" +#: ../src/backend/filters/spatialAnalysis.cpp:2066 +#: ../src/backend/filters/spatialAnalysis.cpp:2370 +msgid "And so on..." +msgstr "Und so weiter..." -#: ../src/filters/externalProgram.cpp:628 -msgid "Unable to parse plot result from external program" -msgstr "Unable to parse plot result from external program" +#: ../src/backend/filters/spatialAnalysis.cpp:2450 +msgid "Extract" +msgstr "" -#: ../src/filters/externalProgram.cpp:630 -msgid "Unable to load ions from external program" -msgstr "Kann Ionen von externem Programm nicht laden" +#: ../src/backend/filters/spatialAnalysis.cpp:2501 +msgid "Reduce" +msgstr "" -#: ../src/filters/externalProgram.cpp:632 -msgid "Unable to perform commandline substitution" -msgstr "Unable to perform commandline substitution" +#: ../src/backend/filters/spatialAnalysis.cpp:2595 +msgid "Compute" +msgstr "" -#: ../src/filters/externalProgram.cpp:634 -msgid "Error executing external program" -msgstr "Fehler beim Ausführen von externem Programm" +#: ../src/backend/filters/spatialAnalysis.cpp:2620 +msgid "Insufficient points to complete analysis" +msgstr "" -#: ../src/filters/transform.cpp:59 ../src/filters/transform.cpp:1217 +#: ../src/backend/filters/spatialAnalysis.cpp:2658 +msgid "Axial Distance" +msgstr "" + +#: ../src/backend/filters/spatialAnalysis.cpp:2660 +msgid " 1D Dist. Func." +msgstr "" + +#: ../src/backend/filters/transform.cpp:77 msgid "Translate" msgstr "Translate" -#: ../src/filters/transform.cpp:60 ../src/filters/transform.cpp:1221 -msgid "Scale" -msgstr "Skaliere" +#: ../src/backend/filters/transform.cpp:78 +msgid "Scale (isotropic)" +msgstr "" + +#: ../src/backend/filters/transform.cpp:79 +msgid "Scale (anisotropic)" +msgstr "" -#: ../src/filters/transform.cpp:61 ../src/filters/transform.cpp:1223 +#: ../src/backend/filters/transform.cpp:80 msgid "Rotate" msgstr "Rotieren" -#: ../src/filters/transform.cpp:62 ../src/filters/transform.cpp:1225 +#: ../src/backend/filters/transform.cpp:81 msgid "Value Shuffle" msgstr "" -#: ../src/filters/transform.cpp:63 ../src/filters/transform.cpp:1227 +#: ../src/backend/filters/transform.cpp:82 msgid "Spatial Noise" msgstr "" -#: ../src/filters/transform.cpp:64 ../src/filters/transform.cpp:1219 +#: ../src/backend/filters/transform.cpp:83 msgid "Translate Value" msgstr "Translate Wert" -#: ../src/filters/transform.cpp:68 +#: ../src/backend/filters/transform.cpp:87 msgid "Specify" msgstr "Angeben" -#: ../src/filters/transform.cpp:69 +#: ../src/backend/filters/transform.cpp:88 msgid "Boundbox Centre" msgstr "Boundbox Zentrum" -#: ../src/filters/transform.cpp:70 +#: ../src/backend/filters/transform.cpp:89 msgid "Mass Centre" msgstr "Massen-Zentrum" -#: ../src/filters/transform.cpp:911 +#: ../src/backend/filters/transform.cpp:1058 msgid "Mass-to-Charge (amu/e)" msgstr "Masse-zu-Ladung (amu/e)" -#: ../src/filters/transform.cpp:974 +#: ../src/backend/filters/transform.cpp:1112 msgid "Shuffle" msgstr "" -#: ../src/filters/transform.cpp:990 +#: ../src/backend/filters/transform.cpp:1128 msgid "Splice" msgstr "" -#: ../src/filters/transform.cpp:1054 ../src/filters/annotation.cpp:515 -msgid "Mode" +#: ../src/backend/filters/transform.cpp:1183 +msgid "Algorithm to use to transform point data" msgstr "" -#: ../src/filters/transform.cpp:1073 +#: ../src/backend/filters/transform.cpp:1199 msgid "Origin mode" msgstr "" -#: ../src/filters/transform.cpp:1078 +#: ../src/backend/filters/transform.cpp:1202 +msgid "Select how transform origin is computed" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1207 msgid "Show marker" msgstr "Zeige Markierung" -#: ../src/filters/transform.cpp:1094 +#: ../src/backend/filters/transform.cpp:1211 +msgid "Display an interactive object to set transform origin" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1213 +msgid "Display a small marker to denote transform origin" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1229 msgid "Translation" msgstr "Translation" -#: ../src/filters/transform.cpp:1129 +#: ../src/backend/filters/transform.cpp:1232 +msgid "Translation vector for transform" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1244 +msgid "Offset" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1248 +msgid "Scalar to use to offset each point's associated value" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1265 +#: ../src/backend/filters/transform.cpp:1292 +msgid "Origin of scale trasnform" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1272 +#: ../src/backend/filters/transform.cpp:1299 msgid "Scale Fact." msgstr "Skalierungsfaktor" -#: ../src/filters/transform.cpp:1151 +#: ../src/backend/filters/transform.cpp:1275 +#: ../src/backend/filters/transform.cpp:1302 +msgid "Enlargement factor for scaling around origin" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1318 +msgid "Origin of rotation" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1326 +msgid "Axis around which to revolve" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1331 msgid "Angle (deg)" msgstr "Winkel (deg)" -#: ../src/filters/transform.cpp:1167 +#: ../src/backend/filters/transform.cpp:1334 +msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1351 msgid "Noise Type" msgstr "" -#: ../src/filters/transform.cpp:1175 +#: ../src/backend/filters/transform.cpp:1354 +msgid "Method to use to degrade point data" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1361 msgid "Noise level" msgstr "" -#: ../src/filters/transform.cpp:1177 +#: ../src/backend/filters/transform.cpp:1363 msgid "Standard dev." msgstr "Standardabweichung" -#: ../src/filters/transform.cpp:1199 +#: ../src/backend/filters/transform.cpp:1371 +msgid "Amplitude of noise" +msgstr "" + +#: ../src/backend/filters/transform.cpp:1383 msgid "Transform Params" msgstr "Transformationsparameter" -#: ../src/filters/transform.cpp:1386 +#: ../src/backend/filters/transform.cpp:1580 msgid "Unable to allocate memory" msgstr "Kann Speicher nicht zuweisen" -#: ../src/filters/transform.cpp:1630 +#: ../src/backend/filters/transform.cpp:1759 msgid "White" msgstr "" -#: ../src/filters/transform.cpp:1632 +#: ../src/backend/filters/transform.cpp:1761 msgid "Gaussian" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:47 -msgid "Local Density" -msgstr "Lokale Dichte" - -#: ../src/filters/spatialAnalysis.cpp:48 -msgid "Density Filtering" +#: ../src/backend/filters/boundingBox.cpp:55 +msgid "Box only" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:49 -msgid "Radial Distribution" -msgstr "Radial Distribution" - -#: ../src/filters/spatialAnalysis.cpp:53 -msgid "Fixed Neighbour Count" -msgstr "Fixed Neighbour Count" - -#: ../src/filters/spatialAnalysis.cpp:54 -msgid "Fixed Radius" -msgstr "Fixierter Radius" - -#: ../src/filters/spatialAnalysis.cpp:308 -#: ../src/filters/spatialAnalysis.cpp:696 -#: ../src/filters/spatialAnalysis.cpp:755 -#: ../src/filters/spatialAnalysis.cpp:1009 -msgid "Build" +#: ../src/backend/filters/boundingBox.cpp:56 +msgid "Tick" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:335 -#: ../src/filters/spatialAnalysis.cpp:786 -#: ../src/filters/spatialAnalysis.cpp:1036 -msgid "Analyse" -msgstr "Analyse" - -#: ../src/filters/spatialAnalysis.cpp:531 -#: ../src/filters/spatialAnalysis.cpp:1242 -msgid "Number Density (\\#/Vol^3)" -msgstr "Number Density (\\#/Vol^3)" - -#: ../src/filters/spatialAnalysis.cpp:558 -#: ../src/filters/spatialAnalysis.cpp:1267 -msgid "Warning," -msgstr "Warnung," - -#: ../src/filters/spatialAnalysis.cpp:559 -#: ../src/filters/spatialAnalysis.cpp:1268 -msgid " points were un-analysable. These have been dropped" -msgstr " points were un-analysable. These have been dropped" - -#: ../src/filters/spatialAnalysis.cpp:581 -#: ../src/filters/spatialAnalysis.cpp:1290 -msgid "And so on..." -msgstr "Und so weiter..." - -#: ../src/filters/spatialAnalysis.cpp:708 -#: ../src/filters/spatialAnalysis.cpp:767 -msgid "Surface" -msgstr "Oberfläche" - -#: ../src/filters/spatialAnalysis.cpp:843 -#: ../src/filters/spatialAnalysis.cpp:916 -msgid "Radial Distance" -msgstr "Radialer Abstand" - -#: ../src/filters/spatialAnalysis.cpp:847 -msgid "NN Freq." -msgstr "NN Freq." - -#: ../src/filters/spatialAnalysis.cpp:906 -msgid "Warning, " -msgstr "Warnung, " - -#: ../src/filters/spatialAnalysis.cpp:907 -msgid "" -" points were unable to find neighbour points that exceeded the search " -"radius, and thus terminated prematurely" +#: ../src/backend/filters/boundingBox.cpp:57 +msgid "Dimension" msgstr "" -" Punkte konnten keine Nachbapunkte die den Suchradius überschritten finden " -"und beendeten vorzeitig." - -#: ../src/filters/spatialAnalysis.cpp:918 -msgid " RDF" -msgstr " RDF" -#: ../src/filters/spatialAnalysis.cpp:1346 -msgid "Stop Mode" +#: ../src/backend/filters/boundingBox.cpp:532 +msgid "If true, show box, otherwise hide box" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1353 -msgid "NN Max" -msgstr "NN Max" - -#: ../src/filters/spatialAnalysis.cpp:1360 -msgid "Dist Max" -msgstr "Abst. Max." - -#: ../src/filters/spatialAnalysis.cpp:1383 -msgid "Surface Remove" +#: ../src/backend/filters/boundingBox.cpp:545 +msgid "Style" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1390 -msgid "Remove Dist" +#: ../src/backend/filters/boundingBox.cpp:548 +msgid "Box display mode" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1401 -msgid "Plot colour " -msgstr "Plotfarbe " - -#: ../src/filters/spatialAnalysis.cpp:1425 -msgid "Source" -msgstr "Quelle" - -#: ../src/filters/spatialAnalysis.cpp:1480 -msgid "Cutoff" -msgstr "" +#: ../src/backend/filters/boundingBox.cpp:559 +msgid "Fixed Tick Num" +msgstr "Fixed Tick Num" -#: ../src/filters/spatialAnalysis.cpp:1490 -msgid "Retain Upper" +#: ../src/backend/filters/boundingBox.cpp:563 +msgid "" +"If true, evenly use specified number of ticks. Otherwise, use distance to " +"determine tick count" msgstr "" -#: ../src/filters/spatialAnalysis.cpp:1855 -msgid "Spatial analysis aborted by user" -msgstr "Spatial analysis aborted by user" - -#: ../src/filters/spatialAnalysis.cpp:1857 -msgid "Insufficient data to complete analysis." -msgstr "Ungenügend Daten zum Fertigstellen der Analyse." - -#: ../src/filters/ionInfo.cpp:41 -msgid "Rectilinear" -msgstr "Geradlinig" - -#: ../src/filters/ionInfo.cpp:42 -msgid "Convex hull" -msgstr "Konvexe Hülle" +#: ../src/backend/filters/boundingBox.cpp:571 +msgid "Num X" +msgstr "Num X" -#: ../src/filters/ionInfo.cpp:305 -msgid "No ions" +#: ../src/backend/filters/boundingBox.cpp:574 +msgid "Tick count in X direction" msgstr "" -#: ../src/filters/ionInfo.cpp:343 -msgid "--Counts--" -msgstr "- Anzahl -" +#: ../src/backend/filters/boundingBox.cpp:579 +msgid "Num Y" +msgstr "Num Y" -#: ../src/filters/ionInfo.cpp:355 -msgid "Total Ranged\t" -msgstr "Gesamt ranged\t" +#: ../src/backend/filters/boundingBox.cpp:582 +msgid "Tick count in Y direction" +msgstr "" -#: ../src/filters/ionInfo.cpp:360 -msgid "Total (incl. unranged)\t" -msgstr "Total (inkl. nicht geranged)" +#: ../src/backend/filters/boundingBox.cpp:587 +msgid "Num Z" +msgstr "Num Z" -#: ../src/filters/ionInfo.cpp:373 -msgid "n/a" +#: ../src/backend/filters/boundingBox.cpp:590 +msgid "Tick count in Z direction" msgstr "" -#: ../src/filters/ionInfo.cpp:383 -msgid "Unranged" -msgstr "Nicht Geranged" - -#: ../src/filters/ionInfo.cpp:399 -msgid "Number of points : " -msgstr "Anzahl der Punkte: " +#: ../src/backend/filters/boundingBox.cpp:596 +msgid "Spacing X" +msgstr "X-Abstand" -#: ../src/filters/ionInfo.cpp:428 -msgid "Rectilinear Bounds : " -msgstr "Geradlinige Grenzen:" +#: ../src/backend/filters/boundingBox.cpp:600 +msgid "Distance between ticks on X axis" +msgstr "" -#: ../src/filters/ionInfo.cpp:433 -msgid "Volume (len^3): " -msgstr "Volumen (Läng.^3)" +#: ../src/backend/filters/boundingBox.cpp:604 +msgid "Spacing Y" +msgstr "Y-Abstand" -#: ../src/filters/ionInfo.cpp:449 -msgid "Convex Volume (len^3): " -msgstr "Konvexes Volumen (Läng.^3)" +#: ../src/backend/filters/boundingBox.cpp:608 +msgid "Distance between ticks on Y axis" +msgstr "" -#: ../src/filters/ionInfo.cpp:451 -msgid "Unable to compute volume" -msgstr "Kann Volumen nicht berechnen" +#: ../src/backend/filters/boundingBox.cpp:612 +msgid "Spacing Z" +msgstr "Z-Abstand" -#: ../src/filters/ionInfo.cpp:480 -msgid "Ranged Density (pts/vol):" -msgstr "Ranged Dichte (pts / vol):" +#: ../src/backend/filters/boundingBox.cpp:616 +msgid "Distance between ticks on Z axis" +msgstr "" -#: ../src/filters/ionInfo.cpp:485 -msgid "Total Density (pts/vol):" -msgstr "Gesamtdichte (pts / vol):" +#: ../src/backend/filters/boundingBox.cpp:619 +msgid "Tick marks" +msgstr "" -#: ../src/filters/ionInfo.cpp:512 -msgid "Compositions" -msgstr "Zusammensetzungen" +#: ../src/backend/filters/boundingBox.cpp:629 +msgid "Box Colour" +msgstr "Box Farbe" -#: ../src/filters/ionInfo.cpp:514 -msgid "Counts" -msgstr "Anzahl" +#: ../src/backend/filters/boundingBox.cpp:633 +msgid "Colour of the bounding box" +msgstr "" -#: ../src/filters/ionInfo.cpp:534 -msgid "Volume" -msgstr "Volumen" +#: ../src/backend/filters/boundingBox.cpp:638 +msgid "Line thickness" +msgstr "Linienbreite" -#: ../src/filters/ionInfo.cpp:647 -msgid "Insufficient memory for operation" -msgstr "Nicht genügend Speicher für Operation" +#: ../src/backend/filters/boundingBox.cpp:642 +msgid "Thickness of the lines used to draw the box" +msgstr "" -#: ../src/filters/ionInfo.cpp:651 -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/boundingBox.cpp:650 +#: ../src/backend/filters/annotation.cpp:833 +msgid "Font Size" +msgstr "Schriftgröße" + +#: ../src/backend/filters/boundingBox.cpp:653 +msgid "Relative size for text" +msgstr "" -#: ../src/filters/annotation.cpp:50 +#: ../src/backend/filters/annotation.cpp:67 msgid "Arrow" msgstr "Pfeil" -#: ../src/filters/annotation.cpp:51 +#: ../src/backend/filters/annotation.cpp:68 msgid "Text" msgstr "Text" -#: ../src/filters/annotation.cpp:52 +#: ../src/backend/filters/annotation.cpp:69 msgid "Arrow+Text" msgstr "Pfeil+Text" -#: ../src/filters/annotation.cpp:53 +#: ../src/backend/filters/annotation.cpp:70 msgid "Angle" msgstr "Winkel" -#: ../src/filters/annotation.cpp:54 +#: ../src/backend/filters/annotation.cpp:71 msgid "Ruler" msgstr "Lineal" -#: ../src/filters/annotation.cpp:540 ../src/filters/annotation.cpp:618 -#: ../src/filters/annotation.cpp:661 ../src/filters/annotation.cpp:725 +#: ../src/backend/filters/annotation.cpp:538 +msgid "Type or style of annotation" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:553 +#: ../src/backend/filters/annotation.cpp:655 +msgid "Text of annotation" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:561 +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 msgid "Up dir" msgstr "Up dir" -#: ../src/filters/annotation.cpp:545 ../src/filters/annotation.cpp:623 -#: ../src/filters/annotation.cpp:656 ../src/filters/annotation.cpp:730 +#: ../src/backend/filters/annotation.cpp:569 +#: ../src/backend/filters/annotation.cpp:820 +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 msgid "Across dir" msgstr "Across dir" -#: ../src/filters/annotation.cpp:551 ../src/filters/annotation.cpp:613 -#: ../src/filters/annotation.cpp:678 +#: ../src/backend/filters/annotation.cpp:577 +#: ../src/backend/filters/annotation.cpp:828 +msgid "Reading direction for annotation" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:582 +#: ../src/backend/filters/annotation.cpp:661 +#: ../src/backend/filters/annotation.cpp:754 msgid "Text size" msgstr "Textgröße" -#: ../src/filters/annotation.cpp:560 ../src/filters/annotation.cpp:590 -#: ../src/filters/annotation.cpp:715 +#: ../src/backend/filters/annotation.cpp:586 +#: ../src/backend/filters/annotation.cpp:665 +#: ../src/backend/filters/annotation.cpp:836 +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 msgid "Start" msgstr "Anfang" -#: ../src/filters/annotation.cpp:565 ../src/filters/annotation.cpp:596 -#: ../src/filters/annotation.cpp:720 +#: ../src/backend/filters/annotation.cpp:598 +#: ../src/backend/filters/annotation.cpp:637 +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 msgid "End" msgstr "Ende" -#: ../src/filters/annotation.cpp:575 ../src/filters/annotation.cpp:628 +#: ../src/backend/filters/annotation.cpp:606 +#: ../src/backend/filters/annotation.cpp:646 +msgid "3D Position to which arrow points" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:612 +#: ../src/backend/filters/annotation.cpp:683 msgid "Tip radius" msgstr "" -#: ../src/filters/annotation.cpp:580 +#: ../src/backend/filters/annotation.cpp:616 +msgid "Size of the arrow head" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:620 msgid "Line size" msgstr "" -#: ../src/filters/annotation.cpp:636 +#: ../src/backend/filters/annotation.cpp:624 +msgid "Thickness of line used to draw arrow stem" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:693 msgid "Position A" msgstr "Position A" -#: ../src/filters/annotation.cpp:641 +#: ../src/backend/filters/annotation.cpp:697 +msgid "Location of first non-central vertex" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:701 msgid "Origin " msgstr "Ursprung " -#: ../src/filters/annotation.cpp:646 +#: ../src/backend/filters/annotation.cpp:705 +msgid "Location of central vertex" +msgstr "" + +#: ../src/backend/filters/annotation.cpp:709 msgid "Position B" msgstr "Position B" -#: ../src/filters/annotation.cpp:667 -msgid "Reflexive" -msgstr "Reflexive" - -#: ../src/filters/annotation.cpp:671 -msgid "Show Angle" -msgstr "Zeige Winkel" - -#: ../src/filters/annotation.cpp:697 -msgid "Digit format" -msgstr "Zahlenformat" +#: ../src/backend/filters/annotation.cpp:713 +msgid "Location of second non-central vertex" +msgstr "" -#: ../src/filters/annotation.cpp:704 -msgid "Sphere size" -msgstr "Kugelgröße" +#: ../src/backend/filters/annotation.cpp:723 +msgid "Reading direction for angle text" +msgstr "" -#: ../src/filters/annotation.cpp:745 -msgid "Fixed ticks" -msgstr "Fixe Marker" +#: ../src/backend/filters/annotation.cpp:728 +msgid "Vector for up direction of angle text" +msgstr "" -#: ../src/filters/annotation.cpp:752 -msgid "Num Ticks" -msgstr "Anzahl Marker" +#: ../src/backend/filters/annotation.cpp:736 +msgid "Reflexive" +msgstr "Reflexive" -#: ../src/filters/annotation.cpp:759 -msgid "Tick Spacing" -msgstr "Markerabstand" +#: ../src/backend/filters/annotation.cpp:739 +msgid "Measure interor (enabled) or exterior angle (disabled)" +msgstr "" -#: ../src/filter.cpp:48 ../src/dialogs/ExportRngDialog.cpp:116 -msgid "Ion" -msgstr "Ion" +#: ../src/backend/filters/annotation.cpp:744 +msgid "Show Angle" +msgstr "Zeige Winkel" -#: ../src/filter.cpp:49 -msgid "Plot" -msgstr "Plot" +#: ../src/backend/filters/annotation.cpp:748 +msgid "Display angle text (when enabled)" +msgstr "" -#: ../src/filter.cpp:50 -msgid "Draw" -msgstr "Zeichnen" +#: ../src/backend/filters/annotation.cpp:758 +msgid "Size of angle text" +msgstr "" -#: ../src/filter.cpp:52 -msgid "Voxel" -msgstr "Voxel" +#: ../src/backend/filters/annotation.cpp:776 +msgid "Digit format" +msgstr "Zahlenformat" -#: ../src/viscontrol.cpp:987 +#: ../src/backend/filters/annotation.cpp:780 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" +"Format of angle text; # for numeral position, '.' for separator, eg ##.## " +"gives 12.34" 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/viscontrol.cpp:1129 -msgid "Failed to allocate parser" -msgstr "Kann Parser nicht zuordnen" +#: ../src/backend/filters/annotation.cpp:786 +msgid "Sphere size" +msgstr "Kugelgröße" -#: ../src/viscontrol.cpp:1165 -msgid "" -"Unable to retrieve root node in input state file... Is this really a non-" -"empty XML file?" +#: ../src/backend/filters/annotation.cpp:790 +msgid "Marker sphere size for manipulating tool" msgstr "" -#: ../src/viscontrol.cpp:1172 -msgid "Base state node missing. Is this really a state XML file??" +#: ../src/backend/filters/annotation.cpp:804 +msgid "Ruler beginning 3D location" msgstr "" -#: ../src/viscontrol.cpp:1201 -msgid "State was created by a newer version of this program.. " -msgstr "Status wurde von einer neueren Version dieses Programmes erstellt.. " +#: ../src/backend/filters/annotation.cpp:812 +msgid "Ruler finish 3D location" +msgstr "" -#: ../src/viscontrol.cpp:1202 -msgid "file reading will continue, but may fail." -msgstr "Datei wird weiter eingelesen kann aber unter Umständen fehlschlagen." +#: ../src/backend/filters/annotation.cpp:845 +msgid "Fixed ticks" +msgstr "Fixe Marker" -#: ../src/viscontrol.cpp:1207 +#: ../src/backend/filters/annotation.cpp:848 msgid "" -"Warning, unparseable version number in state file. File reading will " -"continue, but may fail" +"Use fixed (enabled) number of text markers, or one every fixed distance " +"(disabled)" msgstr "" -"Warnung: Nicht lesbare Versionsnummer in Statusdatei. Datei wird weiter " -"eingelesen kann aber unter Umständen fehlschlagen." - -#: ../src/viscontrol.cpp:1214 -msgid "Unable to find the \"writer\" node" -msgstr "Kann \"writer\" node nicht finden" - -#: ../src/viscontrol.cpp:1224 -msgid "Unable to find the \"backcolour\" node." -msgstr "Unable to find the \"backcolour\" node." -#: ../src/viscontrol.cpp:1231 -msgid "\"backcolour\" node missing \"r\" value." -msgstr "\"backcolour\" node fehlt \"r\" Wert." - -#: ../src/viscontrol.cpp:1236 -msgid "Unable to interpret \"backColour\" node's \"r\" value." -msgstr "Kann \"backColour\" node's \"r\" Wert nicht interpretieren." +#: ../src/backend/filters/annotation.cpp:855 +msgid "Num Ticks" +msgstr "Anzahl Marker" -#: ../src/viscontrol.cpp:1244 -msgid "\"backcolour\" node missing \"g\" value." -msgstr "\"backcolour\" node fehlt \"g\" Wert." +#: ../src/backend/filters/annotation.cpp:858 +msgid "Number of tick marks along ruler" +msgstr "" -#: ../src/viscontrol.cpp:1250 -msgid "Unable to interpret \"backColour\" node's \"g\" value." -msgstr "Kann \"backColour\" node's \"g\" Wert nicht interpretieren." +#: ../src/backend/filters/annotation.cpp:865 +msgid "Tick Spacing" +msgstr "Markerabstand" -#: ../src/viscontrol.cpp:1258 -msgid "\"backcolour\" node missing \"b\" value." -msgstr "\"backcolour\" node fehlt \"b\" Wert." +#: ../src/backend/filters/annotation.cpp:868 +msgid "Distance between tick marks along ruler" +msgstr "" -#: ../src/viscontrol.cpp:1264 -msgid "Unable to interpret \"backColour\" node's \"b\" value." -msgstr "Kann \"backColour\" node's \"b\" Wert nicht interpretieren." +#: ../src/backend/filters/annotation.cpp:885 +msgid "Colour for ruler and ticks" +msgstr "" -#: ../src/viscontrol.cpp:1271 -msgid "\"backcolour\"s rgb values must be in range [0,1]" -msgstr "\"backcolour\"s rgb Wert muss im Bereich [0,1] liegen" +#: ../src/backend/filters/ionDownsample.cpp:464 +msgid "By Count" +msgstr "Nach Anzahl" -#: ../src/viscontrol.cpp:1298 -msgid "Unable to find or interpret \"showaxis\" node" -msgstr "Kann \"showaxis\" node nicht interpretieren" +#: ../src/backend/filters/ionDownsample.cpp:467 +msgid "Sample up to a fixed number of ions" +msgstr "" -#: ../src/viscontrol.cpp:1307 -msgid "Unable to locate \"filtertree\" node." -msgstr "Kann \"filtertree\" node nicht finden." +#: ../src/backend/filters/ionDownsample.cpp:473 +msgid "Per Species" +msgstr "Nach Spezies" -#: ../src/viscontrol.cpp:1323 -msgid "Cameras section missing \"active\" node." -msgstr "Cameras section fehlt \"active\" node." +#: ../src/backend/filters/ionDownsample.cpp:477 +msgid "Use species specific (from ranging) sampling values" +msgstr "" -#: ../src/viscontrol.cpp:1331 -msgid "Unable to find property \"value\" for \"cameras->active\" node." -msgstr "Kann \"Eigenschaftswert\" für \"Kamera->aktiv\" Node nicht finden." +#: ../src/backend/filters/ionDownsample.cpp:482 +msgid "Sampling rates" +msgstr "" -#: ../src/viscontrol.cpp:1337 -msgid "Unable to interpret property \"value\" for \"cameras->active\" node." +#: ../src/backend/filters/ionDownsample.cpp:505 +msgid "Sampling value for species" msgstr "" -"Kann \"Eigenschaftswert\" für \"Kamera->aktiv\" Node nicht interpretieren." -#: ../src/viscontrol.cpp:1359 -msgid "Unable to interpret the camera type" -msgstr "Kann den Kameratype nicht interpretieren" +#: ../src/backend/filters/ionDownsample.cpp:517 +msgid "Output Count" +msgstr "Ausgabe Anzahl" -#: ../src/viscontrol.cpp:1394 -msgid "Unable to locate stash name for stash " -msgstr "Kann den Stashnamen für Stash nicht finden" +#: ../src/backend/filters/ionDownsample.cpp:520 +msgid "Sample up to this value of points" +msgstr "" -#: ../src/viscontrol.cpp:1401 -msgid "Empty stash name for stash " -msgstr "Leerer Stashname für Stash" +#: ../src/backend/filters/ionDownsample.cpp:525 +msgid "Out Fraction" +msgstr "Ausgabe Anteil" -#: ../src/viscontrol.cpp:1407 -msgid "For stash " -msgstr "Für Stash " +#: ../src/backend/filters/ionDownsample.cpp:529 +msgid "Sample this fraction of points" +msgstr "" -#: ../src/viscontrol.cpp:1435 -msgid "Unrecognised effect :" -msgstr "Nichterkannter Effekt :" +#: ../src/backend/filters/ionDownsample.cpp:677 +msgid "Downsample Aborted" +msgstr "Datenreduktion abgebrochen" -#: ../src/viscontrol.cpp:1445 -msgid "Duplicate effect found" -msgstr "Doppelter Effekt gefunden" +#: ../src/backend/filters/ionDownsample.cpp:679 +msgid "Insuffient memory for downsample" +msgstr "Nicht genug Speicher zur Datenreduktion" -#: ../src/viscontrol.cpp:1445 -msgid " cannot use." -msgstr "kann nicht verwenden." +#: ../src/backend/filters/ionInfo.cpp:30 +msgid "Rectilinear" +msgstr "Geradlinig" -#: ../src/viscontrol.cpp:1455 -msgid "Error reading effect : " -msgstr "Fehler beim Lesen:" +#: ../src/backend/filters/ionInfo.cpp:31 +msgid "Convex hull" +msgstr "Konvexe Hülle" -#: ../src/viscontrol.cpp:1516 -msgid "-merge" +#: ../src/backend/filters/ionInfo.cpp:195 +msgid "No ions" msgstr "" -#: ../src/viscontrol.cpp:1521 -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/ionInfo.cpp:233 +msgid "--Counts--" +msgstr "- Anzahl -" -#: ../src/plot.cpp:40 -msgid "Moving avg." -msgstr "Gleit.Durchschn." +#: ../src/backend/filters/ionInfo.cpp:245 +msgid "Total Ranged\t" +msgstr "Gesamt ranged\t" -#: ../src/plot.cpp:44 -msgid "Lines" -msgstr "Linien" +#: ../src/backend/filters/ionInfo.cpp:250 +msgid "Total (incl. unranged)\t" +msgstr "Total (inkl. nicht geranged)" -#: ../src/plot.cpp:45 -msgid "Bars" -msgstr "Block" +#: ../src/backend/filters/ionInfo.cpp:263 +msgid "n/a" +msgstr "" -#: ../src/plot.cpp:46 -msgid "Steps" -msgstr "Stufen" +#: ../src/backend/filters/ionInfo.cpp:273 +msgid "Unranged" +msgstr "Nicht Geranged" -#: ../src/plot.cpp:47 -msgid "Stem" -msgstr "Stem" +#: ../src/backend/filters/ionInfo.cpp:289 +msgid "Number of points : " +msgstr "Anzahl der Punkte: " -#: ../src/plot.cpp:48 -msgid "Points" -msgstr "Punkte" +#: ../src/backend/filters/ionInfo.cpp:318 +msgid "Rectilinear Bounds : " +msgstr "Geradlinige Grenzen:" -#: ../src/plot.cpp:593 ../src/plot.cpp:601 -msgid "Multiple data types" -msgstr "" +#: ../src/backend/filters/ionInfo.cpp:323 +msgid "Volume (len^3): " +msgstr "Volumen (Läng.^3)" -#: ../src/plot.cpp:744 -msgid "Mixed log/non-log:" -msgstr "Gemischt log/nicht-log" +#: ../src/backend/filters/ionInfo.cpp:339 +msgid "Convex Volume (len^3): " +msgstr "Konvexes Volumen (Läng.^3)" -#: ../src/plot.cpp:1201 -msgid "error" -msgstr "Fehler" +#: ../src/backend/filters/ionInfo.cpp:341 +msgid "Unable to compute volume" +msgstr "Kann Volumen nicht berechnen" -#: ../src/filtertreeAnalyse.cpp:92 -msgid "" -"Parent filter has no output, but filter requires input -- there is no point " -"in placing a child filter here." -msgstr "" +#: ../src/backend/filters/ionInfo.cpp:370 +msgid "Ranged Density (pts/vol):" +msgstr "Ranged Dichte (pts / vol):" -#: ../src/filtertreeAnalyse.cpp:93 -msgid "Leaf-only filter with child" -msgstr "" +#: ../src/backend/filters/ionInfo.cpp:375 +msgid "Total Density (pts/vol):" +msgstr "Gesamtdichte (pts / vol):" -#: ../src/filtertreeAnalyse.cpp:103 -msgid "" -"Parent filters' output will be blocked by child, without use. Parent results " -"will be dropped." -msgstr "" +#: ../src/backend/filters/ionInfo.cpp:403 +msgid "Compositions" +msgstr "Zusammensetzungen" -#: ../src/filtertreeAnalyse.cpp:104 ../src/filtertreeAnalyse.cpp:118 -msgid "Bad parent->child pair" +#: ../src/backend/filters/ionInfo.cpp:404 +msgid "Display compositional data for points in console" msgstr "" -#: ../src/filtertreeAnalyse.cpp:117 -msgid "" -"First filter does not output anything useable by child filter. Child filter " -"not useful." -msgstr "" +#: ../src/backend/filters/ionInfo.cpp:408 +msgid "Counts" +msgstr "Anzahl" -#: ../src/filtertreeAnalyse.cpp:296 -msgid "Spatial results possibly altered" +#: ../src/backend/filters/ionInfo.cpp:409 +msgid "Display count data for points in console" msgstr "" -#: ../src/filtertreeAnalyse.cpp:297 -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." +#: ../src/backend/filters/ionInfo.cpp:423 +msgid "Normalise count data" msgstr "" -#: ../src/filtertree.cpp:902 -msgid "WARNING: Skipping node " -msgstr "WARNUNG: Skipping node " +#: ../src/backend/filters/ionInfo.cpp:432 +msgid "Volume" +msgstr "Volumen" -#: ../src/filtertree.cpp:902 -msgid " as it was not recognised" -msgstr " wurde nicht erkannt." +#: ../src/backend/filters/ionInfo.cpp:435 +msgid "Compute volume for point data" +msgstr "" -#: ../src/filtertree.cpp:940 -msgid "Error processing node: " -msgstr "Fehler beim Verarbeiten von Node: " +#: ../src/backend/filters/ionInfo.cpp:450 +msgid "Select volume counting technique" +msgstr "" -#: ../src/APTClasses.cpp:165 -msgid "Memory allocation failure on POS load" -msgstr "Speicherzuweisungsfeher beim Laden der pos-Datei" +#: ../src/backend/filters/ionInfo.cpp:546 +msgid "Insufficient memory for operation" +msgstr "Nicht genügend Speicher für Operation" -#: ../src/APTClasses.cpp:166 -msgid "Error opening pos file" -msgstr "Fehler beim Öffnen der pos-Datei" +#: ../src/backend/filters/ionInfo.cpp:550 +msgid "Bug? Problem with qhull library, cannot run convex hull." +msgstr "Bug? Problem mit qhull Bibliothek. Kann convex hull nicht ausführen." -#: ../src/APTClasses.cpp:167 -msgid "Pos file empty" -msgstr "Pos-Datei ist leer" +#: ../src/backend/filters/dataLoad.cpp:45 +msgid "POS Data" +msgstr "Pos-Daten" -#: ../src/APTClasses.cpp:168 -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/filters/dataLoad.cpp:46 +msgid "Text Data" +msgstr "Text-Daten" -#: ../src/APTClasses.cpp:169 -msgid "Error reading from pos file (after open)" -msgstr "Fehler beim Lesen aus pos-Datei (nach dem öffnen)" +#: ../src/backend/filters/dataLoad.cpp:225 +msgid " does not exist" +msgstr " existiert nicht" -#: ../src/APTClasses.cpp:170 -msgid "Error - Found NaN in pos file" -msgstr "Fehler - Fand NaN in pos-Datei" +#: ../src/backend/filters/dataLoad.cpp:262 +#: ../src/backend/filters/dataLoad.cpp:273 +#: ../src/backend/filters/dataLoad.cpp:293 +#: ../src/backend/filters/dataLoad.cpp:305 +msgid "Error loading file: " +msgstr "Fehler beim Laden der Datei: " -#: ../src/APTClasses.cpp:171 -msgid "Pos load aborted by interrupt." -msgstr "Pos laden durch Interrupt abgebrochen." +#: ../src/backend/filters/dataLoad.cpp:319 +msgid "Data file contained incorrect number of columns -- should be 4, was " +msgstr "Datei enthielt falsche Anzahl von Spalten - sollte 4 sein, war " -#: ../src/APTClasses.cpp:188 -msgid "No numerical data found" -msgstr "Keine numerischen Daten gefunden" +#: ../src/backend/filters/dataLoad.cpp:372 +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 "" +"Warnung: Eine oder mehrere Grenzen der geladenen Daten erreichen das Limit " +"der numerischen Stabilität des internen Datentyps (Größenordnung zu groß). " +"Erwägen Sie die Daten vor dem Laden zu skalieren. " -#: ../src/APTClasses.cpp:189 -msgid "Error re-opening file, after first scan" -msgstr "Fehler beim nochmaligen Öffnen der Datei nach dem ersten Scan" +#: ../src/backend/filters/dataLoad.cpp:379 +msgid "Loaded " +msgstr "Geladen " -#: ../src/APTClasses.cpp:190 -msgid "Unable to read file contents after open" -msgstr "Kann den Dateiinhalt nach dem Öffnen nich lesen" +#: ../src/backend/filters/dataLoad.cpp:379 +msgid " Points" +msgstr " Punkte" -#: ../src/APTClasses.cpp:192 -msgid "Incorrect number of fields in file" -msgstr "Die Datei enthält eine falsche Anzahl von Feldern" +#: ../src/backend/filters/dataLoad.cpp:407 +#: ../src/backend/filters/rangeFile.cpp:504 +msgid "File" +msgstr "Datei" -#: ../src/APTClasses.cpp:193 -msgid "Unable to allocate memory to store data" -msgstr "Kann Speicher nicht zuordnen" +#: ../src/backend/filters/dataLoad.cpp:408 +msgid "File from which to load data" +msgstr "" -#: ../src/APTClasses.cpp:198 -msgid "Error opening file, check name and permissions." -msgstr "Fehler beim Öffnen der Datei, überprüfe Namen und Berechtigungen." +#: ../src/backend/filters/dataLoad.cpp:419 +msgid "File type" +msgstr "Dateityp" -#: ../src/APTClasses.cpp:199 -msgid "" -"Error interpreting range file header, expecting ion count and range count, " -"respectively." +#: ../src/backend/filters/dataLoad.cpp:421 +msgid "Type of file to be loaded" msgstr "" -"Fehler beim Rangedatei interpretieren, erwarte Ionenanzahl bzw. Rangeanzahl." -#: ../src/APTClasses.cpp:200 -msgid "" -"Range file appears to be empty, check file is a proper range file and is not " -"empty." +#: ../src/backend/filters/dataLoad.cpp:435 +msgid "Entries per point" msgstr "" -"Rangedatei scheint leer zu sein. Prüfe ob die Datei wirklich ein Rangedatei " -"und nicht leer ist." -#: ../src/APTClasses.cpp:201 -msgid "Error reading the long name for ion." -msgstr "Fehler beim Lesen des langen Namens für Ion." +#: ../src/backend/filters/dataLoad.cpp:436 +msgid "Number of decimal values in file per 3D point (normally 4)" +msgstr "" -#: ../src/APTClasses.cpp:202 -msgid "Error reading the short name for ion." -msgstr "Fehler beim Lesen des kurzen Namens für Ion." +#: ../src/backend/filters/dataLoad.cpp:464 +msgid "Relative offset of each entry in file for point's X position" +msgstr "" -#: ../src/APTClasses.cpp:203 -msgid "" -"Error reading colour data in the file, expecting 3 decimal values, space " -"separated." +#: ../src/backend/filters/dataLoad.cpp:472 +msgid "Relative offset of each entry in file for point's Y position" msgstr "" -"Fehler beim Lesen der Farbinformationen in der Datei. Erwarte 3, durch " -"Leerzeichen getrennte, Dezimalwerte." -#: ../src/APTClasses.cpp:204 -msgid "" -"Tried skipping to table separator line (line with dashes), but did not find " -"it." +#: ../src/backend/filters/dataLoad.cpp:480 +msgid "Relative offset of each entry in file for point's Z position" msgstr "" -#: ../src/APTClasses.cpp:205 +#: ../src/backend/filters/dataLoad.cpp:488 msgid "" -"Unexpected failure whilst trying to skip over range lead-in data (bit before " -"range start value)" +"Relative offset of each entry in file to use for scalar value of 3D point" msgstr "" -#: ../src/APTClasses.cpp:206 -msgid "Unable to read range start and end values" -msgstr "Kann Anfangs und Endwert des Range nicht lesen" - -#: ../src/APTClasses.cpp:207 -msgid "Unable to read range table entry" -msgstr "Kann Rangetabelleneintrag nich lesen" - -#: ../src/APTClasses.cpp:208 -msgid "" -"Error reading file, unexpected format, are you sure it is a proper range " -"file?" +#: ../src/backend/filters/dataLoad.cpp:491 +msgid "Value Label" msgstr "" -"Fehler beim Lesen der Datei: Unerwartetes Format, sind Sie sicher, dass dies " -"eine korrekte Rangedatei ist?" -#: ../src/APTClasses.cpp:209 -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/filters/dataLoad.cpp:495 +msgid "Name for the scalar value associated with each point" +msgstr "" -#: ../src/APTClasses.cpp:210 -msgid "" -"Range file appears to contain malformed data, check things like start and " -"ends of m/c are not equal or flipped." +#: ../src/backend/filters/dataLoad.cpp:498 +msgid "Format params." msgstr "" -#: ../src/APTClasses.cpp:211 -msgid "Range file appears to be inconsistent (eg, overlapping ranges)" -msgstr "Rangedatei schein inkonsistent zu sein (z.B. überlappende Ranges)" +#: ../src/backend/filters/dataLoad.cpp:504 +msgid "Enabled" +msgstr "Aktiviert" -#: ../src/APTClasses.cpp:212 -msgid "No ion name mapping found for multiple ion." +#: ../src/backend/filters/dataLoad.cpp:508 +msgid "Load this file?" msgstr "" -#: ../src/glPane.cpp:621 -msgid "Use shift/ctrl-space or double tap to alter reset axis" +#: ../src/backend/filters/dataLoad.cpp:516 +msgid "Sample data" msgstr "" -"Verwenden Sie Shift / ⌘-Leertaste oder doppeltippen, um Achsen " -"zurückzusetzen oder zu verändern" -#: ../src/glPane.cpp:878 -msgid "Image progress" -msgstr "Bild Fortschritt" +#: ../src/backend/filters/dataLoad.cpp:519 +msgid "" +"Perform random selection on file contents, instead of loading entire file" +msgstr "" -#: ../src/glPane.cpp:879 -msgid "Rendering tiles..." -msgstr "Rendering tiles..." +#: ../src/backend/filters/dataLoad.cpp:526 +msgid "Load Limit (MB)" +msgstr "Ladelimit (MB)" -#: ../src/glPane.cpp:895 -msgid "Tile " -msgstr "Tile " +#: ../src/backend/filters/dataLoad.cpp:529 +msgid "Limit for size of data to load" +msgstr "" -#: ../src/glPane.cpp:1027 -msgid "Animation progress" -msgstr "Animation-Fortschritt" +#: ../src/backend/filters/dataLoad.cpp:535 +msgid "Monitor" +msgstr "Monitor" -#: ../src/glPane.cpp:1028 -msgid "Rendering sequence..." -msgstr "Renderreihenfolge..." +#: ../src/backend/filters/dataLoad.cpp:539 +msgid "" +"Watch file timestamp to track changes to file contents from other programs" +msgstr "" -#: ../src/glPane.cpp:1060 -msgid "Saving Image " -msgstr "Speichere Bild " +#: ../src/backend/filters/dataLoad.cpp:541 +msgid "Load params." +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:40 -msgid "Range Sources" -msgstr "Range Sources" +#: ../src/backend/filters/dataLoad.cpp:551 +msgid "Default colour " +msgstr "Bevorzugte Farbe " -#: ../src/dialogs/ExportRngDialog.cpp:42 -msgid "Details" -msgstr "Details" +#: ../src/backend/filters/dataLoad.cpp:554 +msgid "Default colour for points, if not overridden by other filters" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:53 -msgid "Source Filter" -msgstr "Source Filter" +#: ../src/backend/filters/dataLoad.cpp:559 +msgid "Draw Size" +msgstr "Draw Size" -#: ../src/dialogs/ExportRngDialog.cpp:54 -msgid "Ions" -msgstr "Ionen" +#: ../src/backend/filters/dataLoad.cpp:562 +msgid "Default size for points, if not overridden by other filters" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:55 -msgid "Ranges" -msgstr "Ranges" +#: ../src/backend/filters/spectrumPlot.cpp:125 +msgid "Extrema" +msgstr "Extrema" -#: ../src/dialogs/ExportRngDialog.cpp:88 ../src/dialogs/prefDialog.cpp:105 -#: ../src/wxcomponents.cpp:266 -msgid "Param" -msgstr "Param." +#: ../src/backend/filters/spectrumPlot.cpp:174 +msgid "count" +msgstr "Anzahl" -#: ../src/dialogs/ExportRngDialog.cpp:90 -msgid "Value2" -msgstr "Wert2" +#: ../src/backend/filters/spectrumPlot.cpp:259 +msgid "Mixed data" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:97 -msgid "Ion Name" -msgstr "Ionenname" +#: ../src/backend/filters/spectrumPlot.cpp:399 +msgid "Step size for spectrum" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:98 -msgid "Num Ranges" -msgstr "Num Ranges" +#: ../src/backend/filters/spectrumPlot.cpp:408 +msgid "Auto Min/max" +msgstr "Auto Min/max" -#: ../src/dialogs/ExportRngDialog.cpp:117 -msgid "Range Start" -msgstr "Range Anfang" +#: ../src/backend/filters/spectrumPlot.cpp:412 +msgid "Automatically compute spectrum upper and lower bound" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:118 -msgid "Range end" -msgstr "Range Ende" +#: ../src/backend/filters/spectrumPlot.cpp:417 +msgid "Min" +msgstr "Min" -#: ../src/dialogs/ExportRngDialog.cpp:152 -msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*" -msgstr "ORNL Format RNG (*.rng)|*.rng|Alle Dateien (*)|*" +#: ../src/backend/filters/spectrumPlot.cpp:420 +msgid "Starting position for spectrum" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:236 -msgid "Export Range" -msgstr "Range exportieren" +#: ../src/backend/filters/spectrumPlot.cpp:425 +msgid "Max" +msgstr "Max" -#: ../src/dialogs/ExportRngDialog.cpp:241 -msgid "List of rangefiles in filter tree" -msgstr "Liste der Rangedateien im Filterbaum" +#: ../src/backend/filters/spectrumPlot.cpp:428 +msgid "Ending position for spectrum" +msgstr "" -#: ../src/dialogs/ExportRngDialog.cpp:243 -msgid "Detailed view of selected range" -msgstr "Detailierte Ansicht des ausgewählten Range" +#: ../src/backend/filters/spectrumPlot.cpp:436 +msgid "Logarithmic" +msgstr "Logarithmisch" -#: ../src/dialogs/filterErrorDialog.cpp:20 -msgid "Error" +#: ../src/backend/filters/spectrumPlot.cpp:439 +msgid "Convert the plot to logarithmic mode" msgstr "" -#: ../src/dialogs/filterErrorDialog.cpp:22 -msgid "Warning" +#: ../src/backend/filters/spectrumPlot.cpp:461 +msgid "Visual style of plot" msgstr "" -#: ../src/dialogs/filterErrorDialog.cpp:25 -#: ../src/dialogs/filterErrorDialog.cpp:35 -msgid "Filter Errors" +#: ../src/backend/filters/spectrumPlot.cpp:474 +msgid "Colour of plotted spectrum" msgstr "" -#: ../src/dialogs/ExportPos.cpp:71 -msgid "Export:" -msgstr "Exportieren:" +#: ../src/backend/filters/spectrumPlot.cpp:708 +msgid "Insufficient memory for spectrum filter." +msgstr "Nicht genügend Speicher für Spektrumfilter" -#: ../src/dialogs/ExportPos.cpp:73 -msgid "Selected Data" -msgstr "Daten auswählen" +#: ../src/backend/filters/spectrumPlot.cpp:710 +msgid "Bad bincount value in spectrum filter." +msgstr "Falsche Binanzahl im Spektrumfilter." -#: ../src/dialogs/ExportPos.cpp:75 -msgid "Available Data" -msgstr "Verfügbare Daten" +#: ../src/backend/filters/rangeFile.cpp:146 +msgid "Pre-Allocate" +msgstr "" -#: ../src/dialogs/ExportPos.cpp:81 -msgid "Selection" -msgstr "Auswahl" +#: ../src/backend/filters/rangeFile.cpp:260 ../src/backend/filter.cpp:46 +msgid "Range" +msgstr "Range" -#: ../src/dialogs/ExportPos.cpp:106 ../src/dialogs/ExportPos.cpp:109 -msgid "Index" -msgstr "Index" +#: ../src/backend/filters/rangeFile.cpp:506 +msgid "File to use for range data" +msgstr "" -#: ../src/dialogs/ExportPos.cpp:446 -msgid "Export Pos Data" -msgstr "POS Daten exportieren" +#: ../src/backend/filters/rangeFile.cpp:518 +msgid "Drop unranged" +msgstr "Nicht gerangete ausschalten" -#: ../src/dialogs/ExportPos.cpp:449 -msgid "Tree of filters, select leaves to show ion data." +#: ../src/backend/filters/rangeFile.cpp:520 +msgid "Remove unranged points when generating output" msgstr "" -#: ../src/dialogs/ExportPos.cpp:451 -msgid "Add all data from all filters" -msgstr "" +#: ../src/backend/filters/rangeFile.cpp:540 +msgid "All Ions" +msgstr "Alle Ionen" -#: ../src/dialogs/ExportPos.cpp:452 -msgid "Add all data from currently selected filter" +#: ../src/backend/filters/rangeFile.cpp:541 +msgid "Enable/disable all ions at once" msgstr "" -#: ../src/dialogs/ExportPos.cpp:453 -msgid "Add selected data from currently selected filter" +#: ../src/backend/filters/rangeFile.cpp:549 +msgid "Species" msgstr "" -#: ../src/dialogs/StashDialog.cpp:46 -msgid "Stashes" +#: ../src/backend/filters/rangeFile.cpp:556 +msgid "IonID " +msgstr "IonID " + +#: ../src/backend/filters/rangeFile.cpp:557 +msgid "Enable/disable specified ion" msgstr "" -#: ../src/dialogs/StashDialog.cpp:49 -msgid "Stashed Tree" +#: ../src/backend/filters/rangeFile.cpp:570 +msgid "Active Ion " +msgstr "Actives Ion " + +#: ../src/backend/filters/rangeFile.cpp:572 +msgid "If true, ion is used in output" msgstr "" -#: ../src/dialogs/StashDialog.cpp:51 -msgid "Properties" +#: ../src/backend/filters/rangeFile.cpp:586 +msgid "Colour " +msgstr "Farbe" + +#: ../src/backend/filters/rangeFile.cpp:589 +msgid "Colour used to represent ion" msgstr "" -#: ../src/dialogs/StashDialog.cpp:87 -msgid "Stashed Trees" -msgstr "Stashed Trees" +#: ../src/backend/filters/rangeFile.cpp:613 +msgid "All Ranges" +msgstr "Alle Range" -#: ../src/dialogs/StashDialog.cpp:90 -msgid "Erase stashed item" +#: ../src/backend/filters/rangeFile.cpp:614 +msgid "Enable/disable all ranges" msgstr "" -#: ../src/dialogs/StashDialog.cpp:91 -msgid "Filter view for current stash" -msgstr "Filteransicht für den aktuellen Stash" +#: ../src/backend/filters/rangeFile.cpp:632 +msgid "Active Rng " +msgstr "Activer Rng " -#: ../src/dialogs/StashDialog.cpp:92 -msgid "Settings for selected filter in current stash" -msgstr "Einstellungen für den ausgewählten Stash" +#: ../src/backend/filters/rangeFile.cpp:635 +msgid "" +"Enable/disable specified range (ion must also be enabled to activiate range)" +msgstr "" -#: ../src/dialogs/StashDialog.cpp:93 -msgid "Available stashes" -msgstr "Verfügbare Stash" +#: ../src/backend/filters/rangeFile.cpp:639 +msgid "Ion " +msgstr "Ion " -#: ../src/dialogs/StashDialog.cpp:157 -msgid "Stash Name" -msgstr "Stash Name" +#: ../src/backend/filters/rangeFile.cpp:642 +msgid "Name of ion associate to this range" +msgstr "" -#: ../src/dialogs/StashDialog.cpp:158 -msgid "Filter Count" -msgstr "Filter Count" +#: ../src/backend/filters/rangeFile.cpp:651 +msgid "Start rng " +msgstr "Start rng " -#: ../src/dialogs/autosaveDialog.cpp:22 -msgid "Remove &All" +#: ../src/backend/filters/rangeFile.cpp:654 +msgid "Start value for range" msgstr "" -#: ../src/dialogs/autosaveDialog.cpp:86 -msgid "Restore state?" -msgstr "" +#: ../src/backend/filters/rangeFile.cpp:659 +msgid "End rng " +msgstr "End rng " -#: ../src/dialogs/autosaveDialog.cpp:96 -msgid "Multiple autosave states were found; would you like to restore one?" +#: ../src/backend/filters/rangeFile.cpp:662 +msgid "Stopping value for range`" msgstr "" -#: ../src/dialogs/prefDialog.cpp:63 ../src/dialogs/prefDialog.cpp:541 -msgid "Preferences" -msgstr "Voreinstellungen" +#: ../src/backend/filters/rangeFile.cpp:966 +msgid "Ranging aborted by user" +msgstr "Ranging durch User abgebrochen" -#: ../src/dialogs/prefDialog.cpp:70 -msgid "Online Updates" -msgstr "Online Updates" +#: ../src/backend/filters/rangeFile.cpp:968 +msgid "Insufficient memory for range" +msgstr "Nicht genug Speicher für Range" -#: ../src/dialogs/prefDialog.cpp:72 -msgid "Panel Display" -msgstr "Panel Display" +#: ../src/backend/filtertreeAnalyse.cpp:93 +msgid "" +"Parent filter has no output, but filter requires input -- there is no point " +"in placing a child filter here." +msgstr "" -#: ../src/dialogs/prefDialog.cpp:73 -msgid "Camera Speed" -msgstr "Kamerageschwindigkeit" +#: ../src/backend/filtertreeAnalyse.cpp:94 +msgid "Leaf-only filter with child" +msgstr "" -#: ../src/dialogs/prefDialog.cpp:74 -msgid "Filter Defaults" -msgstr "Filtervoreinstellungen" +#: ../src/backend/filtertreeAnalyse.cpp:104 +msgid "" +"Parent filters' output will be blocked by child, without use. Parent results " +"will be dropped." +msgstr "" -#: ../src/dialogs/prefDialog.cpp:75 -msgid "Available Filters" -msgstr "Verfügbare Filter" +#: ../src/backend/filtertreeAnalyse.cpp:105 +#: ../src/backend/filtertreeAnalyse.cpp:119 +msgid "Bad parent->child pair" +msgstr "" -#: ../src/dialogs/prefDialog.cpp:78 -msgid "Reset All" -msgstr "Alle zurücksetzen" +#: ../src/backend/filtertreeAnalyse.cpp:118 +msgid "" +"First filter does not output anything useable by child filter. Child filter " +"not useful." +msgstr "" -#: ../src/dialogs/prefDialog.cpp:79 ../src/dialogs/resolutionDialog.cpp:38 -msgid "Reset" -msgstr "Zurücksetzen" +#: ../src/backend/filtertreeAnalyse.cpp:291 +msgid "Spatial results possibly altered" +msgstr "" -#: ../src/dialogs/prefDialog.cpp:81 -msgid "Show all panels" -msgstr "Zeige alle Fenster" +#: ../src/backend/filtertreeAnalyse.cpp:292 +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/dialogs/prefDialog.cpp:82 -msgid "Remember last" -msgstr "Zuletzt verwendet" +#: ../src/backend/filtertreeAnalyse.cpp:453 +msgid "Composition results possibly altered" +msgstr "" -#: ../src/dialogs/prefDialog.cpp:83 -msgid "Show Selected" -msgstr "Zeige Auswahl" +#: ../src/backend/filtertreeAnalyse.cpp:454 +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/dialogs/prefDialog.cpp:86 -msgid "Control Pane" -msgstr "Kontrollfenster" +#: ../src/backend/APT/APTClasses.cpp:32 +msgid "Memory allocation failure on POS load" +msgstr "Speicherzuweisungsfeher beim Laden der pos-Datei" -#: ../src/dialogs/prefDialog.cpp:87 -msgid "Raw Data Panel" -msgstr "Rohdatenfenster" +#: ../src/backend/APT/APTClasses.cpp:33 +msgid "Error opening pos file" +msgstr "Fehler beim Öffnen der pos-Datei" -#: ../src/dialogs/prefDialog.cpp:90 -msgid "Periodically notify about available updates" -msgstr "" +#: ../src/backend/APT/APTClasses.cpp:34 +msgid "Pos file empty" +msgstr "Pos-Datei ist leer" -#: ../src/dialogs/prefDialog.cpp:92 -msgid "Move Rate" -msgstr "Bewegungsgeschwindigkeit" +#: ../src/backend/APT/APTClasses.cpp:35 +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/dialogs/prefDialog.cpp:93 ../src/dialogs/prefDialog.cpp:97 -msgid "(slow)" -msgstr "(langsam)" +#: ../src/backend/APT/APTClasses.cpp:36 +msgid "Error reading from pos file (after open)" +msgstr "Fehler beim Lesen aus pos-Datei (nach dem öffnen)" -#: ../src/dialogs/prefDialog.cpp:95 ../src/dialogs/prefDialog.cpp:99 -msgid "(fast)" -msgstr "(schnell)" +#: ../src/backend/APT/APTClasses.cpp:37 +msgid "Error - Found NaN in pos file" +msgstr "Fehler - Fand NaN in pos-Datei" -#: ../src/dialogs/prefDialog.cpp:96 -msgid "Zoom Rate" -msgstr "Zoomgeschwindigkeit" +#: ../src/backend/APT/APTClasses.cpp:38 +msgid "Pos load aborted by interrupt." +msgstr "Pos laden durch Interrupt abgebrochen." -#: ../src/dialogs/prefDialog.cpp:449 -msgid "Notice" -msgstr "Notiz" +#: ../src/backend/APT/APTClasses.cpp:55 +msgid "No numerical data found" +msgstr "Keine numerischen Daten gefunden" -#: ../src/dialogs/prefDialog.cpp:452 -msgid "For security reasons, defaults are not modifiable for this filter" -msgstr "" -"Aus Sicherheitsgründen können die Voreinstellungen für diesen Filter nicht " -"geändert werden." +#: ../src/backend/APT/APTClasses.cpp:56 +msgid "Error re-opening file, after first scan" +msgstr "Fehler beim nochmaligen Öffnen der Datei nach dem ersten Scan" -#: ../src/dialogs/prefDialog.cpp:482 -msgid "Show all panels when starting program" -msgstr "Zeige alle Fenster beim Programmstart" +#: ../src/backend/APT/APTClasses.cpp:57 +msgid "Unable to read file contents after open" +msgstr "Kann den Dateiinhalt nach dem Öffnen nich lesen" -#: ../src/dialogs/prefDialog.cpp:485 -msgid "Show panels visible at last shutdown when starting program" -msgstr "Beim Programmstart zuletzt eingeschaltete Fenster anzeigen." +#: ../src/backend/APT/APTClasses.cpp:59 +msgid "Incorrect number of fields in file" +msgstr "Die Datei enthält eine falsche Anzahl von Feldern" -#: ../src/dialogs/prefDialog.cpp:492 -msgid "Show selected panels when starting program" -msgstr "Zeige ausgewählte Fenster beim Programmstart" +#: ../src/backend/APT/APTClasses.cpp:60 +msgid "Unable to allocate memory to store data" +msgstr "Kann Speicher nicht zuordnen" -#: ../src/dialogs/prefDialog.cpp:543 -msgid "Set the method of panel layout when starting the program" -msgstr "" +#: ../src/backend/APT/APTRanges.cpp:42 +msgid "Error opening file, check name and permissions." +msgstr "Fehler beim Öffnen der Datei, überprüfe Namen und Berechtigungen." -#: ../src/dialogs/prefDialog.cpp:546 +#: ../src/backend/APT/APTRanges.cpp:43 msgid "" -"Lets the program check the internet to see if updates to the program version " -"are available, then notifies you about updates now and again." +"Error interpreting range file header, expecting ion count and range count, " +"respectively." msgstr "" -"Lässt das Programm via Internet überprüfen ob Updates für diese " -"Programmversion verfügbar sind. Danach informiert es über die neuen Updates." +"Fehler beim Rangedatei interpretieren, erwarte Ionenanzahl bzw. Rangeanzahl." -#: ../src/dialogs/prefDialog.cpp:548 -msgid "Camera translation, orbit and swivel rates. " +#: ../src/backend/APT/APTRanges.cpp:44 +msgid "" +"Range file appears to be empty, check file is a proper range file and is not " +"empty." msgstr "" +"Rangedatei scheint leer zu sein. Prüfe ob die Datei wirklich ein Rangedatei " +"und nicht leer ist." -#: ../src/dialogs/prefDialog.cpp:549 -msgid "Camera zooming rate." -msgstr "Zoomgeschwindigkeit der Kamera" +#: ../src/backend/APT/APTRanges.cpp:45 +msgid "Error reading the long name for ion." +msgstr "Fehler beim Lesen des langen Namens für Ion." -#: ../src/dialogs/prefDialog.cpp:551 -msgid "Reset the filter initial values back to program defaults" -msgstr "" +#: ../src/backend/APT/APTRanges.cpp:46 +msgid "Error reading the short name for ion." +msgstr "Fehler beim Lesen des kurzen Namens für Ion." -#: ../src/dialogs/prefDialog.cpp:552 -msgid "Reset all filter initial values back to program defaults" +#: ../src/backend/APT/APTRanges.cpp:47 +msgid "" +"Error reading colour data in the file, expecting 3 decimal values, space " +"separated." msgstr "" +"Fehler beim Lesen der Farbinformationen in der Datei. Erwarte 3, durch " +"Leerzeichen getrennte, Dezimalwerte." -#: ../src/dialogs/prefDialog.cpp:614 -msgid "Pref" -msgstr "Pref" - -#: ../src/dialogs/prefDialog.cpp:615 -msgid "Startup" -msgstr "Startup" - -#: ../src/dialogs/prefDialog.cpp:616 -msgid "Camera" -msgstr "Kamera" - -#: ../src/dialogs/resolutionDialog.cpp:30 -msgid "Width :" +#: ../src/backend/APT/APTRanges.cpp:48 +msgid "" +"Tried skipping to table separator line (line with dashes), but did not find " +"it." msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:32 -msgid "Height :" +#: ../src/backend/APT/APTRanges.cpp:49 +msgid "" +"Unexpected failure whilst trying to skip over range lead-in data (bit before " +"range start value)" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:34 -msgid "Lock Aspect" +#: ../src/backend/APT/APTRanges.cpp:50 +msgid "" +"Range table had an incorrect number of entries, should be 2 or 3 + number of " +"ranges" msgstr "" -#: ../src/dialogs/resolutionDialog.cpp:445 -msgid "Resolution Selection" -msgstr "" +#: ../src/backend/APT/APTRanges.cpp:51 +msgid "Unable to read range start and end values" +msgstr "Kann Anfangs und Endwert des Range nicht lesen" -#: ../src/mathglPane.cpp:195 -msgid "No plots selected." -msgstr "Kein Plot ausgewählt." +#: ../src/backend/APT/APTRanges.cpp:52 +msgid "Unable to read range table entry" +msgstr "Kann Rangetabelleneintrag nich lesen" -#: ../src/mathglPane.cpp:1051 +#: ../src/backend/APT/APTRanges.cpp:53 msgid "" -"Unable to allocate requested memory.\n" -" Try a lower resolution, or save as vector (SVG)." +"Error reading file, unexpected format, are you sure it is a proper range " +"file?" msgstr "" -"Kann den notwendigen Speicher nicht zuordnen. Versuche eine geringer " -"Auflösung oder speichere als Vektografik (svg)." - -#: ../src/mathglPane.cpp:1053 -msgid "Plotting functions returned an error:\n" -msgstr "Plot-Funktion meldete einen Fehler:\n" +"Fehler beim Lesen der Datei: Unerwartetes Format, sind Sie sicher, dass dies " +"eine korrekte Rangedatei ist?" -#: ../src/mathglPane.cpp:1055 -msgid "File readback check failed" -msgstr "File readback check failed" +#: ../src/backend/APT/APTRanges.cpp:54 +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/mathglPane.cpp:1057 -msgid "Filesize during readback appears to be zero." -msgstr "Filesize during readback appears to be zero." +#: ../src/backend/APT/APTRanges.cpp:55 +msgid "" +"Range file appears to contain malformed data, check things like start and " +"ends of m/c are not equal or flipped." +msgstr "" -#: ../src/wxcomponents.cpp:484 -msgid "Save Data..." -msgstr "Datei speichern..." +#: ../src/backend/APT/APTRanges.cpp:56 +msgid "Range file appears to be inconsistent (eg, overlapping ranges)" +msgstr "Rangedatei schein inkonsistent zu sein (z.B. überlappende Ranges)" -#: ../src/wxcomponents.cpp:485 -msgid "Text File (*.txt)|*.txt|All Files (*)|*" -msgstr "Text Datei (*.txt)|*.txt|Alle Dateien (*)|*" +#: ../src/backend/APT/APTRanges.cpp:57 +msgid "No ion name mapping found for multiple ion." +msgstr "" -#: ../src/wxcomponents.cpp:497 -msgid "Error saving file. Check output dir is writable." +#: ../src/backend/APT/APTRanges.cpp:811 +msgid "" +"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." msgstr "" -"Fehler beim Schreiben der Datei. Stellen Sie sicher, dass das " -"Zielverzeichnis nicht schreibgeschüzt ist." -#: ../src/filters/externalProgram.h:39 -msgid "Ext. Program" -msgstr "Ext. Programm" +#: ../src/backend/filter.cpp:45 +msgid "Draw" +msgstr "Zeichnen" -#: ../src/filters/rangeFile.h:62 -msgid "Ranging" -msgstr "Ranging" +#: ../src/backend/filter.cpp:47 +msgid "Voxel" +msgstr "Voxel" -#: ../src/filters/transform.h:54 +#: ../src/backend/filters/transform.h:71 msgid "Ion. Transform" msgstr "Ion. Transformieren" -#: ../src/filters/compositionProfile.h:86 -msgid "Comp. Prof." -msgstr "Konz. Prof." +#: ../src/backend/filters/ionColour.h:60 +msgid "Spectral Colour" +msgstr "Spectral Farbe" -#: ../src/filters/ionInfo.h:67 -msgid "Ion info" -msgstr "Ioneninfo" +#: ../src/backend/filters/boundingBox.h:72 +msgid "Bound box" +msgstr "Begrenzungs-Box" -#: ../src/filters/ionDownsample.h:63 +#: ../src/backend/filters/ionDownsample.h:79 msgid "Ion Sampler" msgstr "Ion Sampler" -#: ../src/filters/dataLoad.h:114 +#: ../src/backend/filters/ionInfo.h:91 +msgid "Ion info" +msgstr "Ioneninfo" + +#: ../src/backend/filters/dataLoad.h:131 msgid "Pos Data" msgstr "POS-Daten" -#: ../src/filters/boundingBox.h:55 -msgid "Bound box" -msgstr "Begrenzungs-Box" +#: ../src/backend/filters/externalProgram.h:56 +msgid "Ext. Program" +msgstr "Ext. Programm" -#: ../src/filters/ionColour.h:43 -msgid "Spectral Colour" -msgstr "Spectral Farbe" +#: ../src/backend/filters/rangeFile.h:79 +msgid "Ranging" +msgstr "Ranging" + +#: ../src/backend/filters/compositionProfile.h:110 +msgid "Comp. Prof." +msgstr "Konz. Prof." diff -Nru 3depict-0.0.12/translations/checkTranslationDupes.py 3depict-0.0.13/translations/checkTranslationDupes.py --- 3depict-0.0.12/translations/checkTranslationDupes.py 1970-01-01 00:00:00.000000000 +0000 +++ 3depict-0.0.13/translations/checkTranslationDupes.py 2013-03-22 18:31:39.000000000 +0000 @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import sys +import re + +filename="3Depict_de_DE.po" +f = open(filename) + +if not f: + sys.exit("Unable to open file. Exiting") + +curLine=0 + +while True: + curLine=curLine+1; + s=f.readline(); + if(not s): + break; + + if re.match("msgid.*",s): + msgid=s[6:]; + elif re.match("msgstr.*",s): + msgstr=s[7:]; + + if(msgid == msgstr and re.match(".*[A-z].*",msgid)): + print "Duplicate id at " + str(curLine) + diff -Nru 3depict-0.0.12/translations/makeTranslations 3depict-0.0.13/translations/makeTranslations --- 3depict-0.0.12/translations/makeTranslations 2012-11-11 14:34:02.000000000 +0000 +++ 3depict-0.0.13/translations/makeTranslations 2013-04-05 21:27:22.000000000 +0000 @@ -6,7 +6,7 @@ #follow some random poorly documented hierarchy and naming system. (Looking at you gettextize!) #extract program name from sources -- Now with added case sensitivity hack! -PROGRAM_NAME=`cat ../src/basics.cpp | grep PROGRAM_NAME | awk -F= '{print $2}' | sed 's/;//g' | sed 's/\"//g' | sed 's/;//' | sed 's/^\s*//'` +PROGRAM_NAME=`cat ../src/common/basics.cpp | grep PROGRAM_NAME | awk -F= '{print $2}' | sed 's/;//g' | sed 's/\"//g' | sed 's/;//' | sed 's/^\s*//'` #Where do we want to install the translations? (if using this script). TRANSLATION_INSTALL="/usr/share/locale/"