[3depict] 07/07: * Add files not caught by git-import-orig (?)
D Haley
mycae-guest at moszumanska.debian.org
Wed Aug 3 23:47:17 UTC 2016
This is an automated email from the git hooks/post-receive script.
mycae-guest pushed a commit to branch master
in repository 3depict.
commit 4974a7b2826e8929ff230ade54c431895778bb8c
Author: D Haley <mycae at gmx.com>
Date: Thu Aug 4 01:43:45 2016 +0200
* Add files not caught by git-import-orig (?)
---
data/textures/tex-source/3Depict-icon-hires.png | Bin 0 -> 58757 bytes
m4/ax_compare_version.m4 | 177 ++
packaging/RPM/3Depict-0.0.19-font-path.patch | 27 +
packaging/RPM/3Depict-0.0.19-manual-pdf-loc.patch | 16 +
.../patches/iconv-fix-alias2.patch | 13 +
.../patches/mathgl-disable-things | 82 +
.../patches/mathgl-fix-pthread-and-linking | 34 +
.../mingw-debian-cross/patches/qhull-ptr.patch | 17 +
.../patches/qhull2015-cmakefile-replacement | 624 ++++++
src/backend/APT/vtk.cpp | 175 ++
src/backend/APT/vtk.h | 54 +
src/backend/filters/profile.cpp | 1993 ++++++++++++++++++++
src/backend/filters/profile.h | 159 ++
13 files changed, 3371 insertions(+)
diff --git a/data/textures/tex-source/3Depict-icon-hires.png b/data/textures/tex-source/3Depict-icon-hires.png
new file mode 100644
index 0000000..9a56ed0
Binary files /dev/null and b/data/textures/tex-source/3Depict-icon-hires.png differ
diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4
new file mode 100644
index 0000000..74dc0fd
--- /dev/null
+++ b/m4/ax_compare_version.m4
@@ -0,0 +1,177 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_compare_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+# This macro compares two version strings. Due to the various number of
+# minor-version numbers that can exist, and the fact that string
+# comparisons are not compatible with numeric comparisons, this is not
+# necessarily trivial to do in a autoconf script. This macro makes doing
+# these comparisons easy.
+#
+# The six basic comparisons are available, as well as checking equality
+# limited to a certain number of minor-version levels.
+#
+# The operator OP determines what type of comparison to do, and can be one
+# of:
+#
+# eq - equal (test A == B)
+# ne - not equal (test A != B)
+# le - less than or equal (test A <= B)
+# ge - greater than or equal (test A >= B)
+# lt - less than (test A < B)
+# gt - greater than (test A > B)
+#
+# Additionally, the eq and ne operator can have a number after it to limit
+# the test to that number of minor versions.
+#
+# eq0 - equal up to the length of the shorter version
+# ne0 - not equal up to the length of the shorter version
+# eqN - equal up to N sub-version levels
+# neN - not equal up to N sub-version levels
+#
+# When the condition is true, shell commands ACTION-IF-TRUE are run,
+# otherwise shell commands ACTION-IF-FALSE are run. The environment
+# variable 'ax_compare_version' is always set to either 'true' or 'false'
+# as well.
+#
+# Examples:
+#
+# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
+# AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
+#
+# would both be true.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
+# AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
+#
+# would both be false.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
+#
+# would be true because it is only comparing two minor versions.
+#
+# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
+#
+# would be true because it is only comparing the lesser number of minor
+# versions of the two values.
+#
+# Note: The characters that separate the version numbers do not matter. An
+# empty string is the same as version 0. OP is evaluated by autoconf, not
+# configure, so must be a string, not a variable.
+#
+# The author would like to acknowledge Guido Draheim whose advice about
+# the m4_case and m4_ifvaln functions make this macro only include the
+# portions necessary to perform the specific comparison specified by the
+# OP argument in the final configure script.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Tim Toolan <toolan at ele.uri.edu>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 11
+
+dnl #########################################################################
+AC_DEFUN([AX_COMPARE_VERSION], [
+ AC_REQUIRE([AC_PROG_AWK])
+
+ # Used to indicate true or false condition
+ ax_compare_version=false
+
+ # Convert the two version strings to be compared into a format that
+ # allows a simple string comparison. The end result is that a version
+ # string of the form 1.12.5-r617 will be converted to the form
+ # 0001001200050617. In other words, each number is zero padded to four
+ # digits, and non digits are removed.
+ AS_VAR_PUSHDEF([A],[ax_compare_version_A])
+ A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/[[^0-9]]//g'`
+
+ AS_VAR_PUSHDEF([B],[ax_compare_version_B])
+ B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+ -e 's/[[^0-9]]//g'`
+
+ dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
+ dnl # then the first line is used to determine if the condition is true.
+ dnl # The sed right after the echo is to remove any indented white space.
+ m4_case(m4_tolower($2),
+ [lt],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+ ],
+ [gt],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+ ],
+ [le],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+ ],
+ [ge],[
+ ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+ ],[
+ dnl Split the operator from the subversion count if present.
+ m4_bmatch(m4_substr($2,2),
+ [0],[
+ # A count of zero means use the length of the shorter version.
+ # Determine the number of characters in A and B.
+ ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
+ ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
+
+ # Set A to no more than B's length and B to no more than A's length.
+ A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
+ B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
+ ],
+ [[0-9]+],[
+ # A count greater than zero means use only that many subversions
+ A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+ B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+ ],
+ [.+],[
+ AC_WARNING(
+ [illegal OP numeric parameter: $2])
+ ],[])
+
+ # Pad zeros at end of numbers to make same length.
+ ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
+ B="$B`echo $A | sed 's/./0/g'`"
+ A="$ax_compare_version_tmp_A"
+
+ # Check for equality or inequality as necessary.
+ m4_case(m4_tolower(m4_substr($2,0,2)),
+ [eq],[
+ test "x$A" = "x$B" && ax_compare_version=true
+ ],
+ [ne],[
+ test "x$A" != "x$B" && ax_compare_version=true
+ ],[
+ AC_WARNING([illegal OP parameter: $2])
+ ])
+ ])
+
+ AS_VAR_POPDEF([A])dnl
+ AS_VAR_POPDEF([B])dnl
+
+ dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
+ if test "$ax_compare_version" = "true" ; then
+ m4_ifvaln([$4],[$4],[:])dnl
+ m4_ifvaln([$5],[else $5])dnl
+ fi
+]) dnl AX_COMPARE_VERSION
diff --git a/packaging/RPM/3Depict-0.0.19-font-path.patch b/packaging/RPM/3Depict-0.0.19-font-path.patch
new file mode 100644
index 0000000..02f52fc
--- /dev/null
+++ b/packaging/RPM/3Depict-0.0.19-font-path.patch
@@ -0,0 +1,27 @@
+diff -r 7abb69436c2b src/wx/wxcomponents.cpp
+--- src/wx/wxcomponents.cpp Sat Aug 02 05:39:24 2014 -0400
++++ src/wx/wxcomponents.cpp Sat Aug 02 05:40:51 2014 -0400
+@@ -547,16 +547,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 --git a/packaging/RPM/3Depict-0.0.19-manual-pdf-loc.patch b/packaging/RPM/3Depict-0.0.19-manual-pdf-loc.patch
new file mode 100644
index 0000000..31178af
--- /dev/null
+++ b/packaging/RPM/3Depict-0.0.19-manual-pdf-loc.patch
@@ -0,0 +1,16 @@
+diff -r 7abb69436c2b src/gui/mainFrame.cpp
+--- src/gui/mainFrame.cpp Sat Aug 02 05:39:24 2014 -0400
++++ src/gui/mainFrame.cpp Sat Aug 02 05:40:32 2014 -0400
+@@ -2840,9 +2840,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(s))
++ s="/usr/share/doc/3Depict-0.0.8/3Depict-0.0.8-manual.pdf";
+
+ //FIXME: under windows, currently we use "manual.pdf"
+ if(!s.size())
diff --git a/packaging/mingw-debian-cross/patches/iconv-fix-alias2.patch b/packaging/mingw-debian-cross/patches/iconv-fix-alias2.patch
new file mode 100644
index 0000000..f11dc60
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/iconv-fix-alias2.patch
@@ -0,0 +1,13 @@
+--- a/lib/iconv.c.orig 2015-08-01 20:34:47.018022800 +0100
++++ b/lib/iconv.c 2015-08-01 20:35:06.783246600 +0100
+@@ -176,9 +176,6 @@
+ #include "aliases2.h"
+ #undef S
+ };
+-#ifdef __GNUC__
+-__inline
+-#endif
+ const struct alias *
+ aliases2_lookup (register const char *str)
+ {
+
diff --git a/packaging/mingw-debian-cross/patches/mathgl-disable-things b/packaging/mingw-debian-cross/patches/mathgl-disable-things
new file mode 100644
index 0000000..9de0e5c
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/mathgl-disable-things
@@ -0,0 +1,82 @@
+diff -r 5d7a3ac5d87d CMakeLists.txt
+--- a/CMakeLists.txt Sat Apr 23 01:11:46 2016 +0100
++++ b/CMakeLists.txt Sat Apr 23 01:14:12 2016 +0100
+@@ -94,17 +94,17 @@
+ set(MGL_LIB_INSTALL_DIR "lib" CACHE STRING "Set library install directory")
+ string(TIMESTAMP MGL_NIGHT "%d.%m.%y")
+
+-option(enable-double "Enable double precision in MathGL library" ON)
+-option(enable-mpi "Enable mpi" ON)
+-option(enable-opengl "Enable OpenGL support" ON)
+-option(enable-all-docs "Enable all documentation building")
++option(enable-double "Enable double precision in MathGL library" OFF)
++option(enable-mpi "Enable mpi" OFF)
++option(enable-opengl "Enable OpenGL support" OFF)
++option(enable-all-docs "Enable all documentation building" OFF)
+ #option(enable-doc "Enable documentation building")
+ option(enable-all "Enable all core features")
+-option(enable-all-widgets "Enable all Widgets")
+-option(enable-all-swig "Enable all SWIG based interfaces")
++option(enable-all-widgets "Enable all Widgets" OFF)
++option(enable-all-swig "Enable all SWIG based interfaces" OFF)
+ option(enable-rvalue "Enable move constructor support (need C++11)" OFF)
+-option(enable-pthread "Enable POSIX threads support" ON)
+-option(enable-pthr-widget "Enable POSIX threads for widgets" ON)
++option(enable-pthread "Enable POSIX threads support" OFF)
++option(enable-pthr-widget "Enable POSIX threads for widgets" OFF)
+ option(enable-openmp "Enable OpenMP support" OFF)
+
+ if(enable-pthread AND enable-openmp)
+@@ -114,7 +114,7 @@
+ option(enable-lgpl "Enable only LGPL part of MathGL")
+ option(enable-mgl2 "Use names 'libmgl2-*' instead of 'libmgl-*'")
+ option(enable-ltdl "Enable loading modules support" ON)
+-CMAKE_DEPENDENT_OPTION(enable-doc-site "Enable HTML documentation for website" OFF "NOT enable-all-docs" ON)
++CMAKE_DEPENDENT_OPTION(enable-doc-site "Enable HTML documentation for website" OFF "NOT enable-all-docs" O)
+ CMAKE_DEPENDENT_OPTION(enable-doc-html "Enable HTML documentation" OFF "NOT enable-all-docs" ON)
+ CMAKE_DEPENDENT_OPTION(enable-doc-info "Enable INFO documentation" OFF "NOT enable-all-docs" ON)
+ CMAKE_DEPENDENT_OPTION(enable-doc-pdf-ru "Enable Russian PDF documentation" OFF "NOT enable-all-docs" ON)
+@@ -128,16 +128,16 @@
+ CMAKE_DEPENDENT_OPTION(enable-png "Enable png support" ON "NOT enable-all" ON)
+ CMAKE_DEPENDENT_OPTION(enable-jpeg "Enable jpeg support" ON "NOT enable-all" ON)
+ MGL_DEPENDENT_OPTION(enable-gsl "Enable gsl support" ON "NOT enable-lgpl" ON "NOT enable-all" ON)
+-MGL_DEPENDENT_OPTION(enable-hdf4 "Enable hdf4 support" ON "NOT enable-lgpl" ON "NOT enable-all" ON)
+-MGL_DEPENDENT_OPTION(enable-hdf5 "Enable hdf5 support" ON "NOT enable-lgpl" ON "NOT enable-all" ON)
+-CMAKE_DEPENDENT_OPTION(enable-pdf "Enable pdf support" ON "NOT enable-all" ON)
+-CMAKE_DEPENDENT_OPTION(enable-gif "Enable gif support" ON "NOT enable-all" ON)
+-CMAKE_DEPENDENT_OPTION(enable-glut "Enable glut support" ON "NOT enable-all-widgets" ON)
+-CMAKE_DEPENDENT_OPTION(enable-fltk "Enable fltk widget" ON "NOT enable-all-widgets" ON)
+-CMAKE_DEPENDENT_OPTION(enable-wx "Enable wxWidget widget" ON "NOT enable-all-widgets" ON)
+-CMAKE_DEPENDENT_OPTION(enable-qt4 "Enable Qt4 widget" OFF "NOT enable-all-widgets" ON)
+-CMAKE_DEPENDENT_OPTION(enable-qt5 "Enable Qt5 widget" ON "NOT enable-all-widgets" ON)
+-CMAKE_DEPENDENT_OPTION(enable-qt5asqt "Set Qt5 as default libmgl-qt" ON "enable-qt5" ON)
++MGL_DEPENDENT_OPTION(enable-hdf4 "Enable hdf4 support" OFF "NOT enable-lgpl" OFF "NOT enable-all" OFF)
++MGL_DEPENDENT_OPTION(enable-hdf5 "Enable hdf5 support" OFF "NOT enable-lgpl" OFF "NOT enable-all" OFF)
++CMAKE_DEPENDENT_OPTION(enable-pdf "Enable pdf support" OFF "NOT enable-all" OFF)
++CMAKE_DEPENDENT_OPTION(enable-gif "Enable gif support" OFF "NOT enable-all" OFF)
++CMAKE_DEPENDENT_OPTION(enable-glut "Enable glut support" OFF "NOT enable-all-widgets" OFF)
++CMAKE_DEPENDENT_OPTION(enable-fltk "Enable fltk widget" OFF "NOT enable-all-widgets" OFF)
++CMAKE_DEPENDENT_OPTION(enable-wx "Enable wxWidget widget" OFF "NOT enable-all-widgets" OFF)
++CMAKE_DEPENDENT_OPTION(enable-qt4 "Enable Qt4 widget" OFF "NOT enable-all-widgets" OFF)
++CMAKE_DEPENDENT_OPTION(enable-qt5 "Enable Qt5 widget" OFF "NOT enable-all-widgets" OFF)
++CMAKE_DEPENDENT_OPTION(enable-qt5asqt "Set Qt5 as default libmgl-qt" OFF "enable-qt5" OFF)
+
+ if(UNIX AND enable-rvalue)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
+@@ -149,11 +149,11 @@
+ set(QT_ENABLED ON)
+ endif(enable-qt4 OR enable-qt5)
+
+-CMAKE_DEPENDENT_OPTION(enable-json-sample "Enable JSON sample" ON "QT_ENABLED" ON)
+-MGL_DEPENDENT_OPTION(enable-python "Enable python interface" ON "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
+-MGL_DEPENDENT_OPTION(enable-lua "Enable Lua (v.5.1) interface" OFF "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
+-MGL_DEPENDENT_OPTION(enable-octave "Enable octave interface" ON "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
+-MGL_DEPENDENT_OPTION(enable-octave-install "Octave interface will install for all users" ON "NOT enable-lgpl" ON "NOT enable-all-swig" ON)
++CMAKE_DEPENDENT_OPTION(enable-json-sample "Enable JSON sample" OFF "QT_ENABLED" OFF)
++MGL_DEPENDENT_OPTION(enable-python "Enable python interface" OFF "NOT enable-lgpl" OFF "NOT enable-all-swig" OFF)
++MGL_DEPENDENT_OPTION(enable-lua "Enable Lua (v.5.1) interface" OFF "NOT enable-lgpl" OFF "NOT enable-all-swig" OFF)
++MGL_DEPENDENT_OPTION(enable-octave "Enable octave interface" OFF "NOT enable-lgpl" OFF "NOT enable-all-swig" OFF)
++MGL_DEPENDENT_OPTION(enable-octave-install "Octave interface will install for all users" OFF "NOT enable-lgpl" OFF "NOT enable-all-swig" OFF)
+
+ include_directories( ${MathGL_SOURCE_DIR}/include ${MathGL_BINARY_DIR}/include)
+ set(MGL_INCLUDE_PATH "${CMAKE_INSTALL_PREFIX}/include/mgl2")
diff --git a/packaging/mingw-debian-cross/patches/mathgl-fix-pthread-and-linking b/packaging/mingw-debian-cross/patches/mathgl-fix-pthread-and-linking
new file mode 100644
index 0000000..7f7fe88
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/mathgl-fix-pthread-and-linking
@@ -0,0 +1,34 @@
+diff -r 9fbd31e8af49 CMakeLists.txt
+--- a/CMakeLists.txt Sun Sep 20 14:25:16 2015 +0100
++++ b/CMakeLists.txt Sun Sep 20 14:26:23 2015 +0100
+@@ -12,9 +12,9 @@
+ set(MathGL_VERSION_MINOR 2.2)
+ set(MathGL_SOVERSION 7.2.0)
+
+-set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro")
+-set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro")
+-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro")
++set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -lpng")
++set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lpng")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lpng")
+
+ MACRO(MGL_DEPENDENT_OPTION option doc default depends1 force1 depends2 force2)
+ IF(${option}_ISSET MATCHES "^${option}_ISSET$")
+@@ -61,7 +61,7 @@
+
+ set(MGL_LIB_INSTALL_DIR "lib" CACHE STRING "Set library install directory")
+
+-option(enable-double "Enable double precision in MathGL library" OFF)
++option(enable-double "Enable double precision in MathGL library" ON)
+ option(enable-simple "Slightly increase drawing speed but disable mglDataA class")
+ option(enable-mpi "Enable mpi" OFF)
+ option(enable-opengl "Enable OpenGL support" OFF)
+@@ -70,7 +70,7 @@
+ option(enable-all "Enable all core features")
+ option(enable-all-widgets "Enable all Widgets" OFF)
+ option(enable-all-swig "Enable all SWIG based interfaces" OFF)
+-option(enable-pthread "Enable POSIX threads support" ON)
++option(enable-pthread "Enable POSIX threads support" OFF)
+ option(enable-openmp "Enable OpenMP support" OFF)
+ option(enable-lgpl "Enable only LGPL part of MathGL")
+ option(enable-mgl2 "Use names 'libmgl2-*' instead of 'libmgl-*'")
diff --git a/packaging/mingw-debian-cross/patches/qhull-ptr.patch b/packaging/mingw-debian-cross/patches/qhull-ptr.patch
new file mode 100644
index 0000000..6892493
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/qhull-ptr.patch
@@ -0,0 +1,17 @@
+diff -r ec21eff71acf src/libqhull_r/mem_r.h
+--- a/src/libqhull_r/mem_r.h Sun Apr 24 16:13:34 2016 +0100
++++ b/src/libqhull_r/mem_r.h Sun Apr 24 16:15:10 2016 +0100
+@@ -88,13 +88,7 @@
+ Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
+ This matches Qt convention and is easier to work with.
+ */
+-#if (defined(__MINGW64__)) && defined(_WIN64)
+ typedef long long ptr_intT;
+-#elif (_MSC_VER) && defined(_WIN64)
+-typedef long long ptr_intT;
+-#else
+-typedef long ptr_intT;
+-#endif
+
+ /*-<a href="qh-mem_r.htm#TOC"
+ >--------------------------------</a><a name="qhmemT">-</a>
diff --git a/packaging/mingw-debian-cross/patches/qhull2015-cmakefile-replacement b/packaging/mingw-debian-cross/patches/qhull2015-cmakefile-replacement
new file mode 100644
index 0000000..d152d4d
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/qhull2015-cmakefile-replacement
@@ -0,0 +1,624 @@
+# CMakeLists.txt -- CMake configuration file for qhull, qhull6, and related programs
+#
+# To install CMake
+# Download from http://www.cmake.org/download/
+#
+# To find the available targets for CMake -G "..."
+# cmake --help
+#
+# To build with MSYS/mingw
+# cd build && cmake -G "MSYS Makefiles" .. && cmake ..
+# make
+# make install
+#
+# To uninstall on unix or MSYS/mingw
+# xargs rm <build/install_manifest.txt
+#
+# To build Qhull with Visual Studio projects, run cmake twice
+# To install bin/doc/include/lib in the current directory
+# mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012" .. && cmake -DCMAKE_INSTALL_PREFIX=.. ..
+# mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012 Win64" .. && cmake -DCMAKE_INSTALL_PREFIX=.. ..
+# To install into Program Files/qhull
+# mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012" .. && cmake ..
+# mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 11 2012 Win64" .. && cmake ..
+# To build for Visual Studio 2005 and install into Program Files/qhull
+# mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 8 2005" .. && cmake ..
+# mkdir -p build-cmake && cd build-cmake && cmake -G "Visual Studio 8 2005 Win64" .. && cmake ..
+# Double click build-cmake/qhull-all.sln
+# Build INSTALL to copy files into C:/Program Files/qhull
+#
+# Additional build targets
+# qhullp -- Same as qhull using qh_QHpointer and deprecated libqhull_p
+# user_egp -- Same as user_eg using qh_QHpointer and deprecated libqhull_p
+#
+# Notes on Visual Studio projects
+# You may need to copy bin/msvcr80.dll into C:/Program Files/qhull/bin
+# If using library debug targets, please rename with '_d' (e.g., qhullstatic_d.lib)
+#
+# Troubleshooting
+# "No CMAKE_C_COMPILER could be found"
+# cmake was not able to find the build environment specified (e.g., Visual Studio 11)
+#
+# To uninstall on Windows
+# Delete C:/Program Files/qhull
+#
+# If creating a qhull package, please include a pkg-config file based on build/qhull*.pc.in
+#
+# For qhulltest, use the Qt build (src/qhull-all.pro)
+#
+# Qhull ships with cmake-derived sln and proj files for DevStudio 8 2005
+# See eg/make-vcproj.sh
+# Change to relative paths
+# Remove ZERO_CHECK, ALL_BUILD, and INSTALL projects
+# Change targets to bin/ and lib/ directories
+# Disable incremental linking and ilk files (LinkIncremental="1")
+# Disable Run-Time Type Info (rtti)
+# Remove src/libqhullcpp from most of the AdditionalIncludeDirectories
+# Remove CMAKE_INTDIR from PreprocessorDefinitions
+# Adjust target names and destinations (e.g., lib/libqhullstatic_rd.a)
+#
+# $Id: //main/2015/qhull/CMakeLists.txt#8 $$Change: 2066 $
+# $DateTime: 2016/01/18 19:29:17 $$Author: bbarber $
+
+project(qhull)
+cmake_minimum_required(VERSION 2.6)
+set(CMAKE_BUILD_TYPE "Release")
+
+# Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, qhull-warn.pri
+set(qhull_VERSION2 "2015.2 2016/01/18") # not used, See global.c, global_r.c, rbox.c, rbox_r.c
+set(qhull_VERSION "7.2.0") # Advance every release
+
+# SOVERSION -- qhull 2003 = empty, 2009 = 5, 2010-2012 = 6, 2015 (reentrant) = 7
+set(qhull_SOVERSION 7) # For SOVERSION
+
+include(CMakeModules/CheckLFS.cmake)
+option(WITH_LFS "Enable Large File Support" ON)
+check_lfs(WITH_LFS)
+
+if(INCLUDE_INSTALL_DIR)
+else()
+set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include)
+endif()
+if(LIB_INSTALL_DIR)
+else()
+set(LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib)
+endif()
+if(BIN_INSTALL_DIR)
+else()
+set(BIN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/bin)
+endif()
+if(MAN_INSTALL_DIR)
+else()
+ if(WIN32)
+ set(MAN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/man/man1)
+ else()
+ set(MAN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/man/man1)
+ endif()
+endif()
+if(DOC_INSTALL_DIR)
+else()
+ if(WIN32)
+ set(DOC_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/doc)
+ else()
+ set(DOC_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/doc/qhull)
+ endif()
+endif()
+message(STATUS)
+message(STATUS "========== qhull Build Information ==========")
+message(STATUS "Build Version: ${qhull_VERSION}")
+message(STATUS "Install Prefix (CMAKE_INSTALL_PREFIX): ${CMAKE_INSTALL_PREFIX}")
+message(STATUS "Binary Directory (BIN_INSTALL_DIR): ${BIN_INSTALL_DIR}")
+message(STATUS "Library Directory (LIB_INSTALL_DIR): ${LIB_INSTALL_DIR}")
+message(STATUS "Include Directory (INCLUDE_INSTALL_DIR): ${INCLUDE_INSTALL_DIR}")
+message(STATUS "Documentation Directory (DOC_INSTALL_DIR): ${DOC_INSTALL_DIR}")
+message(STATUS "Man Pages Directory (MAN_INSTALL_DIR): ${MAN_INSTALL_DIR}")
+message(STATUS "Build Type (CMAKE_BUILD_TYPE): ${CMAKE_BUILD_TYPE}")
+message(STATUS "To override these options, add -D{OPTION_NAME}=... to the cmake command")
+message(STATUS " Build the debug targets -DCMAKE_BUILD_TYPE=Debug")
+message(STATUS)
+message(STATUS "To build and install qhull, enter \"make\" and \"make install\"")
+message(STATUS "To smoketest qhull, enter \"ctest\"")
+message(STATUS)
+
+
+# ---------------------------------------
+# Define library source files and variables
+#
+# Files for individual targets are defined with the target
+# ---------------------------------------
+
+# Order libqhull object files by frequency of execution. Small files at end.
+
+## Non-reentrant Qhull
+#set(
+# libqhull_HEADERS
+# src/libqhull/libqhull.h
+# src/libqhull/geom.h
+# src/libqhull/io.h
+# src/libqhull/mem.h
+# src/libqhull/merge.h
+# src/libqhull/poly.h
+# src/libqhull/qhull_a.h
+# src/libqhull/qset.h
+# src/libqhull/random.h
+# src/libqhull/stat.h
+# src/libqhull/user.h
+#)
+#set(
+# libqhull_SOURCES
+# src/libqhull/global.c
+# src/libqhull/stat.c
+# src/libqhull/geom2.c
+# src/libqhull/poly2.c
+# src/libqhull/merge.c
+# src/libqhull/libqhull.c
+# src/libqhull/geom.c
+# src/libqhull/poly.c
+# src/libqhull/qset.c
+# src/libqhull/mem.c
+# src/libqhull/random.c
+# src/libqhull/usermem.c
+# src/libqhull/userprintf.c
+# src/libqhull/io.c
+# src/libqhull/user.c
+# src/libqhull/rboxlib.c
+# src/libqhull/userprintf_rbox.c
+# ${libqhull_HEADERS}
+#)
+
+set(
+ libqhull_DOC
+ src/libqhull/index.htm
+ src/libqhull/qh-geom.htm
+ src/libqhull/qh-globa.htm
+ src/libqhull/qh-io.htm
+ src/libqhull/qh-mem.htm
+ src/libqhull/qh-merge.htm
+ src/libqhull/qh-poly.htm
+ src/libqhull/qh-qhull.htm
+ src/libqhull/qh-set.htm
+ src/libqhull/qh-stat.htm
+ src/libqhull/qh-user.htm
+ src/libqhull/DEPRECATED.txt
+)
+
+#set(
+# testqset_HEADERS
+# src/libqhull/mem.h
+# src/libqhull/qset.h
+#)
+#set(
+# testqset_SOURCES
+# src/libqhull/qset.c
+# src/libqhull/mem.c
+# src/libqhull/usermem.c
+# src/testqset/testqset.c
+# ${testqset_HEADERS}
+#)
+
+# Reeentrant Qhull
+
+set(
+ libqhullr_HEADERS
+ src/libqhull_r/libqhull_r.h
+ src/libqhull_r/geom_r.h
+ src/libqhull_r/io_r.h
+ src/libqhull_r/mem_r.h
+ src/libqhull_r/merge_r.h
+ src/libqhull_r/poly_r.h
+ src/libqhull_r/qhull_ra.h
+ src/libqhull_r/qset_r.h
+ src/libqhull_r/random_r.h
+ src/libqhull_r/stat_r.h
+ src/libqhull_r/user_r.h
+)
+set(
+ libqhullr_SOURCES
+ src/libqhull_r/global_r.c
+ src/libqhull_r/stat_r.c
+ src/libqhull_r/geom2_r.c
+ src/libqhull_r/poly2_r.c
+ src/libqhull_r/merge_r.c
+ src/libqhull_r/libqhull_r.c
+ src/libqhull_r/geom_r.c
+ src/libqhull_r/poly_r.c
+ src/libqhull_r/qset_r.c
+ src/libqhull_r/mem_r.c
+ src/libqhull_r/random_r.c
+ src/libqhull_r/usermem_r.c
+ src/libqhull_r/userprintf_r.c
+ src/libqhull_r/io_r.c
+ src/libqhull_r/user_r.c
+ src/libqhull_r/rboxlib_r.c
+ src/libqhull_r/userprintf_rbox_r.c
+ ${libqhullr_HEADERS}
+)
+
+set(
+ libqhullr_DOC
+ src/libqhull_r/index.htm
+ src/libqhull_r/qh-geom_r.htm
+ src/libqhull_r/qh-globa_r.htm
+ src/libqhull_r/qh-io_r.htm
+ src/libqhull_r/qh-mem_r.htm
+ src/libqhull_r/qh-merge_r.htm
+ src/libqhull_r/qh-poly_r.htm
+ src/libqhull_r/qh-qhull_r.htm
+ src/libqhull_r/qh-set_r.htm
+ src/libqhull_r/qh-stat_r.htm
+ src/libqhull_r/qh-user_r.htm
+)
+
+set(
+ testqsetr_HEADERS
+ src/libqhull_r/mem_r.h
+ src/libqhull_r/qset_r.h
+)
+set(
+ testqsetr_SOURCES
+ src/libqhull_r/qset_r.c
+ src/libqhull_r/mem_r.c
+ src/libqhull_r/usermem_r.c
+ src/testqset_r/testqset_r.c
+ ${testqsetr_HEADERS}
+)
+
+# C++ interface to reentrant Qhull
+
+#set(
+# libqhullcpp_HEADERS
+# src/libqhullcpp/Coordinates.h
+# src/libqhullcpp/functionObjects.h
+# src/libqhullcpp/PointCoordinates.h
+# src/libqhullcpp/Qhull.h
+# src/libqhullcpp/QhullError.h
+# src/libqhullcpp/QhullFacet.h
+# src/libqhullcpp/QhullFacetList.h
+# src/libqhullcpp/QhullFacetSet.h
+# src/libqhullcpp/QhullHyperplane.h
+# src/libqhullcpp/QhullIterator.h
+# src/libqhullcpp/QhullLinkedList.h
+# src/libqhullcpp/QhullPoint.h
+# src/libqhullcpp/QhullPoints.h
+# src/libqhullcpp/QhullPointSet.h
+# src/libqhullcpp/QhullQh.h
+# src/libqhullcpp/QhullRidge.h
+# src/libqhullcpp/QhullSet.h
+# src/libqhullcpp/QhullSets.h
+# src/libqhullcpp/QhullStat.h
+# src/libqhullcpp/QhullVertex.h
+# src/libqhullcpp/QhullVertexSet.h
+# src/libqhullcpp/RboxPoints.h
+# src/libqhullcpp/RoadError.h
+# src/libqhullcpp/RoadLogEvent.h
+# src/qhulltest/RoadTest.h
+#)
+
+#set(
+# libqhullcpp_SOURCES
+# src/libqhullcpp/Coordinates.cpp
+# src/libqhullcpp/PointCoordinates.cpp
+# src/libqhullcpp/Qhull.cpp
+# src/libqhullcpp/QhullFacet.cpp
+# src/libqhullcpp/QhullFacetList.cpp
+# src/libqhullcpp/QhullFacetSet.cpp
+# src/libqhullcpp/QhullHyperplane.cpp
+# src/libqhullcpp/QhullPoint.cpp
+# src/libqhullcpp/QhullPointSet.cpp
+# src/libqhullcpp/QhullPoints.cpp
+# src/libqhullcpp/QhullQh.cpp
+# src/libqhullcpp/QhullRidge.cpp
+# src/libqhullcpp/QhullSet.cpp
+# src/libqhullcpp/QhullStat.cpp
+# src/libqhullcpp/QhullVertex.cpp
+# src/libqhullcpp/QhullVertexSet.cpp
+# src/libqhullcpp/RboxPoints.cpp
+# src/libqhullcpp/RoadError.cpp
+# src/libqhullcpp/RoadLogEvent.cpp
+# ${libqhullcpp_HEADERS}
+#)
+#
+# Documentation files (index.htm refers to html/...)
+
+set(
+ doc_FILES
+ README.txt
+ REGISTER.txt
+ Announce.txt
+ COPYING.txt
+ index.htm
+)
+
+include_directories(${CMAKE_SOURCE_DIR}/src)
+
+if(CMAKE_BUILD_TYPE MATCHES "[dD]ebug")
+ set(qhull_CPP qhullcpp_d)
+ set(qhull_SHARED qhull_d)
+ set(qhull_SHAREDP qhull_pd)
+ set(qhull_SHAREDR qhull_rd)
+ set(qhull_STATIC qhullstatic_d)
+ set(qhull_STATICR qhullstatic_rd)
+else()
+ set(qhull_CPP qhullcpp)
+ set(qhull_SHARED libqhull) # Temporarily avoid name conflict with qhull executable
+ set(qhull_SHAREDP qhull_p)
+ set(qhull_SHAREDR qhull_r)
+ set(qhull_STATIC qhullstatic)
+ set(qhull_STATICR qhullstatic_r)
+endif()
+
+set(
+ qhull_TARGETS_INSTALL ${qhull_SHAREDR}
+)
+set(
+ qhull_TARGETS_TEST # Unused
+ user_eg user_eg2 user_eg3 user_egp testqset testqset_r
+)
+
+# ---------------------------------------
+# Define shared library for reentrant qhull (installed)
+# ---------------------------------------
+
+add_library(${qhull_SHAREDR} SHARED
+ ${libqhullr_SOURCES}
+ src/libqhull_r/qhull_r-exports.def)
+set_target_properties(${qhull_SHAREDR} PROPERTIES
+ SOVERSION ${qhull_SOVERSION}
+ VERSION ${qhull_VERSION})
+
+if(UNIX)
+ target_link_libraries(${qhull_SHAREDR} m)
+ if(APPLE)
+ set_target_properties(${qhull_SHAREDR} PROPERTIES
+ INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
+ else()
+ set_target_properties(${qhull_SHAREDR} PROPERTIES
+ INSTALL_RPATH "${LIB_INSTALL_DIR}"
+ INSTALL_RPATH_USE_LINK_PATH TRUE
+ BUILD_WITH_INSTALL_RPATH FALSE)
+ endif()
+endif(UNIX)
+
+# ---------------------------------------
+# Define shared library for non-reentrant qhull without qh_QHpointer
+# ---------------------------------------
+
+#add_library(${qhull_SHARED} SHARED
+# ${libqhull_SOURCES}
+# src/libqhull/qhull-exports.def)
+#
+#if(qhull_SHARED MATCHES "libqhull")
+# set(qhull_OUTPUT_NAME qhull)
+# set_target_properties(${qhull_SHARED} PROPERTIES
+# OUTPUT_NAME "${qhull_OUTPUT_NAME}" )
+#endif()
+#
+#set_target_properties(${qhull_SHARED} PROPERTIES
+# SOVERSION ${qhull_SOVERSION}
+# VERSION ${qhull_VERSION})
+#
+#if(UNIX)
+# target_link_libraries(${qhull_SHARED} m)
+# if(APPLE)
+# set_target_properties(${qhull_SHARED} PROPERTIES
+# INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
+# else()
+# set_target_properties(${qhull_SHARED} PROPERTIES
+# INSTALL_RPATH "${LIB_INSTALL_DIR}"
+# INSTALL_RPATH_USE_LINK_PATH TRUE
+# BUILD_WITH_INSTALL_RPATH FALSE)
+# endif()
+#endif(UNIX)
+
+# ---------------------------------------
+# Define old shared library qhull with qh_QHpointer
+# ---------------------------------------
+
+#add_library(${qhull_SHAREDP} SHARED
+# ${libqhull_SOURCES}
+# src/libqhull/qhull_p-exports.def)
+#set_target_properties(${qhull_SHAREDP} PROPERTIES
+# COMPILE_DEFINITIONS "qh_QHpointer"
+# SOVERSION ${qhull_SOVERSION}
+# VERSION ${qhull_VERSION})
+#
+#if(UNIX)
+# target_link_libraries(${qhull_SHAREDP} m)
+# if(APPLE)
+# set_target_properties(${qhull_SHAREDP} PROPERTIES
+# INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
+# else()
+# set_target_properties(${qhull_SHAREDP} PROPERTIES
+# INSTALL_RPATH "${LIB_INSTALL_DIR}"
+# INSTALL_RPATH_USE_LINK_PATH TRUE
+# BUILD_WITH_INSTALL_RPATH FALSE)
+# endif()
+#endif(UNIX)
+
+# ---------------------------------------
+# Define static libraries qhullstatic (non-reentrant) and qhullstatic_r (reentrant)
+# ---------------------------------------
+
+#add_library(${qhull_STATIC} STATIC ${libqhull_SOURCES})
+#set_target_properties(${qhull_STATIC} PROPERTIES
+# VERSION ${qhull_VERSION})
+#
+#add_library(${qhull_STATICR} STATIC ${libqhullr_SOURCES})
+#set_target_properties(${qhull_STATICR} PROPERTIES
+# VERSION ${qhull_VERSION})
+
+#if(UNIX)
+# target_link_libraries(${qhull_STATIC} m)
+# target_link_libraries(${qhull_STATICR} m)
+#endif(UNIX)
+#
+## ---------------------------------------
+## Define C++ static library qhullcpp
+## Do not create libqhullcpp as a shared library. Qhull C++ classes may change layout and size.
+## ---------------------------------------
+#
+#add_library(${qhull_CPP} STATIC ${libqhullcpp_SOURCES})
+#set_target_properties(${qhull_CPP} PROPERTIES
+# VERSION ${qhull_VERSION})
+
+# ---------------------------------------
+# Define qhull executables linked to qhullstatic library
+# qhull is linked to reentrant qhull (more flexible)
+# the others are linked to non-reentrant qhull (somewhat faster)
+# ---------------------------------------
+
+set(qhull_SOURCES src/qhull/unix_r.c)
+set(rbox_SOURCES src/rbox/rbox.c)
+set(qconvex_SOURCES src/qconvex/qconvex.c)
+set(qdelaunay_SOURCES src/qdelaunay/qdelaun.c)
+set(qvoronoi_SOURCES src/qvoronoi/qvoronoi.c)
+set(qhalf_SOURCES src/qhalf/qhalf.c)
+
+#add_executable(qhull ${qhull_SOURCES})
+#target_link_libraries(qhull ${qhull_STATICR})
+#
+#add_executable(rbox ${rbox_SOURCES})
+#target_link_libraries(rbox ${qhull_STATIC})
+#
+#add_executable(qconvex ${qconvex_SOURCES})
+#target_link_libraries(qconvex ${qhull_STATIC})
+#
+#add_executable(qdelaunay ${qdelaunay_SOURCES})
+#target_link_libraries(qdelaunay ${qhull_STATIC})
+#
+#add_executable(qvoronoi ${qvoronoi_SOURCES})
+#target_link_libraries(qvoronoi ${qhull_STATIC})
+#
+#add_executable(qhalf ${qhalf_SOURCES})
+#target_link_libraries(qhalf ${qhull_STATIC})
+
+# ---------------------------------------
+# Define options for linking to qhull_SHAREDR or qhull_SHARED
+# ---------------------------------------
+#if(MSVC)
+# set(user_eg_DEFINES qh_dllimport)
+# set(user_eg2_DEFINES qh_dllimport)
+# set(user_eg3_DEFINES qh_dllimport)
+# set(user_egp_DEFINES qh_QHpointer_dllimport qh_QHpointer)
+# set(qhullp_DEFINES qh_QHpointer_dllimport qh_QHpointer)
+#else()
+# set(user_eg_DEFINES )
+# set(user_eg2_DEFINES )
+# set(user_eg3_DEFINES )
+# set(user_egp_DEFINES )
+# set(qhullp_DEFINES )
+#endif()
+
+# ---------------------------------------
+# Define testqset linked to qset.o and mem.o
+# Define testqset_r linked to qset_r.o and mem_r.o
+# ---------------------------------------
+
+#add_executable(testqset ${testqset_SOURCES})
+#add_executable(testqset_r ${testqsetr_SOURCES})
+
+# ---------------------------------------
+# Define user_eg linked to reentrant qhull shared library
+# ---------------------------------------
+#
+#set(user_eg_SOURCES src/user_eg/user_eg_r.c)
+#
+#add_executable(user_eg ${user_eg_SOURCES})
+## user_eg may be linked to qhull_STATICR if user_eg_DEFINES is removed
+#target_link_libraries(user_eg ${qhull_SHAREDR})
+#set_target_properties(user_eg PROPERTIES
+# COMPILE_DEFINITIONS "${user_eg_DEFINES}")
+
+# ---------------------------------------
+# Define user_eg2 linked to reentrant qhull static library
+# ---------------------------------------
+
+#set(user_eg2_SOURCES src/user_eg2/user_eg2_r.c)
+#
+#add_executable(user_eg2 ${user_eg2_SOURCES})
+## user_eg2 may be linked to qhull_SHAREDR if user_eg2_DEFINES is added
+#target_link_libraries(user_eg2 ${qhull_STATICR})
+
+# ---------------------------------------
+# Define user_eg3 linked to qhullstatic_r and qhullcpp static library
+#
+# user_eg3 and qhullcpp must be compiled with the same compiler for setjmp/longjmp
+## ---------------------------------------
+#
+#set(user_eg3_SOURCES src/user_eg3/user_eg3_r.cpp)
+#
+#add_executable(user_eg3 ${user_eg3_SOURCES})
+## qhull_STATICR must be last, otherwise qh_fprintf,etc. are not loaded from qhull_CPP
+## user_eg3 may be linked to qhull_SHAREDR if user_eg3_DEFINES is added
+#target_link_libraries(user_eg3 ${qhull_CPP} ${qhull_STATICR})
+#
+## ---------------------------------------
+## qhullp is qhull/unix.c linked to deprecated qh_QHpointer libqhull_p
+## Included for testing qh_QHpointer
+## ---------------------------------------
+#
+#set(qhullp_SOURCES src/qhull/unix.c)
+#
+#add_executable(qhullp EXCLUDE_FROM_ALL ${qhullp_SOURCES})
+#target_link_libraries(qhullp ${qhull_SHAREDP})
+#set_target_properties(qhullp PROPERTIES
+# COMPILE_DEFINITIONS "${qhullp_DEFINES}")
+#
+# ---------------------------------------
+# user_egp is user_eg/user_eg.c linked to deprecated qh_QHpointer libqhull_p
+# Included for compatibility with qhull-2012.1
+# ---------------------------------------
+
+#set(user_egp_SOURCES src/user_eg/user_eg.c)
+#
+#add_executable(user_egp EXCLUDE_FROM_ALL ${user_egp_SOURCES})
+#target_link_libraries(user_egp ${qhull_SHAREDP})
+#set_target_properties(user_egp PROPERTIES
+# COMPILE_DEFINITIONS "${user_egp_DEFINES}")
+#
+# ---------------------------------------
+# Define test
+# ---------------------------------------
+
+#enable_testing()
+#add_test(NAME testqset
+# COMMAND ./testqset 10000)
+#add_test(NAME testqset_r
+# COMMAND ./testqset_r 10000)
+#add_test(NAME smoketest
+# COMMAND sh -c "./rbox D4 | ./qhull Tv")
+#add_test(NAME rbox-10-qhull
+# COMMAND sh -c "./rbox 10 | ./qhull Tv")
+#add_test(NAME rbox-10-qconvex
+# COMMAND sh -c "./rbox 10 | ./qconvex Tv")
+#add_test(NAME rbox-10-qdelaunay
+# COMMAND sh -c "./rbox 10 | ./qdelaunay Tv")
+#add_test(NAME rbox-10-qhalf
+# COMMAND sh -c "./rbox 10 | ./qconvex FQ FV n Tv | ./qhalf Tv")
+#add_test(NAME rbox-10-qvoronoi
+# COMMAND sh -c "./rbox 10 | ./qvoronoi Tv")
+#add_test(NAME user_eg
+# COMMAND sh -c "./user_eg")
+#add_test(NAME user_eg2
+# COMMAND sh -c "./user_eg2")
+#add_test(NAME user_eg3
+# COMMAND sh -c "./user_eg3 rbox '10 D2' '2 D2' qhull 's p' facets")
+
+# ---------------------------------------
+# Define install
+# ---------------------------------------
+
+install(TARGETS ${qhull_TARGETS_INSTALL}
+ RUNTIME DESTINATION ${BIN_INSTALL_DIR}
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}
+ ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
+
+#install(FILES ${libqhull_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull)
+#install(FILES ${libqhull_DOC} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull)
+install(FILES ${libqhullr_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull_r)
+install(FILES ${libqhullr_DOC} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull_r)
+#install(FILES ${libqhullcpp_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhullcpp)
+#install(FILES html/qhull.man DESTINATION ${MAN_INSTALL_DIR} RENAME qhull.1)
+#install(FILES html/rbox.man DESTINATION ${MAN_INSTALL_DIR} RENAME rbox.1)
+#install(FILES ${doc_FILES} DESTINATION ${DOC_INSTALL_DIR})
+#install(DIRECTORY html/ DESTINATION ${DOC_INSTALL_DIR})
diff --git a/src/backend/APT/vtk.cpp b/src/backend/APT/vtk.cpp
new file mode 100644
index 0000000..3d15f0a
--- /dev/null
+++ b/src/backend/APT/vtk.cpp
@@ -0,0 +1,175 @@
+/*
+ * vtk.cpp - VTK file Import-export
+ * Copyright (C) 2016, D Haley
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "vtk.h"
+
+#include <fstream>
+
+using std::endl;
+using std::vector;
+using std::string;
+using std::cerr;
+
+
+//Adapted with permission (2016) from mVTK, by
+// guillaume flandin
+unsigned int vtk_write_legacy(const std::string &filename, unsigned int format,
+ const std::vector<IonHit> &ions)
+{
+
+ std::ofstream f;
+
+ if(format != VTK_ASCII)
+ {
+ cerr << "Binary mode is not implemented"
+ << endl;
+
+ return VTK_ERR_NOT_IMPLEMENTED;
+ }
+
+ f.open(filename.c_str());
+
+ if(!f)
+ return VTK_ERR_FILE_OPEN_FAIL;
+
+
+
+ f << "# vtk DataFile Version 2.0\n";
+ f << "Saved using AtomProbe Tools\n";
+ f << "ASCII\n\n";
+
+ f << "DATASET UNSTRUCTURED_GRID\n";
+ f << "POINTS " << ions.size() << " float\n";
+ //Write ion data which is the support points for later scalar data
+ for(unsigned int ui=0;ui<ions.size(); ui++)
+ {
+ f << ions[ui][0] << " " << ions[ui][1] << " "<<
+ ions[ui][2] << "\n";
+ }
+
+ f << "POINT_DATA " << ions.size() << endl;
+
+ f << "SCALARS masstocharge float\n";
+ f << "LOOKUP_TABLE default\n";
+
+ for(unsigned int ui=0;ui<ions.size(); ui++)
+ {
+ f << ions[ui].getMassToCharge() << "\n";
+ }
+
+
+ return 0;
+}
+
+//TODO: This is a template function, we will need to move it to the header
+template<class T>
+unsigned int vtk_write_legacy(const std::string &filename, unsigned int format,
+
+ const Voxels<T> &vox)
+{
+
+ std::ofstream f;
+
+ if(format != VTK_ASCII)
+ {
+ cerr << "Binary mode is not implemented"
+ << endl;
+
+ return VTK_ERR_NOT_IMPLEMENTED;
+ }
+
+ f.open(filename.c_str());
+
+ if(!f)
+ return VTK_ERR_FILE_OPEN_FAIL;
+
+
+
+ f << "# vtk DataFile Version 3.0\n";
+ f << "Saved using AtomProbe Tools\n";
+ f << "ASCII\n\n";
+
+ size_t nx,ny,nz;
+ vox.getSize(nx,ny,nz);
+ f << "DATASET RECTILINEAR_GRID\n";
+ f << "DIMENSIONS " << nx << " " << ny << " " << nz << endl;
+
+
+ f << "X_COORDINATES " << nx << " float" << endl;
+ for(unsigned int ui=0;ui<nx;ui++)
+ {
+ f << vox.getPoint((nx-1)-ui,0,0)[0] << " ";
+ }
+ f << endl;
+
+ f << "Y_COORDINATES " << ny << " float" << endl;
+ for(unsigned int ui=0;ui<ny;ui++)
+ {
+ f << vox.getPoint(0,ui,0)[1] << " ";
+ }
+ f << endl;
+
+ f << "Z_COORDINATES " << nz << " float" << endl;
+ for(unsigned int ui=0;ui<nz;ui++)
+ {
+ f << vox.getPoint(0,0,ui)[2] << " ";
+ }
+ f << endl;
+
+
+ f << "POINT_DATA " << vox.size() << endl;
+ f << "SCALARS masstocharge float\n";
+ f << "LOOKUP_TABLE default\n";
+
+ for(unsigned int ui=0;ui<vox.size(); ui++)
+ {
+ f << vox.getData(ui)<< "\n";
+ }
+ return 0;
+}
+
+
+#ifdef DEBUG
+
+bool testVTKExport()
+{
+ vector<IonHit> ions;
+
+ //make a cube of ions, each with a differing mass.
+ for(unsigned int ui=0;ui<8;ui++)
+ ions.push_back(IonHit(Point3D(ui &1, (ui & 2) >>1, (ui &4) >>2),ui));
+
+ //export it
+ TEST(vtk_write_legacy("debug.vtk",VTK_ASCII,ions) == 0,"VTK write");
+
+
+ Voxels<float> v;
+ v.resize(3,3,3);
+ v.setData(0,0,0,1);
+ v.setData(1,0,0,2);
+ v.setData(2,0,0,3);
+ v.setData(2,1,0,4);
+
+
+ vtk_write_legacy("debug-vox.vtk",VTK_ASCII,v);
+
+ return true;
+}
+
+#endif
diff --git a/src/backend/APT/vtk.h b/src/backend/APT/vtk.h
new file mode 100644
index 0000000..fcea225
--- /dev/null
+++ b/src/backend/APT/vtk.h
@@ -0,0 +1,54 @@
+/*
+ * vtk.h - VTK file Import-export
+ * Copyright (C) 2016, D Haley
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef VTK_H
+#define VTK_H
+
+#include <vector>
+#include <string>
+
+#include "ionhit.h"
+#include "common/voxels.h"
+
+enum
+{
+ VTK_ERR_FILE_OPEN_FAIL=1,
+ VTK_ERR_NOT_IMPLEMENTED,
+ VTK_ERR_ENUM_END
+};
+
+enum
+{
+ VTK_ASCII,
+ VTK_BINARY,
+ VTK_FORMAT_ENUM_END
+};
+
+//write ions to a VTK (paraview compatible) file.
+// FIXME : This currenly only supports ASCII mode.
+// Need binary mode because of the large files we have
+unsigned int vtk_write_legacy(const std::string &filename,
+ unsigned int format, const std::vector<IonHit> &ions);
+
+unsigned int vtk_write_legacy(const std::string &filename,
+ unsigned int format, const Voxels<class T> &vox);
+
+#ifdef DEBUG
+//unit testing
+bool testVTKExport();
+#endif
+#endif
diff --git a/src/backend/filters/profile.cpp b/src/backend/filters/profile.cpp
new file mode 100644
index 0000000..455dba1
--- /dev/null
+++ b/src/backend/filters/profile.cpp
@@ -0,0 +1,1993 @@
+/*
+ * profile.cpp - Compute composition or density profiles from valued point clouds
+ * Copyright (C) 2015, D Haley
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "profile.h"
+#include "../plot.h"
+
+#include "filterCommon.h"
+#include "geometryHelpers.h"
+
+using std::vector;
+using std::string;
+using std::pair;
+using std::make_pair;
+using std::map;
+
+
+//!Possible primitive types for composition profiles
+enum
+{
+ PRIMITIVE_CYLINDER_AXIAL,
+ PRIMITIVE_CYLINDER_RADIAL,
+ PRIMITIVE_SPHERE,
+ PRIMITIVE_END, //Not actually a primitive, just end of enum
+};
+
+
+//!Error codes
+enum
+{
+ ERR_NUMBINS=1,
+ ERR_MEMALLOC,
+ ERR_ABORT,
+ ERR_COMP_ENUM_END
+};
+
+const char *PRIMITIVE_NAME[]={
+ NTRANS("Cylinder (axial)"),
+ NTRANS("Cylinder (radial)"),
+ NTRANS("Sphere")
+};
+
+const float DEFAULT_RADIUS = 10.0f;
+
+const unsigned int MINEVENTS_DEFAULT =10;
+
+
+ProfileFilter::ProfileFilter() : primitiveType(PRIMITIVE_CYLINDER_AXIAL),
+ showPrimitive(true), lockAxisMag(false),normalise(true), fixedBins(0),
+ nBins(1000), binWidth(0.5f), minEvents(MINEVENTS_DEFAULT), rgba(0,0,1), plotStyle(0)
+{
+ COMPILE_ASSERT(THREEDEP_ARRAYSIZE(PRIMITIVE_NAME) == PRIMITIVE_END);
+
+ wantDensity=false;
+ 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;
+}
+
+//Puts an ion in its appropriate range position, given ionID mapping,
+//range data (if any), mass to charge and the output table
+void ProfileFilter::binIon(unsigned int targetBin, const RangeStreamData* rng,
+ const map<unsigned int,unsigned int> &ionIDMapping,
+ vector<vector<size_t> > &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())
+ {
+ vector<size_t>::iterator it;
+ it=frequencyTable[0].begin()+targetBin;
+ #pragma omp critical
+ (*it)++;
+ }
+ 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;
+ vector<size_t>::iterator it;
+ it=frequencyTable[pos].begin()+targetBin;
+ #pragma omp critical
+ (*it)++;
+ }
+}
+
+
+Filter *ProfileFilter::cloneUncached() const
+{
+ ProfileFilter *p = new ProfileFilter();
+
+ 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->wantDensity=wantDensity;
+ p->normalise=normalise;
+ p->fixedBins=fixedBins;
+ p->lockAxisMag=lockAxisMag;
+
+ p->rgba=rgba;
+ p->binWidth=binWidth;
+ p->nBins = nBins;
+ p->plotStyle=plotStyle;
+ p->errMode=errMode;
+ //We are copying whether to cache or not,
+ //not the cache itself
+ p->cache=cache;
+ p->cacheOK=false;
+ p->userString=userString;
+ return p;
+}
+
+void ProfileFilter::initFilter(const std::vector<const FilterStreamData *> &dataIn,
+ std::vector<const FilterStreamData *> &dataOut)
+{
+ //Check for range file parent
+ for(unsigned int ui=0;ui<dataIn.size();ui++)
+ {
+ if(dataIn[ui]->getStreamType() == STREAM_TYPE_RANGE)
+ {
+ haveRangeParent=true;
+ return;
+ }
+ }
+ haveRangeParent=false;
+}
+
+unsigned int ProfileFilter::refresh(const std::vector<const FilterStreamData *> &dataIn,
+ std::vector<const FilterStreamData *> &getOut, ProgressData &progress)
+{
+ //Clear selection devices
+ // FIXME: Leaking drawables.
+ 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_AXIAL:
+ case PRIMITIVE_CYLINDER_RADIAL:
+ {
+ //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(sqrtf(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<float>::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<float>::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);
+ }
+
+
+ //Propagate all the incoming data (excluding ions)
+ propagateStreams(dataIn,getOut,STREAM_TYPE_IONS,true);
+
+ //use the cached copy of the data if we have it.
+ if(cacheOK)
+ {
+ //propagate our cached plot data.
+ propagateCache(getOut);
+
+ ASSERT(filterOutputs.back()->getStreamType() == STREAM_TYPE_PLOT);
+
+ progress.filterProgress=100;
+ return 0;
+ }
+
+
+ //Ion Frequencies (composition specific if rangefile present)
+ vector<vector<size_t> > ionFrequencies;
+
+ RangeStreamData *rngData=0;
+ for(unsigned int ui=0;ui<dataIn.size() ;ui++)
+ {
+ if(dataIn[ui]->getStreamType() == STREAM_TYPE_RANGE)
+ {
+ rngData =((RangeStreamData *)dataIn[ui]);
+ break;
+ }
+ }
+
+ unsigned int numBins, errCode;
+ {
+ float length;
+ errCode=getBinData(numBins,length);
+
+ if(!numBins)
+ return 0;
+ }
+
+ if(errCode)
+ return errCode;
+
+ //Indirection vector to convert ionFrequencies position to ionID mapping.
+ //Should only be used in conjunction with rngData == true
+ std::map<unsigned int,unsigned int> ionIDMapping,inverseIDMapping;
+ //Allocate space for the frequency table
+ if(rngData)
+ {
+ ASSERT(rngData->rangeFile);
+ unsigned int enabledCount=0;
+ for(unsigned int ui=0;ui<rngData->rangeFile->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<ionFrequencies.size(); ui++)
+ ionFrequencies[ui].resize(numBins,0);
+ }
+ catch(std::bad_alloc)
+ {
+ return ERR_MEMALLOC;
+ }
+
+ }
+ else
+ {
+ try
+ {
+ ionFrequencies.resize(1);
+ ionFrequencies[0].resize(numBins,0);
+ }
+ catch(std::bad_alloc)
+ {
+ return ERR_MEMALLOC;
+ }
+ }
+
+
+ size_t n=0;
+ size_t totalSize=numElements(dataIn);
+
+ map<size_t,size_t> primitiveMap;
+ primitiveMap[PRIMITIVE_CYLINDER_AXIAL] = CROP_CYLINDER_INSIDE_AXIAL;
+ primitiveMap[PRIMITIVE_CYLINDER_RADIAL] = CROP_CYLINDER_INSIDE_RADIAL;
+ primitiveMap[PRIMITIVE_SPHERE] = CROP_SPHERE_INSIDE;
+
+ CropHelper dataMapping(totalSize,primitiveMap[primitiveType],
+ vectorParams,scalarParams );
+ dataMapping.setMapMaxima(numBins);
+
+ for(unsigned int ui=0;ui<dataIn.size() ;ui++)
+ {
+ //Loop through each element data set
+ switch(dataIn[ui]->getStreamType())
+ {
+ case STREAM_TYPE_IONS:
+ {
+ const IonStreamData *dIon = (const IonStreamData*)dataIn[ui];
+#ifdef _OPENMP
+ //OpenMP abort is not v. good, simply spin instead of working
+ bool spin=false;
+#endif
+ //Process ion streams
+
+ size_t nIons=dIon->data.size();
+ #pragma omp parallel for shared(n)
+ for(size_t uj=0;uj<nIons;uj++)
+ {
+#ifdef _OPENMP
+ //if parallelised, abort computaiton
+ if(spin) continue;
+#endif
+ unsigned int targetBin;
+ targetBin=dataMapping.mapIon1D(dIon->data[uj]);
+
+ //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,
+ dIon->data[uj].getMassToCharge());
+ }
+
+#ifdef _OPENMP
+ #pragma omp atomic
+ n++; //FIXME: Performance - we could use a separate non-sahred counter to reduce locking?
+
+ if(omp_get_thread_num() == 0)
+ {
+#endif
+ progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
+ if(*Filter::wantAbort)
+ {
+ #ifdef _OPENMP
+ spin=true;
+ #else
+ return ERR_ABORT;
+ #endif
+ }
+#ifdef _OPENMP
+ }
+#endif
+ }
+
+#ifdef _OPENMP
+ //Check to see if we aborted the Calculation
+ if(spin)
+ return ERR_ABORT;
+#endif
+
+ break;
+ }
+ default:
+ //Do not propagate other types.
+ break;
+ }
+
+ }
+
+#ifdef DEBUG
+ ASSERT(ionFrequencies.size());
+ //Ion frequencies must be of equal length
+ for(unsigned int ui=1;ui<ionFrequencies.size();ui++)
+ {
+ ASSERT(ionFrequencies[ui].size() == ionFrequencies[0].size());
+ }
+#endif
+
+
+ vector<float> normalisationFactor;
+ vector<unsigned int> normalisationCount;
+ normalisationFactor.resize(ionFrequencies[0].size());
+ normalisationCount.resize(ionFrequencies[0].size());
+ bool needNormalise=false;
+
+ //Perform the appropriate normalisation
+ if(!rngData && normalise)
+ {
+ // For density plots, normalise by
+ // the volume of the primitive's shell
+ switch(primitiveType)
+ {
+ case PRIMITIVE_CYLINDER_AXIAL:
+ case PRIMITIVE_CYLINDER_RADIAL:
+ {
+
+ float dx;
+ if(fixedBins)
+ dx=(sqrtf(vectorParams[1].sqrMag())/(float)numBins);
+
+ else
+ dx=binWidth;
+ needNormalise=true;
+ float nFact;
+ //Normalise by cylinder slice volume, pi*r^2*h.
+ // This is the same in both radial and axial mode as the radial slices are equi-volume,
+ // same as axial mode
+ nFact=1.0/(M_PI*scalarParams[0]*scalarParams[0]*dx);
+ for(unsigned int uj=0;uj<normalisationFactor.size(); uj++)
+ normalisationFactor[uj] = nFact;
+ break;
+ }
+ case PRIMITIVE_SPHERE:
+ {
+ float dx;
+ if(fixedBins)
+ dx=(scalarParams[0]/(float)numBins);
+
+ else
+ dx=binWidth;
+ for(unsigned int uj=0;uj<normalisationFactor.size(); uj++)
+ {
+ //Normalise by sphere shell volume,
+ // 4/3 *PI*dx^3*((n+1)^3-n^3)
+ // note -> (n+1)^3 -n^3 = (3*n^2) + (3*n) + 1
+ normalisationFactor[uj] = 1.0/(4.0/3.0*M_PI*
+ dx*(3.0*((float)uj*(float)uj + uj) + 1.0));
+ }
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+ }
+ else if(normalise && rngData) //compute normalisation values, if we are in composition mode
+ {
+ // the loops' nesting is reversed as we need to sum over distinct plots
+ //Density profiles (non-ranged plots) have a fixed normalisation factor
+ needNormalise=true;
+
+ for(unsigned int uj=0;uj<ionFrequencies[0].size(); uj++)
+ {
+ float sum;
+ sum=0;
+ //Loop across each bin type, summing result
+ for(unsigned int uk=0;uk<ionFrequencies.size();uk++)
+ sum +=(float)ionFrequencies[uk][uj];
+ normalisationCount[uj]=sum;
+
+
+ //Compute the normalisation factor
+ if(sum)
+ normalisationFactor[uj]=1.0/sum;
+ else
+ normalisationFactor[uj] = 0;
+ }
+
+ }
+
+
+ //Create the plots
+ PlotStreamData *plotData[ionFrequencies.size()];
+ for(unsigned int ui=0;ui<ionFrequencies.size();ui++)
+ {
+ plotData[ui] = new PlotStreamData;
+
+ plotData[ui]->index=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 (\\frac{\\#}{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 = rgba.r();
+ plotData[ui]->g = rgba.g();
+ plotData[ui]->b = rgba.b();
+ plotData[ui]->a = rgba.a();
+ }
+
+ plotData[ui]->xyData.reserve(ionFrequencies[ui].size());
+
+
+ //Go through each bin, then perform the appropriate normalisation
+ for(unsigned int uj=0;uj<ionFrequencies[ui].size(); uj++)
+ {
+ float xPos;
+ xPos = getBinPosition(uj);
+
+ if(ionFrequencies[ui][uj] < minEvents)
+ continue;
+
+ //Recompute normalisation value for this bin, if needed
+ if(needNormalise)
+ {
+ float normFactor=normalisationFactor[uj];
+
+ //keep the data if we are not using minimum threshold for normalisation, or we met the
+ // threhsold
+ plotData[ui]->xyData.push_back(
+ std::make_pair(xPos,
+ normFactor*(float)ionFrequencies[ui][uj]));
+ }
+ else
+ {
+ plotData[ui]->xyData.push_back(
+ std::make_pair(xPos,ionFrequencies[ui][uj]) );
+ }
+ }
+
+
+
+
+ plotData[ui]->plotStyle = plotStyle;
+ plotData[ui]->plotMode=PLOT_MODE_1D;
+
+ //If we ended up with any data, display it
+ // otherwise, trash the plot info
+ if(plotData[ui]->xyData.size())
+ {
+ cacheAsNeeded(plotData[ui]);
+ getOut.push_back(plotData[ui]);
+ }
+ else
+ {
+ consoleOutput.push_back(TRANS("No data remained in profile - cannot display result"));
+ delete plotData[ui];
+ }
+ }
+
+ progress.filterProgress=100;
+
+ return 0;
+}
+
+std::string ProfileFilter::getSpecificErrString(unsigned int code) const
+{
+ const char *errCodes[] = { "",
+ "Too many bins in comp. profile.",
+ "Not enough memory for comp. profile.",
+ "Aborted composition prof." };
+
+ COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errCodes) == ERR_COMP_ENUM_END);
+ ASSERT(code < ERR_COMP_ENUM_END);
+
+ return errCodes[code];
+}
+
+bool ProfileFilter::setProperty( unsigned int key,
+ const std::string &value, bool &needUpdate)
+{
+
+ switch(key)
+ {
+ case PROFILE_KEY_DENSITY_ONLY:
+ {
+ if(!applyPropertyNow(wantDensity,value,needUpdate))
+ return false;
+ break;
+ }
+ case PROFILE_KEY_BINWIDTH:
+ {
+ float newBinWidth;
+ if(stream_cast(newBinWidth,value))
+ return false;
+
+ if(newBinWidth < sqrtf(std::numeric_limits<float>::epsilon()))
+ return false;
+
+ binWidth=newBinWidth;
+ clearCache();
+ needUpdate=true;
+ break;
+ }
+ case PROFILE_KEY_FIXEDBINS:
+ {
+ if(!applyPropertyNow(fixedBins,value,needUpdate))
+ return false;
+ break;
+ }
+ case PROFILE_KEY_NORMAL:
+ {
+ Point3D newPt;
+ if(!newPt.parse(value))
+ return false;
+
+ if(primitiveType == PRIMITIVE_CYLINDER_AXIAL)
+ {
+ if(lockAxisMag &&
+ newPt.sqrMag() > sqrtf(std::numeric_limits<float>::epsilon()))
+ {
+ newPt.normalise();
+ newPt*=sqrtf(vectorParams[1].sqrMag());
+ }
+ }
+ if(newPt.sqrMag() < sqrtf(std::numeric_limits<float>::epsilon()))
+ return false;
+
+ if(!(vectorParams[1] == newPt ))
+ {
+ vectorParams[1] = newPt;
+ needUpdate=true;
+ clearCache();
+ }
+ return true;
+ }
+ case PROFILE_KEY_MINEVENTS:
+ {
+ if(!applyPropertyNow(minEvents,value,needUpdate))
+ return false;
+ break;
+ }
+ case PROFILE_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 PROFILE_KEY_ORIGIN:
+ {
+ if(!applyPropertyNow(vectorParams[0],value,needUpdate))
+ return false;
+ return true;
+ }
+ case PROFILE_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_AXIAL:
+ case PRIMITIVE_CYLINDER_RADIAL:
+ {
+ 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);
+ }
+
+ if(primitiveType == PRIMITIVE_CYLINDER_RADIAL)
+ fixedBins=true;
+
+ 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 PROFILE_KEY_RADIUS:
+ {
+ float newRad;
+ if(stream_cast(newRad,value))
+ return false;
+
+ if(newRad < sqrtf(std::numeric_limits<float>::epsilon()))
+ return false;
+
+ if(scalarParams[0] != newRad )
+ {
+ scalarParams[0] = newRad;
+ needUpdate=true;
+ clearCache();
+ }
+ return true;
+ }
+ case PROFILE_KEY_SHOWPRIMITIVE:
+ {
+ if(!applyPropertyNow(showPrimitive,value,needUpdate))
+ return false;
+ break;
+ }
+ case PROFILE_KEY_NORMALISE:
+ {
+ if(!applyPropertyNow(normalise,value,needUpdate))
+ return false;
+ break;
+ }
+ case PROFILE_KEY_LOCKAXISMAG:
+ {
+ if(!applyPropertyNow(lockAxisMag,value,needUpdate))
+ return false;
+ break;
+ }
+ case PROFILE_KEY_PLOTTYPE:
+ {
+ unsigned int tmpPlotType;
+
+ tmpPlotType=plotID(value);
+
+ if(tmpPlotType >= PLOT_LINE_NONE)
+ return false;
+
+ plotStyle = tmpPlotType;
+ needUpdate=true;
+ break;
+ }
+ case PROFILE_KEY_COLOUR:
+ {
+ ColourRGBA tmpRgba;
+ if(!tmpRgba.parse(value))
+ return false;
+
+ rgba=tmpRgba.toRGBAf();
+ needUpdate=true;
+ break;
+ }
+ case PROFILE_KEY_ERRMODE:
+ {
+ unsigned int tmpMode;
+ tmpMode=plotErrmodeID(value);
+
+ if(tmpMode >= PLOT_ERROR_ENDOFENUM)
+ return false;
+
+ errMode.mode= tmpMode;
+ needUpdate=true;
+
+ break;
+ }
+ case PROFILE_KEY_AVGWINSIZE:
+ {
+ unsigned int tmpNum;
+ if(stream_cast(tmpNum,value))
+ return false;
+
+ if(tmpNum<=1)
+ return false;
+
+ errMode.movingAverageNum=tmpNum;
+ needUpdate=true;
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+
+ if(needUpdate)
+ clearCache();
+
+ return true;
+}
+
+void ProfileFilter::getProperties(FilterPropGroup &propertyList) const
+{
+ bool doDensityPlot = (!haveRangeParent) || wantDensity;
+
+ string str,tmpStr;
+ FilterProperty p;
+ size_t curGroup=0;
+
+ if(haveRangeParent)
+ {
+ stream_cast(tmpStr,wantDensity);
+ p.name=TRANS("Total Density");
+ p.data=tmpStr;
+ p.key=PROFILE_KEY_DENSITY_ONLY;
+ p.type=PROPERTY_TYPE_BOOL;
+ p.helpText=TRANS("Do not do per-species analysis, perform density computation only");
+ propertyList.addProperty(p,curGroup);
+ }
+
+ //Allow primitive selection if we have more than one primitive
+ if(PRIMITIVE_END > 1)
+ {
+ //Choices for primitive type
+ vector<pair<unsigned int,string> > choices;
+ for(unsigned int ui=0;ui<PRIMITIVE_END;ui++)
+ {
+ str =TRANS(PRIMITIVE_NAME[ui]);
+ choices.push_back(make_pair(ui,str));
+ }
+ p.name=TRANS("Primitive type");
+ p.data=choiceString(choices,primitiveType);
+ p.key=PROFILE_KEY_PRIMITIVETYPE;
+ p.type=PROPERTY_TYPE_CHOICE;
+ p.helpText=TRANS("Basic shape to use for profile");
+ propertyList.addProperty(p,curGroup);
+ propertyList.setGroupTitle(curGroup,TRANS("Primitive"));
+ curGroup++;
+ }
+
+
+ stream_cast(tmpStr,showPrimitive);
+ p.name=TRANS("Show Primitive");
+ p.data=tmpStr;
+ p.key=PROFILE_KEY_SHOWPRIMITIVE;
+ p.type=PROPERTY_TYPE_BOOL;
+ p.helpText=TRANS("Display the 3D composition profile interaction object");
+ propertyList.addProperty(p,curGroup);
+
+ switch(primitiveType)
+ {
+ case PRIMITIVE_CYLINDER_AXIAL:
+ case PRIMITIVE_CYLINDER_RADIAL:
+ {
+ ASSERT(vectorParams.size() == 2);
+ ASSERT(scalarParams.size() == 1);
+ stream_cast(str,vectorParams[0]);
+ p.key=PROFILE_KEY_ORIGIN;
+ p.name=TRANS("Origin");
+ p.data=str;
+ p.type=PROPERTY_TYPE_POINT3D;
+ p.helpText=TRANS("Position for centre of cylinder");
+ propertyList.addProperty(p,curGroup);
+
+ stream_cast(str,vectorParams[1]);
+ p.key=PROFILE_KEY_NORMAL;
+ p.name=TRANS("Axis");
+ p.data=str;
+ p.type=PROPERTY_TYPE_POINT3D;
+ p.helpText=TRANS("Vector between ends of cylinder");
+ propertyList.addProperty(p,curGroup);
+
+ str=boolStrEnc(lockAxisMag);
+ p.key=PROFILE_KEY_LOCKAXISMAG;
+ p.name=TRANS("Lock Axis Mag.");
+ p.data= str;
+ p.type=PROPERTY_TYPE_BOOL;
+ p.helpText=TRANS("Prevent length of cylinder changing during interaction");
+ propertyList.addProperty(p,curGroup);
+
+ stream_cast(str,scalarParams[0]);
+ p.key=PROFILE_KEY_RADIUS;
+ p.name=TRANS("Radius");
+ p.data= str;
+ p.type=PROPERTY_TYPE_POINT3D;
+ p.helpText=TRANS("Radius of cylinder");
+ propertyList.addProperty(p,curGroup);
+ break;
+ }
+ case PRIMITIVE_SPHERE:
+ {
+
+ ASSERT(vectorParams.size() == 1);
+ ASSERT(scalarParams.size() == 1);
+ stream_cast(str,vectorParams[0]);
+ p.key=PROFILE_KEY_ORIGIN;
+ p.name=TRANS("Origin");
+ p.data=str;
+ p.type=PROPERTY_TYPE_POINT3D;
+ p.helpText=TRANS("Position for centre of sphere");
+ propertyList.addProperty(p,curGroup);
+
+ stream_cast(str,scalarParams[0]);
+ p.key=PROFILE_KEY_RADIUS;
+ p.name=TRANS("Radius");
+ p.data= str;
+ p.type=PROPERTY_TYPE_POINT3D;
+ p.helpText=TRANS("Radius of sphere");
+ propertyList.addProperty(p,curGroup);
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+
+ //Must be fixed bin num in radial mode. Disallow turning this off
+ if(primitiveType!= PRIMITIVE_CYLINDER_RADIAL)
+ {
+ p.key=PROFILE_KEY_FIXEDBINS;
+ stream_cast(str,fixedBins);
+ p.name=TRANS("Fixed Bin Num");
+ p.data=str;
+ p.type=PROPERTY_TYPE_BOOL;
+ p.helpText=TRANS("If true, use a fixed number of bins for profile, otherwise use fixed step size");
+ propertyList.addProperty(p,curGroup);
+ }
+
+ if(fixedBins)
+ {
+ stream_cast(tmpStr,nBins);
+ str = TRANS("Num Bins");
+ p.name=str;
+ p.data=tmpStr;
+ p.key=PROFILE_KEY_NUMBINS;
+ p.type=PROPERTY_TYPE_INTEGER;
+ p.helpText=TRANS("Number of bins to use for profile");
+ propertyList.addProperty(p,curGroup);
+ }
+ else
+ {
+ ASSERT(primitiveType!=PRIMITIVE_CYLINDER_RADIAL);
+ str = TRANS("Bin width");
+ stream_cast(tmpStr,binWidth);
+ p.name=str;
+ p.data=tmpStr;
+ p.key=PROFILE_KEY_BINWIDTH;
+ p.type=PROPERTY_TYPE_REAL;
+ p.helpText=TRANS("Size of each bin in profile");
+ propertyList.addProperty(p,curGroup);
+ }
+
+ stream_cast(tmpStr,normalise);
+ p.name= TRANS("Normalise");
+ p.data=tmpStr;
+ p.key=PROFILE_KEY_NORMALISE;
+ p.type=PROPERTY_TYPE_BOOL;
+ p.helpText=TRANS("Convert bin counts into relative frequencies in each bin");
+ propertyList.addProperty(p,curGroup);
+
+ stream_cast(tmpStr,minEvents);
+ p.name= TRANS("Min. events");
+ p.data=tmpStr;
+ p.key=PROFILE_KEY_MINEVENTS;
+ p.type=PROPERTY_TYPE_INTEGER;
+ p.helpText=TRANS("Drop data that does not have this many events");
+ propertyList.addProperty(p,curGroup);
+
+ propertyList.setGroupTitle(curGroup,TRANS("Settings"));
+
+
+
+ curGroup++;
+
+ //use set 2 to store the plot properties
+ stream_cast(str,plotStyle);
+ //Let the user know what the valid values for plot type are
+ vector<pair<unsigned int,string> > choices;
+
+
+ tmpStr=plotString(PLOT_LINE_LINES);
+ choices.push_back(make_pair((unsigned int) PLOT_LINE_LINES,tmpStr));
+ tmpStr=plotString(PLOT_LINE_BARS);
+ choices.push_back(make_pair((unsigned int)PLOT_LINE_BARS,tmpStr));
+ tmpStr=plotString(PLOT_LINE_STEPS);
+ choices.push_back(make_pair((unsigned int)PLOT_LINE_STEPS,tmpStr));
+ tmpStr=plotString(PLOT_LINE_STEM);
+ choices.push_back(make_pair((unsigned int)PLOT_LINE_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=PROFILE_KEY_PLOTTYPE;
+ propertyList.addProperty(p,curGroup);
+
+ //If we are not doing per-species, then we need colour
+ if(doDensityPlot)
+ {
+ //Convert the colour to a hex string
+ p.name=TRANS("Colour");
+ p.data=rgba.toColourRGBA().rgbString();
+ p.type=PROPERTY_TYPE_COLOUR;
+ p.helpText=TRANS("Colour of plot");
+ p.key=PROFILE_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=PROFILE_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=PROFILE_KEY_AVGWINSIZE;
+ propertyList.addProperty(p,curGroup);
+ }
+ propertyList.setGroupTitle(curGroup,TRANS("Error analysis"));
+}
+
+unsigned int ProfileFilter::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_AXIAL:
+ //length of cylinder, full axis length
+ length=sqrtf(vectorParams[1].sqrMag());
+ break;
+ case PRIMITIVE_CYLINDER_RADIAL:
+ //radius of cylinder
+ length =scalarParams[0];
+ break;
+ default:
+ ASSERT(false);
+ }
+
+ if(fixedBins)
+ numBins=nBins;
+ else
+ {
+ switch(primitiveType)
+ {
+ case PRIMITIVE_CYLINDER_AXIAL:
+ case PRIMITIVE_CYLINDER_RADIAL:
+ case PRIMITIVE_SPHERE:
+ {
+
+ ASSERT(binWidth > std::numeric_limits<float>::epsilon());
+
+ //Check for possible overflow
+ if(length/binWidth > (float)std::numeric_limits<unsigned int>::max())
+ return ERR_NUMBINS;
+
+ numBins=(unsigned int)(length/binWidth);
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+
+ }
+
+ return 0;
+}
+
+float ProfileFilter::getBinPosition(unsigned int nBin) const
+{
+ unsigned int nBinsMax; float fullLen, xPos;
+ getBinData(nBinsMax,fullLen);
+ ASSERT(nBin < nBinsMax)
+ xPos = ((float) nBin + 0.5)/(float)nBinsMax;
+ if( primitiveType == PRIMITIVE_CYLINDER_RADIAL)
+ {
+ float maxPosSqr = fullLen*fullLen;
+ //compute fraction
+ xPos = sqrt ( xPos*maxPosSqr);
+ }
+ else
+ {
+ xPos = xPos*fullLen;
+ }
+
+ return xPos;
+}
+
+//!Get approx number of bytes for caching output
+size_t ProfileFilter::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 ProfileFilter::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) << "<userstring value=\""<< escapeXML(userString) << "\"/>" << endl;
+
+ f << tabs(depth+1) << "<primitivetype value=\"" << primitiveType<< "\"/>" << endl;
+ f << tabs(depth+1) << "<showprimitive value=\"" << showPrimitive << "\"/>" << endl;
+ f << tabs(depth+1) << "<lockaxismag value=\"" << lockAxisMag<< "\"/>" << endl;
+ f << tabs(depth+1) << "<vectorparams>" << endl;
+ for(unsigned int ui=0; ui<vectorParams.size(); ui++)
+ {
+ f << tabs(depth+2) << "<point3d x=\"" << vectorParams[ui][0] <<
+ "\" y=\"" << vectorParams[ui][1] << "\" z=\"" << vectorParams[ui][2] << "\"/>" << endl;
+ }
+ f << tabs(depth+1) << "</vectorparams>" << endl;
+
+ f << tabs(depth+1) << "<scalarparams>" << endl;
+ for(unsigned int ui=0; ui<scalarParams.size(); ui++)
+ f << tabs(depth+2) << "<scalar value=\"" << scalarParams[0] << "\"/>" << endl;
+
+ f << tabs(depth+1) << "</scalarparams>" << endl;
+ f << tabs(depth+1) << "<normalise value=\"" << normalise << "\" minevents=\"" << minEvents << "\" />" << endl;
+ f << tabs(depth+1) << "<fixedbins value=\"" << (int)fixedBins << "\"/>" << endl;
+ f << tabs(depth+1) << "<nbins value=\"" << nBins << "\"/>" << endl;
+ f << tabs(depth+1) << "<binwidth value=\"" << binWidth << "\"/>" << endl;
+ f << tabs(depth+1) << "<colour r=\"" << rgba.r() << "\" g=\"" << rgba.g() << "\" b=\"" << rgba.b()
+ << "\" a=\"" << rgba.a() << "\"/>" <<endl;
+
+ f << tabs(depth+1) << "<plottype value=\"" << plotStyle << "\"/>" << endl;
+ f << tabs(depth) << "</" << trueName() << ">" << endl;
+ break;
+ }
+ default:
+ ASSERT(false);
+ return false;
+ }
+
+ return true;
+}
+
+
+void ProfileFilter::setUserString(const std::string &str)
+{
+ if(userString != str)
+ {
+ userString=str;
+ clearCache();
+ }
+}
+
+bool ProfileFilter::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;
+
+ //FIXME: DEPRECATE 3Depict versions <=0.0.17 had only two primitives,
+ // cylinder and sphere.
+/* if(versionCheckGreater(Filter::stateWriterVersion,("0.0.17")))
+ {
+ //remap the primitive type as needed
+ if(primitiveType == PRIMITIVE_CYLINDER_RADIAL)
+ primitiveType=PRIMITIVE_SPHERE;
+
+ }
+*/
+ 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(!boolStrDec(tmpStr,showPrimitive))
+ 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(!boolStrDec(tmpStr,lockAxisMag))
+ return false;
+
+ xmlFree(xmlString);
+ //====
+
+ //Retrieve 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;
+ //Retrieve 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_AXIAL:
+ case PRIMITIVE_CYLINDER_RADIAL:
+ 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(!boolStrDec(tmpStr,normalise))
+ 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(!boolStrDec(tmpStr,fixedBins))
+ return false;
+
+
+ xmlFree(xmlString);
+ //====
+
+ //Retrieve num bins
+ //====
+ if(XMLHelpFwdToElem(nodePtr,"nbins"))
+ return false;
+
+
+ if(XMLHelpGetProp(nBins,nodePtr,"value"))
+ return false;
+
+
+ if(XMLHelpGetProp(minEvents,nodePtr,"minevents"))
+ {
+ //FIXME: Deprecate me.
+ minEvents=MINEVENTS_DEFAULT;
+ }
+ //====
+
+ //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,rgba))
+ 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_LINE_NONE)
+ return false;
+ xmlFree(xmlString);
+ //====
+
+ return true;
+}
+
+unsigned int ProfileFilter::getRefreshBlockMask() const
+{
+ //Absolutely anything can go through this filter.
+ return 0;
+}
+
+unsigned int ProfileFilter::getRefreshEmitMask() const
+{
+ if(showPrimitive)
+ return STREAM_TYPE_PLOT | STREAM_TYPE_DRAW;
+ else
+ return STREAM_TYPE_PLOT;
+}
+
+unsigned int ProfileFilter::getRefreshUseMask() const
+{
+ return STREAM_TYPE_IONS | STREAM_TYPE_RANGE;
+}
+
+void ProfileFilter::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:
+ {
+ Point3D pOld=vectorParams[1];
+ b.getValue(vectorParams[1]);
+ //Test getting the bin data.
+ // if something is wrong, abort
+ float length;
+ unsigned int numBins;
+ unsigned int errCode= getBinData(numBins,length);
+ if(errCode || !numBins)
+ {
+ vectorParams[1]=pOld;
+ return;
+ }
+
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+
+ clearCache();
+}
+
+unsigned int ProfileFilter::getPrimitiveId(const std::string &primitiveName)
+{
+ for(size_t ui=0;ui<PRIMITIVE_END; ui++)
+ {
+ if( TRANS(PRIMITIVE_NAME[ui]) == primitiveName)
+ return ui;
+ }
+
+ ASSERT(false);
+}
+
+#ifdef DEBUG
+
+bool testDensityCylinder();
+bool testCompositionCylinder();
+void synthComposition(const vector<pair<float,float> > &compositionData,
+ vector<IonHit> &h);
+IonStreamData *synthLinearProfile(const Point3D &start, const Point3D &end,
+ float radialSpread,unsigned int numPts);
+
+bool ProfileFilter::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<std::pair<float,float> > 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
+ ProfileFilter *f = new ProfileFilter;
+
+ //Build some points to pass to the filter
+ vector<const FilterStreamData*> streamIn,streamOut;
+
+ bool needUp; std::string s;
+ stream_cast(s,Point3D((startPt+endPt)*0.5f));
+ TEST(f->setProperty(PROFILE_KEY_ORIGIN,s,needUp),"set origin");
+ TEST(f->setProperty(PROFILE_KEY_MINEVENTS,"0",needUp),"set origin");
+
+ stream_cast(s,Point3D((endPt-startPt)*0.5f));
+ TEST(f->setProperty(PROFILE_KEY_NORMAL,s,needUp),"set direction");
+ TEST(f->setProperty(PROFILE_KEY_SHOWPRIMITIVE,"1",needUp),"Set cylinder visibility");
+ TEST(f->setProperty(PROFILE_KEY_NORMALISE,"1",needUp),"Disable normalisation");
+ TEST(f->setProperty(PROFILE_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),"Refresh error code");
+
+ //2* plot, 1*rng, 1*draw
+ TEST(streamOut.size() == 4, "output stream count");
+
+ delete d;
+
+ std::map<unsigned int, unsigned int> countMap;
+ countMap[STREAM_TYPE_PLOT] = 0;
+ countMap[STREAM_TYPE_DRAW] = 0;
+ countMap[STREAM_TYPE_RANGE] = 0;
+
+ for(unsigned int ui=0;ui<streamOut.size();ui++)
+ {
+ ASSERT(countMap.find(streamOut[ui]->getStreamType()) != countMap.end());
+ countMap[streamOut[ui]->getStreamType()]++;
+ }
+
+ TEST(countMap[STREAM_TYPE_PLOT] == 2,"Plot count");
+ TEST(countMap[STREAM_TYPE_DRAW] == 1,"Draw count");
+ TEST(countMap[STREAM_TYPE_RANGE] == 1,"Range count");
+
+ const PlotStreamData* plotData=0;
+ for(unsigned int ui=0;ui<streamOut.size();ui++)
+ {
+ if(streamOut[ui]->getStreamType() == STREAM_TYPE_PLOT)
+ {
+ plotData = (const PlotStreamData *)streamOut[ui];
+ break;
+ }
+ }
+ TEST(plotData,"Should have plot data");
+ TEST(plotData->xyData.size(),"Plot data size");
+
+ for(size_t ui=0;ui<plotData->xyData.size(); ui++)
+ {
+ TEST(plotData->xyData[ui].second <= 1.0f &&
+ plotData->xyData[ui].second >=0.0f,"normalised data range test");
+ }
+
+ delete rngStream->rangeFile;
+ for(unsigned int ui=0;ui<streamOut.size();ui++)
+ delete streamOut[ui];
+
+
+ delete f;
+
+ 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<std::pair<float,float> > vecCompositions;
+ vecCompositions.push_back(make_pair(2.0f,0.5f));
+ vecCompositions.push_back(make_pair(3.0f,0.5f));
+ synthComposition(vecCompositions,d->data);
+ }
+
+ ProfileFilter *f = new ProfileFilter;
+ f->setCaching(false);
+
+ //Build some points to pass to the filter
+ vector<const FilterStreamData*> streamIn,streamOut;
+ streamIn.push_back(d);
+
+ bool needUp; std::string s;
+ stream_cast(s,Point3D((startPt+endPt)*0.5f));
+ TEST(f->setProperty(PROFILE_KEY_ORIGIN,s,needUp),"set origin");
+
+ stream_cast(s,Point3D((endPt-startPt)));
+ TEST(f->setProperty(PROFILE_KEY_NORMAL,s,needUp),"set direction");
+
+ TEST(f->setProperty(PROFILE_KEY_SHOWPRIMITIVE,"1",needUp),"Set cylinder visibility");
+
+ TEST(f->setProperty(PROFILE_KEY_NORMALISE,"0",needUp),"Disable normalisation");
+ TEST(f->setProperty(PROFILE_KEY_RADIUS,"5",needUp),"Set radius");
+
+ ProgressData p;
+ TEST(!f->refresh(streamIn,streamOut,p),"Refresh error code");
+ delete f;
+ delete d;
+
+
+ TEST(streamOut.size() == 2, "output stream count");
+
+ std::map<unsigned int, unsigned int> countMap;
+ countMap[STREAM_TYPE_PLOT] = 0;
+ countMap[STREAM_TYPE_DRAW] = 0;
+
+ for(unsigned int ui=0;ui<streamOut.size();ui++)
+ {
+ ASSERT(countMap.find(streamOut[ui]->getStreamType()) != 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;ui<streamOut.size();ui++)
+ {
+ if(streamOut[ui]->getStreamType() == STREAM_TYPE_PLOT)
+ {
+ plotData = (const PlotStreamData *)streamOut[ui];
+ break;
+ }
+ }
+
+ float sum=0;
+ for(size_t ui=0;ui<plotData->xyData.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<streamOut.size();ui++)
+ delete streamOut[ui];
+
+ return true;
+}
+
+
+//first value in pair is target mass, second value is target composition
+void synthComposition(const vector<std::pair<float,float> > &compositionData,
+ vector<IonHit> &h)
+{
+ float fractionSum=0;
+ for(size_t ui=0;ui<compositionData.size(); ui++)
+ fractionSum+=compositionData[ui].second;
+
+ //build the spacings between 0 and 1, so we can
+ //randomly select ions by uniform deviates
+ vector<std::pair<float,float> > ionCuts;
+ ionCuts.resize(compositionData.size());
+ //ionCuts.resize[compositionData.size()];
+ float runningSum=0;
+ for(size_t ui=0;ui<ionCuts.size(); ui++)
+ {
+ runningSum+=compositionData[ui].second;
+ ionCuts[ui]=make_pair(compositionData[ui].first,
+ runningSum/fractionSum);
+ }
+
+ RandNumGen rngHere;
+ rngHere.initTimer();
+ for(size_t ui=0;ui<h.size();ui++)
+ {
+
+ float newMass;
+ bool haveSetMass;
+
+ //keep generating random selections until we hit something.
+ // This is to prevent any fp fallthrough
+ do
+ {
+ float uniformDeviate;
+ uniformDeviate=rngHere.genUniformDev();
+
+ haveSetMass=false;
+ //This is not efficient -- data is sorted,
+ //so binary search would work, but whatever.
+ for(size_t uj=0;uj<ionCuts.size();uj++)
+ {
+ if(uniformDeviate >=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<float>::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<numPts;ui++)
+ {
+ //generate a random offset vector
+ //that is normal to the axis of the simulation
+ Point3D randomVector;
+ do
+ {
+ randomVector=Point3D(rngAxial.genUniformDev(),
+ rngAxial.genUniformDev(),
+ rngAxial.genUniformDev());
+ }while(randomVector.sqrMag() < std::numeric_limits<float>::epsilon() &&
+ randomVector.angle(delta) < std::numeric_limits<float>::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 --git a/src/backend/filters/profile.h b/src/backend/filters/profile.h
new file mode 100644
index 0000000..5c28135
--- /dev/null
+++ b/src/backend/filters/profile.h
@@ -0,0 +1,159 @@
+/*
+ * profile.h - Composition/density profiles of 3D point clouds
+ * Copyright (C) 2015, D Haley
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef COMPPROFILE_H
+#define COMPPROFILE_H
+#include "../filter.h"
+#include "../../common/translation.h"
+
+#include <map>
+
+enum
+{
+ PROFILE_KEY_BINWIDTH=1,
+ PROFILE_KEY_FIXEDBINS,
+ PROFILE_KEY_DENSITY_ONLY,
+ PROFILE_KEY_NORMAL,
+ PROFILE_KEY_MINEVENTS,
+ PROFILE_KEY_NUMBINS,
+ PROFILE_KEY_ORIGIN,
+ PROFILE_KEY_PLOTTYPE,
+ PROFILE_KEY_PRIMITIVETYPE,
+ PROFILE_KEY_RADIUS,
+ PROFILE_KEY_SHOWPRIMITIVE,
+ PROFILE_KEY_NORMALISE,
+ PROFILE_KEY_COLOUR,
+ PROFILE_KEY_ERRMODE,
+ PROFILE_KEY_AVGWINSIZE,
+ PROFILE_KEY_LOCKAXISMAG
+};
+//!Filter that does composition or density profiles for various primitives
+class ProfileFilter : 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
+ std::vector<Point3D> vectorParams;
+ //!Scalar parameters for different primitives
+ std::vector<float> scalarParams;
+
+ //! Does the user explicitly want a density plot?
+ bool wantDensity;
+ //!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;
+
+ //!Number of events required for an entry to be logged in a normalised
+ // histogram
+ unsigned int minEvents;
+
+ //Plotting stuff
+ //--
+ //colour of plot
+ ColourRGBAf rgba;
+ //Mode for plotting (eg lines, steps)
+ 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<unsigned int,unsigned int> &ionIDMapping,
+ std::vector<std::vector<size_t> > &frequencyTable, float massToCharge);
+
+ static unsigned int getPrimitiveId(const std::string &s);;
+
+ //obtain the size of each bin, and number of bins required for profile
+ unsigned int getBinData(unsigned int &numBins, float &binLength) const;
+
+ //Obtain the X coordinate of a given bin's centre, given the bin value
+ float getBinPosition(unsigned int nBin) const;
+
+ public:
+ ProfileFilter();
+ //!Duplicate filter contents, excluding cache.
+ Filter *cloneUncached() const;
+ //!Returns FILTER_TYPE_PROFILE
+ unsigned int getType() const { return FILTER_TYPE_PROFILE;};
+
+ //!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<const FilterStreamData *> &dataIn,
+ std::vector<const FilterStreamData *> &dataOut);
+ //!update filter
+ unsigned int refresh(const std::vector<const FilterStreamData *> &dataIn,
+ std::vector<const FilterStreamData *> &getOut,
+ ProgressData &progress);
+
+ 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 getSpecificErrString(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
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/3depict.git
More information about the debian-science-commits
mailing list