[3depict] 02/07: * Update to upstream effd078610a7
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 b88bbc247b2d5b59585559c78dd58d8824ed62d7
Author: D Haley <mycae at gmx.com>
Date: Thu Aug 4 00:18:23 2016 +0200
* Update to upstream effd078610a7
---
.../patches/diff-upstream-0.0.18_to_212d6e1e6b14 | 1490 --------------------
debian/patches/diff_0.0.19_to_effd078610a7 | 1235 ++++++++++++++++
debian/patches/lowercase-textdomain.patch | 10 +-
debian/patches/series | 2 +-
4 files changed, 1241 insertions(+), 1496 deletions(-)
diff --git a/debian/patches/diff-upstream-0.0.18_to_212d6e1e6b14 b/debian/patches/diff-upstream-0.0.18_to_212d6e1e6b14
deleted file mode 100644
index 3053a6f..0000000
--- a/debian/patches/diff-upstream-0.0.18_to_212d6e1e6b14
+++ /dev/null
@@ -1,1490 +0,0 @@
-diff -ruh ./src/3Depict.cpp ./3Depict.cpp
---- ./src/3Depict.cpp 2016-02-08 02:38:00.000000000 +0100
-+++ ./src/3Depict.cpp 2016-02-08 02:41:11.805762472 +0100
-@@ -21,6 +21,9 @@
- #include <wx/cmdline.h>
- #include <wx/filename.h>
- #include <wx/stdpaths.h>
-+#ifndef DEBUG
-+#include <wx/log.h>
-+#endif
-
- #ifdef __APPLE__
- #include "CoreFoundation/CoreFoundation.h"
-@@ -39,11 +42,12 @@
-
- class threeDepictApp: public wxApp {
- private:
--#ifndef DEBUG
-- //instance of this class suppresses internal wx error dialogs.
-- // these are a nuisance in release code, as recovered errors often annoy the user
-- wxLogNull nullifyLogs;
--#endif
-+
-+
-+ void redirectWxLogging();
-+
-+ std::ofstream debugLogStream;
-+
-
- MainWindowFrame* MainFrame ;
- wxArrayString commandLineFiles;
-@@ -101,11 +105,29 @@
- {
- MainFrame=0;usrLocale=0;
- dontLoad=false;
--#ifndef DEBUG
-+
- //Wx 2.9 and up now has assertions auto-enabled.
- //Disable for release builds
-+#ifndef DEBUG
- wxSetAssertHandler(NULL);
- #endif
-+ redirectWxLogging();
-+}
-+
-+void threeDepictApp::redirectWxLogging()
-+{
-+ //Disable user visible logging on the main thread, this can throw up "error dialogs"
-+ // to the user that seem to be false positives, such as "Error: Sucess" type messages
-+ // ihstead try first to log to file. If that fails, just disable it
-+ wxStandardPaths &paths = wxStandardPaths::Get();
-+ wxString filePath = paths.GetDocumentsDir();
-+ filePath+=("/.")+string(PROGRAM_NAME) + string("log.txt");
-+ debugLogStream.open(filePath.c_str());
-+
-+ if(!debugLogStream)
-+ wxLog::EnableLogging(false);
-+ else
-+ wxLog::SetActiveTarget(new wxLogStream(&debugLogStream));
- }
-
- int threeDepictApp::OnExit()
-diff -ruh ./src/backend/APT/APTFileIO.cpp ./backend/APT/APTFileIO.cpp
---- ./src/backend/APT/APTFileIO.cpp 2016-02-08 01:39:07.246999770 +0100
-+++ ./src/backend/APT/APTFileIO.cpp 2016-02-08 02:41:11.833762535 +0100
-@@ -473,7 +473,7 @@
- //we define this as the split value being able to generate
- //1) Enough data to make interpretable columns
- //2) Enough columns that can be interpreted.
-- while(!CFile.eof() && curPos < maxPos)
-+ while(CFile.good() && !CFile.eof() && curPos < maxPos)
- {
- string s;
- curPos = CFile.tellg();
-@@ -505,7 +505,7 @@
- }
-
- //could not find any data.. only header.
-- if(CFile.eof() || curPos >=maxPos)
-+ if(!CFile.good() || CFile.eof() || curPos >=maxPos)
- return TEXT_ERR_ONLY_HEADER;
-
-
-@@ -526,7 +526,7 @@
- newLinePositions.push_back(curPos);
- bool seenNumeric=false;
- buffer = new char[BUFFER_SIZE];
-- while(!CFile.eof() && curPos < maxPos)
-+ while(CFile.good() && !CFile.eof() && curPos < maxPos)
- {
- size_t bytesToRead;
-
-diff -ruh ./src/backend/APT/APTRanges.cpp ./backend/APT/APTRanges.cpp
---- ./src/backend/APT/APTRanges.cpp 2016-02-08 01:39:07.246999770 +0100
-+++ ./src/backend/APT/APTRanges.cpp 2016-02-08 02:41:11.637762095 +0100
-@@ -1135,10 +1135,8 @@
-
- //Now, spin forwards until we either hit EOF or our double-dash marker
-
-- while(!f.eof())
-+ while(!getline(f,tmpStr))
- {
-- getline(f,tmpStr);
--
- if(tmpStr.size() > 2 &&
- tmpStr[0] == '-' && tmpStr[1] == '-')
- {
-@@ -1149,7 +1147,7 @@
- }
- }
-
-- if(f.eof())
-+ if(!f.good())
- {
- //we did not see a double-dash, must be a vanilla ORNL file
- typeStatus[RANGE_FORMAT_DBL_ORNL]=STATUS_IS_NOT;
-@@ -1505,6 +1503,7 @@
- bool beyondRanges=false;
- bool haveNumRanges=false;
- bool haveNameBlock=false;
-+ bool haveSeenRevHeader=false;
- vector<string> strVec;
-
- //Read file until we get beyond the range length
-@@ -1527,6 +1526,13 @@
- if(!s.size())
- continue;
-
-+ //If we have
-+ if(!haveSeenRevHeader && (s== "Rev_2.0"))
-+ {
-+ haveSeenRevHeader=true;
-+ continue;
-+ }
-+
- //Try different delimiters to split string
- splitStrsRef(s.c_str(),"\t ",strVec);
-
-diff -ruh ./src/backend/filters/algorithms/mass.cpp ./backend/filters/algorithms/mass.cpp
---- ./src/backend/filters/algorithms/mass.cpp 2016-02-08 01:39:07.250999771 +0100
-+++ ./src/backend/filters/algorithms/mass.cpp 2016-02-08 02:41:11.645762113 +0100
-@@ -87,19 +87,18 @@
- const unsigned int MIN_REQUIRED_AVG_COUNTS=10;
- const unsigned int MIN_REQUIRED_BINS=10;
-
-- //CHECKME : The number of bins is the same in TOF as well as in
-- // m/c space.
-- size_t nBins = (backParams.massEnd - backParams.massStart) / backParams.binWidth;
-- float filterStep = (sqrt(backParams.massEnd) - sqrt(backParams.massStart) )/ nBins;
-+ size_t nBinsTof = (sqrt(backParams.massEnd) - sqrt(backParams.massStart)) / backParams.binWidth;
-+ float filterStep = (sqrt(backParams.massEnd) - sqrt(backParams.massStart) )/ nBinsTof;
-
- //we cannot perform a test with fewer than this number of bins
-- if ( nBins < MIN_REQUIRED_BINS)
-+ if ( nBinsTof < MIN_REQUIRED_BINS)
- return BACKGROUND_PARAMS::FIT_FAIL_MIN_REQ_BINS;
-
-- float averageCounts = sqrtFiltMass.size()/ (float)nBins;
-+ float averageCounts = sqrtFiltMass.size()/ (float)nBinsTof;
- if( averageCounts < MIN_REQUIRED_AVG_COUNTS)
- return BACKGROUND_PARAMS::FIT_FAIL_AVG_COUNTS;
-
-+ //Check that the TOF-space histogram is gaussian
- vector<float> histogram;
- makeHistogram(sqrtFiltMass,sqrt(backParams.massStart),
- sqrt(backParams.massEnd), filterStep,histogram);
-@@ -120,14 +119,34 @@
- if(andersonStat > STATISTIC_THRESHOLD || undefCount == histogram.size())
- return BACKGROUND_PARAMS::FIT_FAIL_DATA_NON_GAUSSIAN;
-
-- //Intensity PER AMU
-- //backgroundIntensity= meanVal/filterStep;
- //Intensity PER BIN in TOF space
- backParams.intensity= meanVal;
-
- return 0;
- }
-
-+
-+//Start and end mass, and step size (to get bin count).
-+// tofBackIntensity is the intensity level per unit time in the background, as obtained by doFitBackground
-+// the histogram is
-+void createMassBackground(float massStart, float massEnd, unsigned int nBinsMass,
-+ float tofBackIntensity, vector<float> &histogram)
-+{
-+ const float MC_BIN_STEP = (massEnd-massStart)/nBinsMass;
-+
-+ //compute fitted value analytically
-+ histogram.resize(nBinsMass);
-+ for(size_t ui=0;ui<histogram.size();ui++)
-+ {
-+ float mcX;
-+ mcX=(float)ui*MC_BIN_STEP+ massStart;
-+ if ( mcX <=0)
-+ histogram[ui]=0;
-+ else
-+ histogram[ui]= tofBackIntensity/(2.0*sqrt(mcX))*MC_BIN_STEP;
-+ }
-+}
-+
- #ifdef DEBUG
- #include "common/mathfuncs.h"
-
-@@ -163,7 +182,7 @@
- return true;
- }
-
--bool testBackgroundFit()
-+bool testBackgroundFitMaths()
- {
- RandNumGen rng;
- rng.initTimer();
-@@ -173,15 +192,14 @@
-
- ionData = new IonStreamData;
-
-- const unsigned int NUM_IONS =10000;
-- const float SIMULATED_INTENSITY= 100.0f;
-+ const unsigned int NUM_IONS =100000;
-
- //Simulate a histogram of NUM_IONS
- // between a lower and upper limit.
- // This is flat in TOF space, with mean intensity
- // given by NUM_IONS/NUM_BINS
- //---
-- const float TOF_LIMIT[2] = { 1.0,10};
-+ const float TOF_LIMIT[2] = { 0.0,100};
-
- vector<float> rawData;
- ionData->data.resize(NUM_IONS);
-@@ -194,20 +212,7 @@
- rawData[ui] = simTof;
- }
-
-- const float BIN_STEP=0.1f;
-- vector<float> histogramRes;
-- makeHistogram(rawData,TOF_LIMIT[0],TOF_LIMIT[1],
-- BIN_STEP,histogramRes);
-- //---
-
-- //Find the mean and std. deviation for the tof histogram
-- float meanV,stdV;
-- meanAndStdev(histogramRes,meanV,stdV);
--
-- //check that the TOF histogram's mean matches the expected value
-- const float EXPECTED_MEAN = NUM_IONS*BIN_STEP/(TOF_LIMIT[1] - TOF_LIMIT[0]);
-- TEST(meanV > 0.95*EXPECTED_MEAN &&
-- meanV < EXPECTED_MEAN*1.15,"expected mean should fall (well) within anticipated bounds, but does not");
-
-
- //Now perform the fit in m/c space, and after, check that it matches the anticipated m/c histogram.
-@@ -217,41 +222,39 @@
- vector<float> massData;
- massData.resize(NUM_IONS);
- for(size_t ui=0;ui<NUM_IONS;ui++)
-- massData[ui] = sqrt(rawData[ui]);
-+ massData[ui] = rawData[ui]*rawData[ui];
- vector<float> massHist;
-
- //Recompute the bin step parameter, as the stepping in m/c space to yield
- // the same number of bins will e radially different
-- const float NBINS = ( TOF_LIMIT[1] - TOF_LIMIT[0] )/BIN_STEP;
-- const float MC_BIN_STEP = (sqrt(TOF_LIMIT[1])-sqrt(TOF_LIMIT[0]))/NBINS;
-- makeHistogram(massData,sqrt(TOF_LIMIT[0]),sqrt(TOF_LIMIT[1]),MC_BIN_STEP,massHist);
-+ const float NBINS_TOF = 20;
-+ const float NBINS_MASS= NBINS_TOF;
-+ const float MASS_LIMIT[2] = {TOF_LIMIT[0]*TOF_LIMIT[0], TOF_LIMIT[1]*TOF_LIMIT[1]};
-+
-+
-+ //time-space intensity per unit time
-+ const float TOF_MEAN_INT= NUM_IONS/(TOF_LIMIT[1] - TOF_LIMIT[0]);
-+
-+ const float MC_BIN_STEP = (MASS_LIMIT[1]-MASS_LIMIT[0])/NBINS_MASS;
-+ makeHistogram(massData,MASS_LIMIT[0],MASS_LIMIT[1],MC_BIN_STEP,massHist);
-
- //compute fitted value analytically
- vector<float > fittedMassHist;
-- fittedMassHist.resize(NBINS);
-- for(size_t ui=0;ui<histogramRes.size();ui++)
-- {
-- float mcX;
-- mcX=(float)ui*MC_BIN_STEP + sqrtf(TOF_LIMIT[0]);
-- fittedMassHist[ui]= meanV/(2*mcX);
-- }
-- ASSERT(massHist.size() == histogramRes.size());
-+ createMassBackground(MASS_LIMIT[0],MASS_LIMIT[1],NBINS_MASS,TOF_MEAN_INT,fittedMassHist);
-
-- //FIXME: Test appears to be broken
-- WARN(false,"Test non-functional, and algorithm broken. Fixme.");
-- //check that the numerical and analytical results match
-- for(size_t ui=0;ui<massHist.size();ui++)
-+ //check that the numerical and analytical results match.
-+ // notably, skip the first one as the fit is unstable
-+ for(size_t ui=1;ui<massHist.size();ui++)
- {
- float midV;
-- midV = massHist[ui] + histogramRes[ui];
-+ midV = massHist[ui] + fittedMassHist[ui];
- midV*=0.5f;
- float errorFraction;
-- errorFraction= fabs((massHist[ui] - histogramRes[ui])/midV);
-- //ASSERT(errorFraction < 0.5f);
-+ errorFraction= fabs((massHist[ui] - fittedMassHist[ui])/midV);
-+ ASSERT(errorFraction < 0.5f);
- }
- //---
-
- return true;
- }
--
- #endif
-diff -ruh ./src/backend/filters/algorithms/mass.h ./backend/filters/algorithms/mass.h
---- ./src/backend/filters/algorithms/mass.h 2016-02-08 01:39:07.250999771 +0100
-+++ ./src/backend/filters/algorithms/mass.h 2016-02-08 02:41:11.645762113 +0100
-@@ -194,7 +194,7 @@
-
- //Check that the background fitting routine can fit
- // a random TOF data histogram
--bool testBackgroundFit();
-+bool testBackgroundFitMaths();
-
- #endif
- #endif
-diff -ruh ./src/backend/filters/algorithms/rdf.cpp ./backend/filters/algorithms/rdf.cpp
---- ./src/backend/filters/algorithms/rdf.cpp 2016-02-08 01:39:07.250999771 +0100
-+++ ./src/backend/filters/algorithms/rdf.cpp 2016-02-08 02:41:11.645762113 +0100
-@@ -193,7 +193,7 @@
-
- unsigned int dummyProg;
- vector<Point3D> theHull;
-- if(computeConvexHull(points,progress,wantAbort,theHull,false))
-+ if(computeConvexHull(points,progress,wantAbort,theHull,false,false))
- return 2;
-
- Point3D midPoint(0,0,0);
-@@ -1044,5 +1044,14 @@
-
- }
-
-+bool qhullTest()
-+{
-+#if defined(__WIN64)
-+ //If using a cross-compile (at least)
-+ // qhull under win64 must use long long, or we get random crashes
-+ // The definition is set in qhull/mem.h
-+ COMPILE_ASSERT(sizeof(ptr_intT) == sizeof(long long))
-+#endif
-+}
-
-
-diff -ruh ./src/backend/filters/dataLoad.cpp ./backend/filters/dataLoad.cpp
---- ./src/backend/filters/dataLoad.cpp 2016-02-08 01:39:07.258999772 +0100
-+++ ./src/backend/filters/dataLoad.cpp 2016-02-08 02:41:11.645762113 +0100
-@@ -67,7 +67,7 @@
- NTRANS("Text Data"),
- NTRANS("ATO Data"),
- };
--const char *DEFAULT_LABEL="Mass-to-Charge (amu/e)";
-+const char *DEFAULT_LABEL="Mass-to-Charge (Da/e)";
-
-
-
-diff -ruh ./src/backend/filters/geometryHelpers.cpp ./backend/filters/geometryHelpers.cpp
---- ./src/backend/filters/geometryHelpers.cpp 2016-02-08 01:39:07.258999772 +0100
-+++ ./src/backend/filters/geometryHelpers.cpp 2016-02-08 02:41:11.669762167 +0100
-@@ -455,18 +455,21 @@
- //rotate ion position into cylindrical coordinates
- quat_rot_apply_quat(&p,&qA);
-
-+ fSqrRad=p.fx*p.fx + p.fy*p.fy;
- //Check inside upper and lower bound of cylinder
- // and check inside cylinder radius
-- if(!(p.fz < fA && p.fz > -fA &&
-- p.fx*p.fx+p.fy*p.fy < fB))
-+ if(!( (p.fz < fA && p.fz > -fA ) &&
-+ fSqrRad < fB))
- return (unsigned int)-1;
-
-- fSqrRad=ptmp[0]*ptmp[0] + ptmp[1]*ptmp[1];
--
- }
-
-+ unsigned int mapPos;
-+ mapPos=(unsigned int)(fSqrRad/fB*(float)mapMax);
-+ ASSERT(mapPos < mapMax);
-+
- //Area is constant in square space
-- return (unsigned int)(fSqrRad/fB*(float)mapMax);
-+ return mapPos;
-
- }
-
-@@ -523,8 +526,11 @@
- ASSERT(!invertedClip);
- ASSERT(mapFunc);
- ASSERT(mapMax);
-- //return the 1D mapping for the ion
-- return (this->*mapFunc)(ionIn.getPosRef());
-+ //return the 1D mapping for the ion, or -1 for not mappable
-+ unsigned int mappingPos;
-+ mappingPos=(this->*mapFunc)(ionIn.getPosRef());
-+ ASSERT(mappingPos < mapMax || mappingPos == (unsigned int) -1);
-+ return mappingPos;
- }
-
- void CropHelper::setFilterMode(size_t filterMode)
-diff -ruh ./src/backend/filters/rangeFile.cpp ./backend/filters/rangeFile.cpp
---- ./src/backend/filters/rangeFile.cpp 2016-02-08 01:39:07.258999772 +0100
-+++ ./src/backend/filters/rangeFile.cpp 2016-02-08 02:41:11.673762176 +0100
-@@ -116,6 +116,11 @@
- return 0;
- }
-
-+ progress.filterProgress=0;
-+ progress.stepName=TRANS("Ranging");
-+ progress.step=1;
-+ progress.maxStep=1;
-+
-
- ASSERT(enabledRanges.size() == rng.getNumRanges());
- ASSERT(enabledIons.size() == rng.getNumIons());
-@@ -148,11 +153,6 @@
- sameSize=true;
-
-
-- progress.step=1;
-- progress.filterProgress=0;
-- progress.stepName=TRANS("Pre-Allocate");
-- progress.maxStep=2;
--
- vector<size_t> dSizes;
- dSizes.resize(d.size(),0);
- size_t totalSize=numElements(dataIn);
-@@ -270,7 +270,7 @@
- {
- //slightly over-allocate to allow for any variance
- for(size_t ui=0;ui<d.size();ui++)
-- d[ui]->data.reserve(dSizes[ui]*1.f*RANGE_ALLOC_STEP+10);
-+ d[ui]->data.reserve(dSizes[ui]*1.05f*RANGE_ALLOC_STEP+10);
- }
- catch(std::bad_alloc)
- {
-@@ -282,12 +282,6 @@
- dSizes.clear();
- //===================================
-
-- //Update progress info
-- progress.step=2;
-- progress.filterProgress=0;
-- progress.stepName=TRANS("Range");
--
--
-
-
- //Step 2: Go through each data stream, if it is an ion stream, range it.
-diff -ruh ./src/backend/filters/transform.cpp ./backend/filters/transform.cpp
---- ./src/backend/filters/transform.cpp 2016-02-08 01:39:07.262999773 +0100
-+++ ./src/backend/filters/transform.cpp 2016-02-08 02:41:11.681762194 +0100
-@@ -277,9 +277,10 @@
- DrawStreamData *d=makeMarkerSphere(s);
- if(s)
- devices.push_back(s);
--
-- cacheAsNeeded(d);
--
-+ else
-+ {
-+ cacheAsNeeded(d);
-+ }
- getOut.push_back(d);
- }
-
-diff -ruh ./src/backend/state.cpp ./backend/state.cpp
---- ./src/backend/state.cpp 2016-02-08 01:39:07.266999774 +0100
-+++ ./src/backend/state.cpp 2016-02-08 02:41:11.689762212 +0100
-@@ -979,7 +979,10 @@
- ASSERT(offset < savedCameras.size());
- savedCameras.erase(savedCameras.begin()+offset);
- if(activeCamera >=savedCameras.size())
-- activeCamera=0;
-+ {
-+ ASSERT(savedCameras.size())
-+ activeCamera=savedCameras.size()-1;
-+ }
- }
-
- void AnalysisState::addCamByClone(const Camera *c)
-@@ -990,6 +993,8 @@
-
- void AnalysisState::addCam(const std::string &camName, bool makeActive)
- {
-+ //Disallow unnamed cameras
-+ ASSERT(camName.size());
- //Duplicate the current camera, and give it a new name
- Camera *c=getCam(getActiveCam())->clone();
- c->setUserString(camName);
-@@ -1169,7 +1174,22 @@
- setStateModifyLevel(STATE_MODIFIED_ANCILLARY);
- stashedTrees.erase(stashedTrees.begin() + offset);
- }
-+
-+void AnalysisState::eraseStashes(std::vector<size_t> &offsets)
-+{
-+ std::sort(offsets.begin(),offsets.end());
-+ ASSERT(std::unique(offsets.begin(),offsets.end()) == offsets.end());
-+
-
-+
-+ setStateModifyLevel(STATE_MODIFIED_ANCILLARY);
-+ for(unsigned int ui=offsets.size();ui>0;)
-+ {
-+ ui--;
-+
-+ stashedTrees.erase(stashedTrees.begin() + offsets[ui]);
-+ }
-+}
- bool AnalysisState::hasStateOverrides() const
- {
- if(treeState.hasStateOverrides())
-diff -ruh ./src/backend/state.h ./backend/state.h
---- ./src/backend/state.h 2016-02-08 01:39:07.266999774 +0100
-+++ ./src/backend/state.h 2016-02-08 02:41:11.689762212 +0100
-@@ -368,6 +368,9 @@
-
- //!Add a new camera to the scene
- void addCam(const std::string &camName, bool makeActive=false);
-+
-+ bool defaultCamActive() const { return activeCamera == 0;}
-+
- //=====
-
- //Effect functions
-@@ -417,8 +420,11 @@
-
- //!Insert the given stash into the tree as a child of the given parent filter
- void addStashedToFilters(const Filter *parentFilter, unsigned int stashOffset);
-- //Remove the stash at the specified offset
-+ //Remove the stash at the specified offset. Numbers will
-+ // be reset, so previous offsets will no longer be valid
- void eraseStash(size_t offset);
-+ //Remove the given stashew at the specified offsets
-+ void eraseStashes(std::vector<size_t> &offset);
-
- //Return the number of stash elements
- size_t getStashCount() const { return stashedTrees.size();}
-diff -ruh ./src/backend/viscontrol.cpp ./backend/viscontrol.cpp
---- ./src/backend/viscontrol.cpp 2016-02-08 01:39:07.266999774 +0100
-+++ ./src/backend/viscontrol.cpp 2016-02-08 02:41:11.689762212 +0100
-@@ -670,7 +670,9 @@
-
- void VisController::updateStashComboBox(wxComboBox *comboStash) const
- {
-- comboStash->Clear();
-+ //HACK: Calling ->Clear() under MSW causes a crash
-+ while(comboStash->GetCount())
-+ comboStash->Delete(0);
-
- unsigned int nStashes = state.getStashCount();
- for(unsigned int ui=0;ui<nStashes; ui++)
-@@ -687,7 +689,10 @@
- void VisController::updateCameraComboBox(wxComboBox *comboCamera) const
- {
- //Update the camera dropdown
-- comboCamera->Clear();
-+ //HACK: Calling ->Clear() under MSW causes a crash
-+ while(comboCamera->GetCount())
-+ comboCamera->Delete(0);
-+
- size_t nCams = state.getNumCams();
- //The start from 1 is a hack to avoid the unnamed camera
- for(unsigned int ui=1;ui<nCams;ui++)
-@@ -698,8 +703,7 @@
- //Do not delete as this will be deleted by wx
- comboCamera->Append(camName,
- (wxClientData *)new wxListUint(ui));
-- //If this is the active cam (1) set the selection and (2) remember
-- //the ID
-+ //If this is the active cam (1) set the selection
- if(ui == state.getActiveCam())
- comboCamera->SetSelection(ui-1);
- }
-diff -ruh ./src/common/assertion.h ./common/assertion.h
---- ./src/common/assertion.h 2016-02-08 01:39:07.266999774 +0100
-+++ ./src/common/assertion.h 2016-02-08 02:41:11.693762221 +0100
-@@ -66,6 +66,8 @@
- #define TEST(f,g) if(!(f)) { std::cerr << "Test fail :" << __FILE__ << ":" << __LINE__ << "\t"<< (g) << std::endl;return false;}
- #endif
-
-+ #define TRACE(f) { timespec timeval; clock_gettime(CLOCK_MONOTONIC, &timeval); std::cerr << "<" << f <<">" __FILE__ << ":" << __LINE__ << " t: " << timeval.tv_sec << "." << timeval.tv_nsec/1000 << endl;}
-+
- //A hack to generate compile time asserts (thanks Internet).
- //This causes gcc to give "duplicate case value", if the predicate is false
- #ifndef HAVE_CPP_1X
-@@ -79,6 +81,7 @@
- #define COMPILE_ASSERT(f)
- #define WARN(f,g)
- #define TEST(f,g)
-+ #define TRACE(f)
- //Do we want to trap floating point exceptions
- void trapfpe (bool doTrap=true);
-
-diff -ruh ./src/common/voxels.h ./common/voxels.h
---- ./src/common/voxels.h 2016-02-08 01:39:07.270999774 +0100
-+++ ./src/common/voxels.h 2016-02-08 02:41:11.705762248 +0100
-@@ -31,6 +31,9 @@
- #undef I
- #undef Complex
- #include <typeinfo>
-+#if defined(WIN32) || defined(WIN64)
-+#include <vigra/windows.h>
-+#endif
- #include <vigra/multi_array.hxx>
- #include <vigra/multi_convolution.hxx>
-
-@@ -1506,6 +1509,8 @@
- {
- size_t slicePos;
- slicePos=roundf(offset*binCount[normal]);
-+ if(slicePos == binCount[normal])
-+ slicePos--;
- getSlice(normal,slicePos,p);
- break;
- }
-diff -ruh ./src/gl/drawables.cpp ./gl/drawables.cpp
---- ./src/gl/drawables.cpp 2016-02-08 01:39:07.270999774 +0100
-+++ ./src/gl/drawables.cpp 2016-02-08 02:41:11.709762257 +0100
-@@ -45,7 +45,6 @@
- unsigned int DrawableObj::winX;
- unsigned int DrawableObj::winY;
-
--DrawTexturedQuad DrawPointLegendOverlay::dQuad;
- bool DrawPointLegendOverlay::quadSet=false;
- //==
-
-@@ -182,8 +181,8 @@
- {
- //TODO: Could speedup with LINE_STRIP/LOOP. This is
- //not a bottleneck atm though.
-+ glColor4f(r,g,b,a);
- glBegin(GL_LINES);
-- glColor4f(r,g,b,a);
- //Bottom corner out (three lines from corner)
- glVertex3f(pMin[0],pMin[1],pMin[2]);
- glVertex3f(pMax[0],pMin[1],pMin[2]);
-@@ -725,6 +724,21 @@
- gluDeleteQuadric(q);
- }
-
-+DrawableObj *DrawSphere::clone() const
-+{
-+ DrawSphere *d = new DrawSphere();
-+ d->r=r;
-+ d->g=g;
-+ d->b=b;
-+ d->a=a;
-+ d->origin=origin;
-+ d->radius=radius;
-+ d->latSegments=latSegments;
-+ d->longSegments=longSegments;
-+
-+ d->q=gluNewQuadric();
-+ return d;
-+}
-
- void DrawSphere::getBoundingBox(BoundCube &b) const
- {
-@@ -1858,6 +1872,8 @@
- }
-
-
-+ float visGrey=getHighContrastValue();
-+
- //Draw the completed Steps
- float thetaPerStep = thetaPerFilter/maxStep;
- for(size_t ui=1;ui<step;ui++)
-@@ -1871,7 +1887,7 @@
- if(ui < step-1)
- {
- //Draw a line to mark the step
-- glColor4f(1.0f,0.0f,0.0f,1.0f);
-+ glColor4f(visGrey,0.0f,0.0f,1.0f);
- glBegin(GL_LINES);
- glVertex3f(radiusIn*sin(curTheta),radiusIn*cos(curTheta),0);
- glVertex3f(radiusOut*sin(curTheta),radiusOut*cos(curTheta),0);
-@@ -1961,14 +1977,15 @@
- return;
-
-
-+ float visGrey= getHighContrastValue();
-
-
- const float ALPHA_COMPLETE=0.5*alphaBase;
- const float ALPHA_INCOMPLETE=0.15*alphaBase;
- if(complete)
-- glColor4f(1.0f,1.0f,1.0f,ALPHA_COMPLETE);
-+ glColor4f(visGrey,visGrey,visGrey,ALPHA_COMPLETE);
- else
-- glColor4f(1.0f,1.0f,1.0f,ALPHA_INCOMPLETE);
-+ glColor4f(visGrey,visGrey,visGrey,ALPHA_INCOMPLETE);
-
- //Draw arc
- glBegin(GL_TRIANGLE_STRIP);
-@@ -2214,6 +2231,12 @@
-
- }
-
-+DrawableObj *DrawColourBarOverlay::clone() const
-+{
-+ DrawColourBarOverlay *newBar = new DrawColourBarOverlay(*this);
-+ return newBar;
-+}
-+
- void DrawColourBarOverlay::setColourVec(const vector<float> &r,
- const vector<float> &g,
- const vector<float> &b)
-@@ -2237,45 +2260,6 @@
-
- std::string tmpStr =getDefaultFontFile();
- font = new FTGLPolygonFont(tmpStr.c_str());
--
-- //check to see if we need to init the texture quad
-- if(!quadSet && texPool)
-- {
--
-- dQuad.setUseColouring(false);
--
-- //Create a circular texture
-- const unsigned int N_CHANNELS=4;
-- unsigned int LEG_TEX_SIZE = 256;
-- unsigned char colourWhite[N_CHANNELS]= { 255,255,255,255 };
-- unsigned char colourBlack[N_CHANNELS]= { 0,0,0,0 };
--
-- //TODO: Convert to single channel texture, to save space?
-- // DrawQuad does not support single channel at this time
-- dQuad.resize(LEG_TEX_SIZE,LEG_TEX_SIZE,N_CHANNELS);
-- const float HALF_CIRCLE_R2 = 0.25;
-- #pragma omp parallel for
-- for(unsigned int nX=0;nX<LEG_TEX_SIZE;nX++)
-- {
-- float fx;
-- fx= (float) nX/(float)LEG_TEX_SIZE - 0.5;
-- for(unsigned int nY=0;nY<LEG_TEX_SIZE;nY++)
-- {
-- float fy;
-- fy = (float) nY/(float)LEG_TEX_SIZE -0.5;
-- if( fx*fx + fy*fy < HALF_CIRCLE_R2)
-- dQuad.setData(nX,nY,colourWhite);
-- else
-- dQuad.setData(nX,nY,colourBlack);
-- }
--
-- }
--
-- dQuad.rebindTexture(GL_RGBA);
--
-- quadSet=true;
--
-- }
- }
-
- DrawPointLegendOverlay::~DrawPointLegendOverlay()
-@@ -2318,7 +2302,6 @@
-
- float delta = std::max(std::min(1.0f/legendItems.size(),0.02f),0.05f);
- float size = delta*0.9f;
-- glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- float maxTextWidth=0;
-
-@@ -2329,18 +2312,17 @@
- {
- for(;ui<legendItems.size();ui++)
- {
-+ Draw2DCircle dCirc;
-
-- //Draw textured quad (circle)
-+ //Draw circle
- //--
-- dQuad.setVertex(0,Point3D(curX,curY,0));
-- dQuad.setVertex(1,Point3D(curX+size,curY,0));
-- dQuad.setVertex(2,Point3D(curX+size,curY+size,0));
-- dQuad.setVertex(3,Point3D(curX,curY+size,0));
-+ dCirc.setCentre(curX+size/2.0f,curY+size/2.0f);
-+ dCirc.setRadius(size/2.0f);
-
- const RGBFloat *f;
- f = &legendItems[ui].second;
-- glColor3f(f->v[0],f->v[1],f->v[2]);
-- dQuad.draw();
-+ dCirc.setColour(f->v[0],f->v[1],f->v[2]);
-+ dCirc.draw();
-
-
- //--
-@@ -2369,7 +2351,6 @@
- curX+=maxTextWidth + size;
- curY=position[1] + 0.5*delta;
- }
-- glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
-
- void DrawPointLegendOverlay::addItem(const std::string &s, float r, float g, float b)
-@@ -2863,3 +2844,76 @@
- b.setInvalid();
- }
-
-+Draw2DCircle::Draw2DCircle()
-+{
-+ angularStep = 2.0f*M_PI/180.0f;
-+ filled=true;
-+}
-+
-+void Draw2DCircle::draw() const
-+{
-+
-+ float nSteps = 2.0* M_PI/angularStep;
-+ WARN(nSteps > 1,"Draw2D Circle, too few steps");
-+ glColor4f(r,g,b,1.0f);
-+
-+ if(filled)
-+ {
-+ glBegin(GL_TRIANGLE_FAN);
-+ //Central vertex
-+ glVertex2fv(centre);
-+
-+ //vertices from [0,2PI)
-+ for(unsigned int ui=0;ui<nSteps;ui++)
-+ {
-+ float fx,fy,theta;
-+ theta = angularStep*ui;
-+ fx = centre[0]+cos(-theta)*radius;
-+ fy = centre[1]+sin(-theta)*radius;
-+
-+ glVertex2f(fx,fy);
-+ }
-+
-+ //2PI vertex
-+ glVertex2f(centre[0]+radius,centre[1]);
-+ glEnd();
-+ }
-+ else
-+ {
-+ glBegin(GL_LINE_LOOP);
-+ //Central vertex
-+ for(unsigned int ui=0;ui<nSteps;ui++)
-+ {
-+ float fx,fy,theta;
-+ theta = angularStep*ui;
-+ fx = centre[0]+cos(theta)*radius;
-+ fy = centre[1]+sin(theta)*radius;
-+
-+ glVertex2f(fx,fy);
-+ }
-+ glEnd();
-+ }
-+}
-+
-+void Draw2DCircle::getBoundingBox(BoundCube &b) const
-+{
-+
-+ b.setBounds(centre[0]-radius, centre[1]-radius,
-+ centre[0]+radius, centre[1]+radius,
-+ 0,0);
-+}
-+
-+unsigned int Draw2DCircle::getType() const
-+{
-+ return DRAW_TYPE_2D_CIRCLE;
-+}
-+
-+
-+DrawableObj *Draw2DCircle::clone() const
-+{
-+ Draw2DCircle *p = new Draw2DCircle;
-+ *p = *this;
-+
-+ return p;
-+}
-+
-diff -ruh ./src/gl/drawables.h ./gl/drawables.h
---- ./src/gl/drawables.h 2016-02-08 01:39:07.274999775 +0100
-+++ ./src/gl/drawables.h 2016-02-08 02:41:11.709762257 +0100
-@@ -93,6 +93,7 @@
- DRAW_TYPE_CYLINDER,
- DRAW_TYPE_DISPLAYLIST,
- DRAW_TYPE_GLTEXT,
-+ DRAW_TYPE_2D_CIRCLE,
- DRAW_TYPE_RECTPRISM,
- DRAW_TYPE_COLOURBAR,
- DRAW_TYPE_TEXTUREDOVERLAY,
-@@ -531,6 +532,8 @@
- //! Destructor
- virtual ~DrawSphere();
-
-+ virtual DrawableObj *clone() const;
-+
- virtual unsigned int getType() const {return DRAW_TYPE_SPHERE;};
- //!Sets the location of the sphere's origin
- void setOrigin(const Point3D &p);
-@@ -899,6 +902,7 @@
- DrawColourBarOverlay(const DrawColourBarOverlay &o);
- ~DrawColourBarOverlay(){delete font;};
-
-+ virtual DrawableObj *clone() const;
-
- virtual unsigned int getType() const {return DRAW_TYPE_COLOURBAR;}
-
-@@ -1030,7 +1034,6 @@
- class DrawPointLegendOverlay : public DrawableOverlay
- {
- private:
-- static DrawTexturedQuad dQuad;
- static bool quadSet;
-
- FTFont *font;
-@@ -1194,6 +1197,7 @@
- Point3D position;
- //!size
- float size;
-+
- public:
- DrawAxis();
- ~DrawAxis();
-@@ -1211,5 +1215,41 @@
- void setPosition(const Point3D &p);
-
- void getBoundingBox(BoundCube &b) const;
-+
- };
-+
-+
-+//Draw a 2D filled circle
-+class Draw2DCircle : public DrawableObj
-+{
-+ private:
-+ float centre[2];
-+ float angularStep;
-+ float radius;
-+
-+ //Circle colour
-+ float r,g,b;
-+
-+ //Should the circle be drawn as an outline, or as a filled object
-+ bool filled;
-+ public:
-+ Draw2DCircle();
-+
-+ void result() const;
-+ //Obtain the type mask for this drawable
-+ virtual unsigned int getType() const;
-+ virtual DrawableObj *clone() const;
-+ virtual void getBoundingBox(BoundCube &b) const;
-+
-+ virtual void draw() const;
-+
-+ void setCentre(float fx,float fy) { centre[0] = fx; centre[1]= fy;};
-+ void setRadius(float r) { radius=r;}
-+ //Angular step in radiians
-+ void setAngularStep(float da) { angularStep = da;};
-+
-+ void setColour(float rP, float gP, float bP) { r=rP;g=gP;b=bP;} ;
-+
-+};
-+
- #endif
-diff -ruh ./src/gui/dialogs/animateFilterDialog.cpp ./gui/dialogs/animateFilterDialog.cpp
---- ./src/gui/dialogs/animateFilterDialog.cpp 2016-02-08 01:39:07.278999776 +0100
-+++ ./src/gui/dialogs/animateFilterDialog.cpp 2016-02-08 02:41:11.689762212 +0100
-@@ -408,7 +408,6 @@
- animationGrid->BeginBatch();
- if(animationGrid->GetNumberRows())
- animationGrid->DeleteRows(0,animationGrid->GetNumberRows());
-- animationGrid->EndBatch();
-
-
- animationGrid->AppendRows(propertyAnimator.getNumProps());
-@@ -441,6 +440,8 @@
- animationGrid->SetCellValue(ui,CELL_ENDFRAME, (str));
- }
-
-+ animationGrid->EndBatch();
-+
- //Check for conflicting rows in the animation dialog,
- // and highlight them in colour
- set<size_t> conflictRows;
-@@ -641,12 +642,14 @@
-
- void ExportAnimationDialog::OnFilterGridCellSelected(wxPropertyGridEvent &event)
- {
-- event.Veto();
-
- wxTreeItemId tId=filterTreeCtrl->GetSelection();;
-
- if(tId ==filterTreeCtrl->GetRootItem() || !tId.IsOk())
-+ {
-+ event.Veto();
- return;
-+ }
-
- //Get the filter ID value
- size_t filterId;
-@@ -859,6 +862,8 @@
- ASSERT(false); // that should cover all data types...
- }
-
-+ event.Veto();
-+
- //Add property to animator
- propertyAnimator.addProp(frameProp);
-
-diff -ruh ./src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp ./gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp
---- ./src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 2016-02-08 01:39:07.278999776 +0100
-+++ ./src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp 2016-02-08 02:41:11.705762248 +0100
-@@ -25,6 +25,10 @@
- #include <wx/colordlg.h>
-
-
-+//TODO: Currently we change the foreground text in a button to set colour.
-+// better would be to use a "swatch"
-+
-+
- using std::string;
-
- // begin wxGlade: ::extracode
-@@ -195,16 +199,26 @@
- {
- bool isOK=true;
- isOK&=startFrameOK;
-- isOK&=endFrameOK;
-+ isOK&= (endFrameOK || transitionMode == TRANSITION_STEP) ;
-
-- //Ensure start frame is > end frame
- if(isOK)
- {
-- isOK&=(startFrame<endFrame);
-+ if(transitionMode == TRANSITION_INTERP)
-+ {
-+ //Ensure start frame is > end frame,
-+ // if we are using interp mode
-+ isOK&=(startFrame<endFrame);
-+ }
-+
- if(!isOK)
- {
-+ //If there is a problem, mark the problem with a colour background
- textFrameStart->SetBackgroundColour(*wxCYAN);
-- textFrameEnd->SetBackgroundColour(*wxCYAN);
-+ if(transitionMode == TRANSITION_INTERP)
-+ textFrameEnd->SetBackgroundColour(*wxCYAN);
-+ else
-+ textFrameEnd->SetBackgroundColour(wxNullColour);
-+
- }
- else
- {
-@@ -212,7 +226,8 @@
- textFrameEnd->SetBackgroundColour(wxNullColour);
- }
- }
--
-+
-+ //Enable the OK button if all properties are set appropriately
- buttonOK->Enable(isOK);
- }
-
-diff -ruh ./src/gui/dialogs/StashDialog.cpp ./gui/dialogs/StashDialog.cpp
---- ./src/gui/dialogs/StashDialog.cpp 2016-02-08 01:39:07.274999775 +0100
-+++ ./src/gui/dialogs/StashDialog.cpp 2016-02-08 02:41:11.689762212 +0100
-@@ -164,12 +164,11 @@
- string strTmp;
- pair<std::string,FilterTree> stash;
- long itemIdx;
--
-+ visControl->state.copyStashedTree(ui,stash);
- //First item is the stash name
- itemIdx = listStashes->InsertItem(ui,stash.first);
-
- //Second column is num filters
-- visControl->state.copyStashedTree(ui,stash);
- stream_cast(strTmp,stash.second.size());
- listStashes->SetItem(itemIdx,1,(strTmp));
-
-@@ -329,6 +328,7 @@
- void StashDialog::OnBtnRemove(wxCommandEvent &event)
- {
- //Spin through the list, to find the selected items
-+ vector<size_t> itemsToRemove;
- int item=-1;
- for ( ;; )
- {
-@@ -337,15 +337,12 @@
- wxLIST_STATE_SELECTED);
- if ( item == -1 )
- break;
--
-- visControl->state.eraseStash(listStashes->GetItemData(item));
-- updateList();
-- updateTree();
-- updateGrid();
--
-+ itemsToRemove.push_back(listStashes->GetItemData(item));
- }
-
-+ visControl->state.eraseStashes(itemsToRemove);
-
-+ ready();
- }
-
- void StashDialog::do_layout()
-diff -ruh ./src/gui/glPane.cpp ./gui/glPane.cpp
---- ./src/gui/glPane.cpp 2016-02-08 01:39:07.278999776 +0100
-+++ ./src/gui/glPane.cpp 2016-02-08 02:41:11.721762284 +0100
-@@ -210,6 +210,13 @@
- wxPaintEvent ptEvent;
- wxPostEvent(this,ptEvent);
-
-+#ifdef WIN32
-+ //Hack for windows. Does not redraw otherwise.
-+ // Refresh and Update in tandom dont work.
-+ Show(false);
-+ Show(true);
-+#endif
-+
- }
-
- // some useful events to use
-@@ -635,7 +642,7 @@
- }
- break;
- default:
-- event.Skip();
-+ event.Skip(true);
- }
- }
-
-@@ -658,6 +665,7 @@
- if(event.ShiftDown())
- cameraMoveRate*=5;
-
-+ bool update=true;
- switch(event.GetKeyCode())
- {
- case '-':
-@@ -687,10 +695,12 @@
- break;
- }
- default:
-- event.Skip();
-+ event.Skip(true);
-+ update=false;
- }
-
-- Refresh();
-+ if(update)
-+ Refresh();
- }
-
-
-@@ -1051,10 +1061,11 @@
- free(imageBuffer);
-
- combineWxImage(*image,imageOverlay);
-+
-+ //Free the tile buffer
-+ trDelete(tr);
- }
-
-- //Free the tile buffer
-- trDelete(tr);
-
- //--------------
- bool isOK=image->SaveFile(filename,wxBITMAP_TYPE_PNG);
-diff -ruh ./src/gui/mainFrame.cpp ./gui/mainFrame.cpp
---- ./src/gui/mainFrame.cpp 2016-02-08 01:39:07.282999776 +0100
-+++ ./src/gui/mainFrame.cpp 2016-02-08 02:41:11.805762472 +0100
-@@ -390,6 +390,7 @@
- verCheckThread=0;
- refreshThread=0;
- refreshControl=0;
-+ ensureResultVisible=false;
- lastProgressData.reset();
-
- //Set up the program icon handler
-@@ -662,7 +663,6 @@
- checkWeakRandom = new wxCheckBox(noteTools, ID_CHECK_WEAKRANDOM, TRANS("Fast and weak randomisation."));
- checkWeakRandom->SetValue(true);
- checkLimitOutput = new wxCheckBox(noteTools, ID_CHECK_LIMIT_POINT_OUT, TRANS("Limit Output Pts"));
-- // checkLimitOutput->SetValue((visControl.getIonDisplayLimit() !=0));
- std::string tmpStr;
- // stream_cast(tmpStr,visControl.getIonDisplayLimit());
- textLimitOutput = new wxTextCtrl(noteTools, ID_TEXT_LIMIT_POINT_OUT, (tmpStr),
-@@ -754,7 +754,16 @@
- initedOK=true;
-
-
--
-+ // Set the limit value checkbox and text field with the
-+ // value obtained from the configuration file
-+ unsigned int ionLimit=visControl.getIonDisplayLimit();
-+ checkLimitOutput->SetValue((ionLimit!=0));
-+ if(ionLimit)
-+ {
-+ std::string sValue;
-+ stream_cast(sValue,visControl.getIonDisplayLimit());
-+ textLimitOutput->SetValue(sValue);
-+ }
-
-
-
-@@ -1083,6 +1092,8 @@
- //Load the file
- if(!loadFile(wxF.GetPath()))
- {
-+ //If the load failed, do not try to set the
-+ // selection & visibility
- visControl.clearTreeFilterViewPersistence();
- return;
- }
-@@ -1093,15 +1104,6 @@
- configFile.addRecentFile(tmp);
- //Update the "recent files" menu
- recentHistory->AddFileToHistory(wxF.GetPath());
--
-- //If we are using the default camera,
-- //move it to make sure that it is visible
-- if(visControl.state.getNumCams() == 1)
-- {
-- visControl.scene.ensureVisible(3);
-- }
--
-- panelTop->forceRedraw();
- }
-
- void MainWindowFrame::OnFileMerge(wxCommandEvent &event)
-@@ -1123,7 +1125,6 @@
-
- statusMessage(TRANS("Merged file."),MESSAGE_INFO);
-
-- panelTop->forceRedraw();
-
- setSaveStatus();
- }
-@@ -1233,19 +1234,6 @@
- statusMessage(TRANS("Tip: You can use ctrl to merge"),MESSAGE_HINT);
- #endif
- }
--
-- if(loaded || rangeLoaded)
-- doSceneUpdate();
--
-- if(files.Count())
-- {
-- //If we are using the default camera,
-- //move it to make sure that it is visible
-- if(visControl.state.getNumCams() == 1)
-- {
-- visControl.scene.ensureVisible(3);
-- }
-- }
- }
-
- bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge,bool noUpdate)
-@@ -1372,7 +1360,7 @@
- updateWxTreeCtrl(treeFilters);
-
- if(!noUpdate)
-- return doSceneUpdate();
-+ return doSceneUpdate(true);
-
- return true;
- }
-@@ -1420,10 +1408,6 @@
- }
-
- setSaveStatus();
--
-- //make sure camera is properly centred
-- if(visControl.state.getNumCams() == 1)
-- visControl.scene.ensureVisible(3);
- }
-
- }
-@@ -1725,7 +1709,12 @@
- unsigned int nFilters;
- nFilters = visControl.state.treeState.size();
- comboFilters->Enable(!locking && nFilters);
-- refreshButton->Enable(!locking && nFilters);
-+ if(locking)
-+ refreshButton->SetLabel(TRANS("Abo&rt"));
-+ else
-+ refreshButton->SetLabel(TRANS("&Refresh"));
-+ refreshButton->Enable(nFilters);
-+
- btnFilterTreeErrs->Enable(!locking);
- treeFilters->Enable(!locking);
-
-@@ -2899,7 +2888,7 @@
- info.SetName((PROGRAM_NAME));
- info.SetVersion((PROGRAM_VERSION));
- info.SetDescription(TRANS("Quick and dirty analysis for point data."));
-- info.SetWebSite(wxT("https://sourceforge.net/apps/phpbb/threedepict/"));
-+ info.SetWebSite(wxT("https://threedepict.sourceforge.net/"));
-
- info.AddDeveloper(wxT("D. Haley"));
- info.AddDeveloper(wxT("A. Ceguerra"));
-@@ -2991,7 +2980,7 @@
- void MainWindowFrame::OnComboFilterText(wxCommandEvent &event)
- {
- //prevent user from modifying text
-- comboFilters->ChangeValue(TRANS(ADD_FILTER_TEXT));
-+ //comboFilters->ChangeValue(TRANS(ADD_FILTER_TEXT));
- }
-
- void MainWindowFrame::OnComboStash(wxCommandEvent &event)
-@@ -3447,7 +3436,9 @@
- void MainWindowFrame::OnGridCameraPropertyChange(wxPropertyGridEvent &event)
- {
-
-- if(programmaticEvent)
-+ //Check for inited OK. Seem to be getting called before
-+ //do_layout is complete.
-+ if(programmaticEvent || !initedOK)
- {
- event.Veto();
- return;
-@@ -3522,10 +3513,17 @@
- backCameraPropGrid->SetExtraStyle(PROPERTY_GRID_EXTRA_STYLE);
-
- visControl.updateCameraPropGrid(backCameraPropGrid,cameraId);
-+ int columnPos =gridCameraProperties->GetSplitterPosition();
-
- std::swap(backCameraPropGrid,gridCameraProperties);
- do_cameragrid_prop_layout();
-+ gridCameraProperties->SetSplitterPosition(columnPos);
-
-+#ifdef __WIN32
-+ //Move the splitter panel
-+ splitLeftRight->SetSashPosition(splitLeftRight->GetSashPosition()+1);
-+ splitLeftRight->SetSashPosition(splitLeftRight->GetSashPosition()-1);
-+#endif
- //Ensure that the GL panel shows latest cam orientation
- panelTop->forceRedraw();
- programmaticEvent=false;
-@@ -3583,7 +3581,7 @@
- }
- else
- {
--
-+ ASSERT(camName.size());
- //Create a new camera for the scene.
- visControl.state.addCam(camName,true);
-
-@@ -3773,7 +3771,7 @@
-
- }
-
--bool MainWindowFrame::doSceneUpdate()
-+bool MainWindowFrame::doSceneUpdate(bool ensureVisible)
- {
- //Update scene
- ASSERT(!currentlyUpdatingScene);
-@@ -3800,6 +3798,8 @@
- //reset the progress timer animation
- visControl.scene.resetProgressAnim();
-
-+ ensureResultVisible=ensureVisible;
-+
- ASSERT(!refreshControl);
- refreshControl = new RefreshController(visControl.state.treeState);
- refreshThread=new RefreshThread(this,refreshControl);
-@@ -3871,7 +3871,6 @@
- //Restore the UI elements to their interactive state
- setLockUI(false);
-
-- panelTop->forceRedraw();
- panelSpectra->Refresh(false);
-
- updateEditRangeMenu();
-@@ -3945,6 +3944,19 @@
- MainFrame_statusbar->SetStatusText(TRANS("Complete"),1);
- MainFrame_statusbar->SetStatusText("",2);
- }
-+
-+
-+ if(ensureResultVisible)
-+ {
-+ //If we are using the default camera,
-+ //move it to make sure that it is visible
-+ if(visControl.state.getNumCams() == 1)
-+ visControl.scene.ensureVisible(3);
-+
-+ ensureResultVisible=false;
-+ }
-+
-+
- //restart the update timer, to check for updates from the backend
- updateTimer->Start(UPDATE_TIMER_DELAY);
- }
-@@ -4091,12 +4103,6 @@
-
- if(requireFirstUpdate && !refreshThreadActive())
- {
-- //If we are using the default camera,
-- //move it to make sure that it is visible
-- if(visControl.state.getNumCams() == 1)
-- visControl.scene.ensureVisible(3);
--
--
- doSceneUpdate();
-
- requireFirstUpdate=false;
-@@ -4178,6 +4184,7 @@
- }
-
-
-+
- programmaticEvent=false;
- }
-
-@@ -4582,6 +4589,7 @@
- Thaw();
- }
-
-+
- //This routine is used by other UI processes to trigger an abort
- void MainWindowFrame::OnProgressAbort(wxCommandEvent &event)
- {
-@@ -4609,8 +4617,12 @@
- if(!gridCameraProperties || !gridFilterPropGroup)
- return;
-
-+ //Run abort code as needed
- if(currentlyUpdatingScene || refreshThreadActive())
-+ {
-+ OnProgressAbort(event);
- return;
-+ }
-
- //dirty hack to get keyboard state.
- wxMouseState wxm = wxGetMouseState();
-@@ -4817,6 +4829,16 @@
- programmaticEvent=false;
-
- setSaveStatus();
-+
-+ // There is one camera that we cannot access
-+ // TODO: This logic should not be here, but in the widget update
-+ if(visControl.state.getNumCams() > 1)
-+ {
-+ visControl.updateCameraComboBox(comboCamera);
-+ visControl.updateCameraPropGrid(gridCameraProperties,visControl.state.getActiveCam());
-+ }
-+ else
-+ gridCameraProperties->Clear();
- }
-
- }
-diff -ruh ./src/gui/mainFrame.h ./gui/mainFrame.h
---- ./src/gui/mainFrame.h 2016-02-08 01:39:07.282999776 +0100
-+++ ./src/gui/mainFrame.h 2016-02-08 02:41:11.805762472 +0100
-@@ -117,7 +117,7 @@
- //!Update the progress information in the status bar
- void updateProgressStatus();
- //!Perform an update to the 3D Scene. Returns false if refresh failed
-- bool doSceneUpdate();
-+ bool doSceneUpdate(bool ensureResultVisible=false);
-
- //!Complete the scene update. Returns false if failed
- void finishSceneUpdate(unsigned int errCode);
-@@ -162,6 +162,8 @@
- bool currentlyUpdatingScene;
- //!Have we aborted an update
- bool haveAborted;
-+ //!Should the gui ensure that the refresh result is visible at the next update?
-+ bool ensureResultVisible;
-
- //!source item when dragging a filter in the tree control
- wxTreeItemId *filterTreeDragSource;
-diff -ruh ./src/testing/testing.cpp ./testing/testing.cpp
---- ./src/testing/testing.cpp 2016-02-08 01:39:07.286999777 +0100
-+++ ./src/testing/testing.cpp 2016-02-08 02:41:11.805762472 +0100
-@@ -553,7 +553,7 @@
- {
- if(!testAnderson())
- return false;
-- if(!testBackgroundFit())
-+ if(!testBackgroundFitMaths())
- return false;
-
- if(!K3DMk2Tests())
diff --git a/debian/patches/diff_0.0.19_to_effd078610a7 b/debian/patches/diff_0.0.19_to_effd078610a7
new file mode 100644
index 0000000..27e5e88
--- /dev/null
+++ b/debian/patches/diff_0.0.19_to_effd078610a7
@@ -0,0 +1,1235 @@
+diff -r d478204af715 -r effd078610a7 docs/manual-latex/build-latex.sh
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/docs/manual-latex/build-latex.sh Tue Jun 21 12:45:20 2016 +0100
+@@ -0,0 +1,37 @@
++#!/bin/bash
++LATEXBIN=pdflatex
++BIBTEXBIN=bibtex
++if [ x`which $LATEXBIN` == x"" ] ; then
++ echo "no $LATEXBIN"
++ exit 1
++fi
++
++if [ x`which $BIBTEXBIN` == x"" ] ; then
++ echo "no $BIBTEXBIN"
++ exit 1
++fi
++
++MANUAL=manual.tex
++
++#check to see if the manual and its bib file are around
++if [ ! -f $MANUAL ] ; then
++ echo "$MANUAL is missing"
++ exit 1
++fi
++
++#Remove the old manul
++rm -f manual.pdf
++
++
++
++#run the multi-pass latex build.
++$LATEXBIN $MANUAL || { echo "failed latex build (pass 1 of 2)"; exit 1 ; }
++$BIBTEXBIN `basename -s .tex $MANUAL` || { echo "failed bibtex build"; exit 1 ; }
++$LATEXBIN $MANUAL || { echo "failed latex build (pass 2 of 2)"; exit 1 ; }
++
++
++if [ ! -f manual.pdf ] ; then
++ echo "latex ran, but somehow we did not output the PDF...."
++ exit 1
++fi
++
+diff -r d478204af715 -r effd078610a7 src/backend/filter.cpp
+--- a/src/backend/filter.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filter.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -553,7 +553,7 @@
+ ASSERT(scatterIntensity.empty());
+
+
+- ASSERT(plotType < PLOT_TYPE_ENUM_END);
++ ASSERT(plotStyle < PLOT_TYPE_ENUM_END);
+ }
+ void RangeStreamData::checkSelfConsistent() const
+ {
+diff -r d478204af715 -r effd078610a7 src/backend/filter.h
+--- a/src/backend/filter.h Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filter.h Tue Jun 21 12:45:20 2016 +0100
+@@ -395,7 +395,7 @@
+ //Label for X, Y axes
+ std::string xLabel,yLabel;
+
+- unsigned int plotType;
++ unsigned int plotStyle;
+
+ //!Structured XY data pairs for plotting curve
+ Array2D<float> xyData;
+diff -r d478204af715 -r effd078610a7 src/backend/filters/algorithms/rdf.cpp
+--- a/src/backend/filters/algorithms/rdf.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/algorithms/rdf.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -862,6 +862,8 @@
+ return RDF_ABORT_FAIL;
+ #endif
+
++ *progressPtr=100;
++
+ return 0;
+ }
+
+@@ -1003,6 +1005,8 @@
+ #endif
+
+ //Calculations complete!
++ *progressPtr=100;
++
+ return 0;
+ }
+
+diff -r d478204af715 -r effd078610a7 src/backend/filters/annotation.cpp
+--- a/src/backend/filters/annotation.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/annotation.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -167,8 +167,15 @@
+
+ //If we are not enabled, do not draw anything into the output
+ if(!active)
++ {
++ progress.filterProgress=100;
+ return 0;
++ }
+
++ progress.step=1;
++ progress.maxStep=1;
++ progress.stepName=TRANS("Draw");
++
+ DrawStreamData *d;
+ d = new DrawStreamData;
+ d->parent=this;
+@@ -505,6 +512,7 @@
+ d->cached=0;
+ getOut.push_back(d);
+
++ progress.filterProgress=100;
+ return 0;
+ }
+
+diff -r d478204af715 -r effd078610a7 src/backend/filters/boundingBox.cpp
+--- a/src/backend/filters/boundingBox.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/boundingBox.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -510,7 +510,6 @@
+ }
+ #endif
+ bTotal.expand(bThis);
+- progress.filterProgress=100;
+ break;
+ }
+ default:
+@@ -521,6 +520,7 @@
+ getOut.push_back(dataIn[ui]);
+ }
+
++ progress.filterProgress=100;
+ //Append the bounding box if it is valid
+ if(bTotal.isValid())
+ {
+diff -r d478204af715 -r effd078610a7 src/backend/filters/clusterAnalysis.cpp
+--- a/src/backend/filters/clusterAnalysis.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/clusterAnalysis.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -685,7 +685,7 @@
+ Plot2DStreamData *p = new Plot2DStreamData;
+ p->parent=this;
+
+- p->plotType=PLOT_2D_SCATTER;
++ p->plotStyle=PLOT_2D_SCATTER;
+ p->dataLabel=TRANS("Morphology Plot");
+ p->xLabel=TRANS("\\lambda_1:\\lambda_2 ratio");
+ p->yLabel=TRANS("\\lambda_2:\\lambda_3 ratio");
+diff -r d478204af715 -r effd078610a7 src/backend/filters/ionColour.cpp
+--- a/src/backend/filters/ionColour.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/ionColour.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -271,12 +271,14 @@
+
+
+ p.name=TRANS("Show Bar");
++ p.helpText=TRANS("Display the colour legend in the 3D view");
+ p.key=KEY_IONCOLOURFILTER_SHOWBAR;
+ p.data=boolStrEnc(showColourBar);
+ p.type=PROPERTY_TYPE_BOOL;
+ propertyList.addProperty(p,curGroup);
+
+ p.name=TRANS("Opacity");
++ p.helpText=TRANS("How see-through to make the legend (0- transparent, 1- solid)");
+ p.key=KEY_IONCOLOURFILTER_ALPHA;
+ stream_cast(p.data,alpha);
+ p.type=PROPERTY_TYPE_REAL;
+diff -r d478204af715 -r effd078610a7 src/backend/filters/ionDownsample.cpp
+--- a/src/backend/filters/ionDownsample.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/ionDownsample.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -88,7 +88,7 @@
+ rsdIncoming = new RangeStreamData;
+ *rsdIncoming=*c;
+
+- if(ionFractions.size() != c->rangeFile->getNumIons())
++ if(ionFractions.size() != c->rangeFile->getNumIons()+1)
+ {
+ //set up some defaults; seeded from normal
+ ionFractions.resize(c->rangeFile->getNumIons()+1,fraction);
+@@ -464,7 +464,8 @@
+
+ propertyList.setGroupTitle(curGroup,TRANS("Mode"));
+ curGroup++;
+- if(rsdIncoming && perSpecies)
++
++ if(rsdIncoming && perSpecies && rsdIncoming->enabledIons.size())
+ {
+ unsigned int typeVal;
+ if(fixedNumOut)
+diff -r d478204af715 -r effd078610a7 src/backend/filters/ionInfo.cpp
+--- a/src/backend/filters/ionInfo.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/ionInfo.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -398,7 +398,7 @@
+
+
+ //"Pairwise events" - where we perform an action if both
+- //These
++ //these are set
+ if(wantIonCounts && wantVolume)
+ {
+ if(computedVol > sqrtf(std::numeric_limits<float>::epsilon()))
+@@ -420,6 +420,9 @@
+ }
+ }
+
++
++ progress.filterProgress=100;
++
+ return 0;
+ }
+
+diff -r d478204af715 -r effd078610a7 src/backend/filters/spatialAnalysis.cpp
+--- a/src/backend/filters/spatialAnalysis.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/spatialAnalysis.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -655,115 +655,180 @@
+ return ERR_FILE_READ_FAIL;
+
+
+-
+- progress.step=3;
+- progress.stepName=TRANS("Build");
+- progress.filterProgress=0;
+-
+- //Build the search tree we will use to perform replacement
+- K3DTreeMk2 tree;
+- tree.resetPts(fileIons,false);
+- if(!tree.build())
+- return ERR_ABORT_FAIL;
+- BoundCube b;
+- tree.getBoundCube(b);
+-
+- //map the offset of the nearest to
+- //the tree ID
+- vector<size_t > nearestVec;
+- nearestVec.resize(inIons.size());
+-
+- //TODO: pair vector might be faster
+- // as we can use it in sequence, and can use openmp
+- map<size_t,size_t> matchedMap;
+-
+- //Find the nearest point for all points in the dataset
+-
+- #pragma omp parallel for
+- for(size_t ui=0;ui<inIons.size();ui++)
++ vector<IonHit> outIons;
++ if(inIons.empty() || fileIons.empty())
+ {
+- nearestVec[ui]=tree.findNearestUntagged(inIons[ui].getPos(),b,false);
+- }
+-
+- float sqrReplaceTol=replaceTolerance*replaceTolerance;
+-
+- //Filter this to only points that had an NN within range
+- #pragma omp parallel for
+- for(size_t ui=0;ui<inIons.size();ui++)
+- {
+- if(nearestVec[ui]!=(size_t)-1 && inIons[ui].getPos().sqrDist(*tree.getPt(nearestVec[ui])) <=sqrReplaceTol)
++ //Performance increase if we have an empty item.
++ // - in this case we can swap sets around
++ switch(replaceMode)
+ {
+- #pragma omp critical
+- matchedMap[ui]=tree.getOrigIndex(nearestVec[ui]);
++ case REPLACE_MODE_UNION:
++ {
++ //If the local data is empty, then the union is just the "b" data (swap).
++ // if nonempty, then it is simply the "a" data
++ if(inIons.empty())
++ outIons.swap(fileIons);
++ else
++ outIons.swap(inIons);
++ break;
++ }
++ case REPLACE_MODE_SUBTRACT:
++ {
++ //if either localdata OR bdata is empty, then we don't need to do anything.
++ // either way, input stays as it is
++ outIons.swap(inIons);
++ break;
++ }
++ case REPLACE_MODE_INTERSECT:
++ {
++ //intersection with empty set is empty set.
++ // might as well clear the ions incoming
++ inIons.clear();
++ break;
++ }
++ default:
++ ASSERT(false);
++
+ }
+ }
+-
+- nearestVec.clear();
+-
+-
+- progress.step=4;
+- progress.stepName=TRANS("Compute");
+- progress.filterProgress=0;
+-
+- //Finish if no matches
+- if(matchedMap.empty())
++ else
+ {
+- progress.filterProgress=100;
+- return 0;
+- }
+-
+- vector<IonHit> outIons;
+- switch(replaceMode)
+- {
+- case REPLACE_MODE_SUBTRACT:
++
++ progress.step=3;
++ progress.stepName=TRANS("Build");
++ progress.filterProgress=0;
++
++ //TODO: Possible speed increase by finding the smaller of
++ // the two inputs, and using that to build the tree
++
++ //Build the search tree we will use to perform replacement
++ K3DTreeMk2 tree;
++ tree.resetPts(fileIons,false);
++ if(!tree.build())
++ return ERR_ABORT_FAIL;
++ BoundCube b;
++ tree.getBoundCube(b);
++
++ //map the offset of the nearest to
++ //the tree ID
++ vector<size_t > nearestVec;
++ nearestVec.resize(inIons.size());
++
++ //TODO: pair vector might be faster
++ // as we can use it in sequence, and can use openmp
++ map<size_t,size_t> matchedMap;
++
++ //Find the nearest point for all points in the dataset
++ // maps the ith ion in "inions" to the tree value
++ #pragma omp parallel for
++ for(size_t ui=0;ui<inIons.size();ui++)
+ {
+- //In subtraction mode, we should have
+- // at least this many ions
+- if(inIons.size() > matchedMap.size())
+- outIons.reserve(inIons.size()-matchedMap.size());
+-
+- //
+- #pragma omp parallel for
+- for(unsigned int ui=0;ui<inIons.size();ui++)
++ nearestVec[ui]=tree.findNearestUntagged(inIons[ui].getPos(),b,false);
++ }
++
++ float sqrReplaceTol=replaceTolerance*replaceTolerance;
++
++ //Filter this to only points that had an NN within range
++ #pragma omp parallel for
++ for(size_t ui=0;ui<inIons.size();ui++)
++ {
++ if(nearestVec[ui]!=(size_t)-1 && inIons[ui].getPos().sqrDist(*tree.getPt(nearestVec[ui])) <=sqrReplaceTol)
+ {
+- map<size_t,size_t>::iterator it;
+- it=matchedMap.find(ui);
+- if(it != matchedMap.end())
+- continue;
+-
+ #pragma omp critical
+- outIons.push_back(inIons[ui]);
++ matchedMap[ui]=tree.getOrigIndex(nearestVec[ui]);
+ }
+- break;
+ }
+- case REPLACE_MODE_INTERSECT:
++
++ nearestVec.clear();
++
++
++ progress.step=4;
++ progress.stepName=TRANS("Compute");
++ progress.filterProgress=0;
++
++
++ //now we have a map that matches as so:
++ // map ( "inIon" ID -> "fileIon" ID)
++ // inIon should be our "A" in "A operator B"
++ switch(replaceMode)
+ {
+- outIons.reserve(matchedMap.size());
+-
+- if(replaceMass)
++ case REPLACE_MODE_SUBTRACT:
+ {
+- for(map<size_t,size_t>::const_iterator it=matchedMap.begin();it!=matchedMap.end();++it)
++ //If no matches, A-0 = A. Just return input
++ if(matchedMap.empty())
+ {
+- outIons.push_back(fileIons[it->second]);
+- ASSERT(fileIons[it->second].getPosRef().sqrDist(inIons[it->first].getPosRef()) < sqrReplaceTol);
++ outIons.swap(inIons);
++ break;
+ }
++ //In subtraction mode, we should have
++ // at least this many ions
++ if(inIons.size() > matchedMap.size())
++ outIons.reserve(inIons.size()-matchedMap.size());
++
++ //
++ #pragma omp parallel for
++ for(unsigned int ui=0;ui<inIons.size();ui++)
++ {
++ map<size_t,size_t>::iterator it;
++ it=matchedMap.find(ui);
++ if(it != matchedMap.end())
++ continue;
++
++ #pragma omp critical
++ outIons.push_back(inIons[ui]);
++ }
++ break;
+ }
+- else
++ case REPLACE_MODE_INTERSECT:
+ {
+- for(map<size_t,size_t>::const_iterator it=matchedMap.begin();it!=matchedMap.end();++it)
++ //Finish if no matches
++ if(matchedMap.empty())
++ break;
++
++ outIons.reserve(matchedMap.size());
++
++ if(replaceMass)
+ {
+- outIons.push_back(inIons[it->first]);
++ for(map<size_t,size_t>::const_iterator it=matchedMap.begin();it!=matchedMap.end();++it)
++ {
++ outIons.push_back(fileIons[it->second]);
++ ASSERT(fileIons[it->second].getPosRef().sqrDist(inIons[it->first].getPosRef()) < sqrReplaceTol);
++ }
+ }
++ else
++ {
++ for(map<size_t,size_t>::const_iterator it=matchedMap.begin();it!=matchedMap.end();++it)
++ {
++ outIons.push_back(inIons[it->first]);
++ }
++ }
++ break;
+ }
+- break;
++ case REPLACE_MODE_UNION:
++ {
++ outIons.swap(fileIons);
++ outIons.reserve(outIons.size() + fileIons.size() - matchedMap.size());
++ map<size_t,size_t>::const_iterator it=matchedMap.begin();
++
++
++ for(unsigned int ui=0;ui<inIons.size();ui++)
++ {
++ if(it !=matchedMap.end() && (it->first == ui) )
++ {
++ it++;
++ continue;
++ }
++
++
++ outIons.push_back(inIons[ui]);
++ }
++
++
++ break;
++ }
++ default:
++ ASSERT(false);
+ }
+- case REPLACE_MODE_UNION:
+- {
+- ASSERT(false);
+- break;
+- }
+- default:
+- ASSERT(false);
+ }
+
+ //Only output ions if any were found
+@@ -2779,6 +2844,8 @@
+ newD->data.resize(d->data.size());
+ if(stopMode == STOP_MODE_NEIGHBOUR)
+ {
++ unsigned int nProg=0;
++
+ bool spin=false;
+ #pragma omp parallel for shared(spin)
+ for(size_t uj=0;uj<d->data.size();uj++)
+@@ -2811,14 +2878,15 @@
+ }
+
+ res.clear();
++ #pragma atomic
++ nProg++;
+
+ //Update progress as needed
+ if(!curProg--)
+ {
+ #pragma omp critical
+ {
+- n+=NUM_CALLBACK/(nnMax);
+- progress.filterProgress= (unsigned int)(((float)n/(float)totalDataSize)*100.0f);
++ progress.filterProgress= (unsigned int)(((float)nProg/(float)totalDataSize)*100.0f);
+ if(*Filter::wantAbort)
+ spin=true;
+ curProg=NUM_CALLBACK/(nnMax);
+@@ -3063,9 +3131,10 @@
+ IonStreamData *newD = new IonStreamData;
+ newD->parent=this;
+
+- //Adjust this number to provide more update thanusual, because we
++ //Adjust this number to provide more update than usual, because we
+ //are not doing an o(1) task between updates; yes, it is a hack
+- unsigned int curProg=NUM_CALLBACK/(10*nnMax);
++ const unsigned int PROG_PER_PASS=NUM_CALLBACK/(10*nnMax);
++ unsigned int curProg=PROG_PER_PASS;
+ newD->data.reserve(d->data.size());
+ if(stopMode == STOP_MODE_NEIGHBOUR)
+ {
+@@ -3113,11 +3182,11 @@
+ {
+ #pragma omp critical
+ {
+- n+=NUM_CALLBACK/(nnMax);
++ n+=PROG_PER_PASS;
+ progress.filterProgress= (unsigned int)(((float)n/(float)totalDataSize)*100.0f);
+ if(*Filter::wantAbort)
+ spin=true;
+- curProg=NUM_CALLBACK/(nnMax);
++ curProg=PROG_PER_PASS;
+ }
+ }
+ }
+@@ -3263,6 +3332,8 @@
+ break;
+ }
+ }
++ progress.filterProgress=100;
++
+ //If we have bad points, let the user know.
+ if(!badPts.empty())
+ {
+@@ -4230,11 +4301,8 @@
+ }
+
+ //distance between search pt and found pt
+- float sqrDistance;
+- sqrDistance = searchTree.getPtRef(ptIdx).sqrDist(pSource[ui].getPosRef());
+-
+- if(sqrDistance > DISTANCE_EPSILON)
+- ptsFound.insert(ptIdx);
++
++ ptsFound.insert(ptIdx);
+ }
+
+
+@@ -4244,8 +4312,14 @@
+ //Count the number of numerator and denominator ions, using the masses we set aside earlier
+ for(set<size_t>::iterator it=ptsFound.begin(); it!=ptsFound.end(); ++it)
+ {
++
++ //check that the distance is non-zero, to force no self-matching
++ float sqrDistance;
++ sqrDistance = searchTree.getPtRef(*it).sqrDist(pSource[ui].getPosRef());
++ if(sqrDistance < DISTANCE_EPSILON)
++ continue;
++
+ float ionMass;
+- //check that the distance is non-zero, to force no self-matching
+ ionMass = dataMasses[searchTree.getOrigIndex(*it)];
+
+ unsigned int ionID;
+@@ -4326,9 +4400,11 @@
+ bool nnHistogramTest();
+ bool rdfPlotTest();
+ bool axialDistTest();
+-bool replaceTest();
++bool replaceIntersectAndUnionTest();
+ bool localConcTestRadius();
+ bool localConcTestNN();
++bool replaceSubtractTest();
++bool replaceUnionTest();
+
+ bool SpatialAnalysisFilter::runUnitTests()
+ {
+@@ -4343,8 +4419,15 @@
+
+ if(!axialDistTest())
+ return false;
+- if(!replaceTest())
++ if(!replaceIntersectAndUnionTest())
+ return false;
++
++ if(!replaceSubtractTest())
++ return false;
++
++ if(!replaceUnionTest())
++ return false;
++
+ if(!localConcTestRadius())
+ return false;
+
+@@ -4617,7 +4700,7 @@
+ return true;
+ }
+
+-bool replaceTest()
++bool replaceIntersectAndUnionTest()
+ {
+ std::string ionFile=createTmpFilename(NULL,".pos");
+
+@@ -4637,6 +4720,157 @@
+ //Create a spatial analysis filter
+ SpatialAnalysisFilter *f=new SpatialAnalysisFilter;
+ f->setCaching(false);
++ //Set it to do a union calculation
++ bool needUp;
++ string s;
++ s=TRANS(SPATIAL_ALGORITHMS[ALGORITHM_REPLACE]);
++ TEST(f->setProperty(KEY_ALGORITHM,s,needUp),"Set prop");
++ TEST(f->setProperty(KEY_REPLACE_FILE,ionFile,needUp),"Set prop");
++ s="1";
++ TEST(f->setProperty(KEY_REPLACE_VALUE,s,needUp),"Set prop");
++
++ vector<unsigned int> opVec;
++ opVec.push_back(REPLACE_MODE_INTERSECT);
++ opVec.push_back(REPLACE_MODE_UNION);
++
++ ProgressData p;
++ vector<const FilterStreamData*> streamIn,streamOut;
++ streamIn.push_back(d);
++ for(unsigned int opId=0;opId<opVec.size();opId++)
++ {
++ s=TRANS(REPLACE_ALGORITHMS[opVec[opId]]);
++ TEST(f->setProperty(KEY_REPLACE_ALGORITHM,s,needUp),"Set prop");
++
++ //Do the refresh
++ TEST(!f->refresh(streamIn,streamOut,p),"refresh OK");
++
++ TEST(streamOut.size() == 1,"stream count");
++ TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
++ TEST(streamOut[0]->getNumBasicObjects() == NIONS,"Number objects");
++
++ //we should have taken the mass-to-charge from the file
++ const IonStreamData *outIons = (const IonStreamData*)streamOut[0];
++ for(unsigned int ui=0;ui<NIONS; ui++)
++ {
++ ASSERT(outIons->data[ui].getMassToCharge() == 1);
++ }
++ delete streamOut[0];
++ streamOut.clear();
++ }
++ delete f;
++ delete d;
++
++ wxRemoveFile(ionFile);
++
++
++ return true;
++}
++
++bool replaceSubtractTest()
++{
++ std::string ionFile=createTmpFilename(NULL,".pos");
++
++ vector<IonHit> ions;
++ const unsigned int NIONS=10;
++ const unsigned int DIFF_COUNT=5;
++ for(unsigned int ui=0;ui<NIONS;ui++)
++ {
++ IonHit h;
++ h = IonHit(Point3D(ui,ui,ui),1);
++
++ //make some ions different to the (x,x,x) pattern
++ if(ui < DIFF_COUNT)
++ {
++ h.setPos(h.getPos() - Point3D(0,0,100));
++ ions.push_back(h);
++ }
++ else
++ ions.push_back(h);
++ }
++
++ vector<IonHit> tmpI;
++ for(unsigned int ui=0;ui<NIONS;ui++)
++ {
++ if(ions[ui][2] < 0 )
++ {
++ tmpI.push_back(ions[ui]);
++ tmpI.back().setMassToCharge(2);
++ }
++ }
++
++ IonHit::makePos(tmpI,ionFile.c_str());
++ tmpI.clear();
++
++ IonStreamData *d = new IonStreamData;
++ d->data.swap(ions);
++
++ //Create a spatial analysis filter
++ SpatialAnalysisFilter *f=new SpatialAnalysisFilter;
++ f->setCaching(false);
++
++ //Set it to do a subtraction calculation
++ bool needUp;
++ string s;
++ s=TRANS(SPATIAL_ALGORITHMS[ALGORITHM_REPLACE]);
++ TEST(f->setProperty(KEY_ALGORITHM,s,needUp),"Set prop");
++ TEST(f->setProperty(KEY_REPLACE_FILE,ionFile,needUp),"Set prop");
++ s=TRANS(REPLACE_ALGORITHMS[REPLACE_MODE_SUBTRACT]);
++ TEST(f->setProperty(KEY_REPLACE_ALGORITHM,s,needUp),"Set prop");
++
++ //Do the refresh
++ ProgressData p;
++ vector<const FilterStreamData*> streamIn,streamOut;
++ streamIn.push_back(d);
++ TEST(!f->refresh(streamIn,streamOut,p),"refresh OK");
++ delete f;
++ delete d;
++ streamIn.clear();
++
++ TEST(streamOut.size() == 1,"stream count");
++ TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
++ TEST(streamOut[0]->getNumBasicObjects() == DIFF_COUNT,"Number objects");
++
++ //we should have taken the mass-to-charge from the original data,
++ // not the file
++ const IonStreamData *outIons = (const IonStreamData*)streamOut[0];
++ for(unsigned int ui=0;ui<outIons->getNumBasicObjects(); ui++)
++ {
++ ASSERT(outIons->data[ui].getMassToCharge() == 1);
++ ASSERT(outIons->data[ui].getPos()[2] >= 0);
++ }
++
++ wxRemoveFile(ionFile);
++
++ delete streamOut[0];
++
++ return true;
++}
++
++bool replaceUnionTest()
++{
++ std::string ionFile=createTmpFilename(NULL,".pos");
++
++ //"B" dataset
++ vector<IonHit> ions;
++ ions.push_back(IonHit(Point3D(0,0,0),1));
++ ions.push_back(IonHit(Point3D(1,0,1),1));
++ ions.push_back(IonHit(Point3D(0,1,1),1));
++
++ IonHit::makePos(ions,ionFile.c_str());
++ ions.clear();
++
++ //"A" dataset
++ ions.push_back(IonHit(Point3D(0,0,0),2));
++ ions.push_back(IonHit(Point3D(1,0,-1),2));
++ ions.push_back(IonHit(Point3D(0,1,-1),2));
++
++
++ IonStreamData *d = new IonStreamData;
++ d->data.swap(ions);
++
++ //Create a spatial analysis filter
++ SpatialAnalysisFilter *f=new SpatialAnalysisFilter;
++ f->setCaching(false);
+
+ //Set it to do a union calculation
+ bool needUp;
+@@ -4644,13 +4878,11 @@
+ s=TRANS(SPATIAL_ALGORITHMS[ALGORITHM_REPLACE]);
+ TEST(f->setProperty(KEY_ALGORITHM,s,needUp),"Set prop");
+ TEST(f->setProperty(KEY_REPLACE_FILE,ionFile,needUp),"Set prop");
+- s=TRANS(REPLACE_ALGORITHMS[REPLACE_MODE_INTERSECT]);
++ s=TRANS(REPLACE_ALGORITHMS[REPLACE_MODE_UNION]);
+ TEST(f->setProperty(KEY_REPLACE_ALGORITHM,s,needUp),"Set prop");
+-
+ s="1";
+ TEST(f->setProperty(KEY_REPLACE_VALUE,s,needUp),"Set prop");
+
+-
+ //Do the refresh
+ ProgressData p;
+ vector<const FilterStreamData*> streamIn,streamOut;
+@@ -4662,14 +4894,16 @@
+
+ TEST(streamOut.size() == 1,"stream count");
+ TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
+- TEST(streamOut[0]->getNumBasicObjects() == NIONS,"Number objects");
+-
+- //we should have taken the mass-to-charge from the file
++ TEST(streamOut[0]->getNumBasicObjects() == 5,"Number objects");
++
++ //There should be
+ const IonStreamData *outIons = (const IonStreamData*)streamOut[0];
+- for(unsigned int ui=0;ui<NIONS; ui++)
++ float sumV=0;
++ for(unsigned int ui=0;ui<outIons->getNumBasicObjects(); ui++)
+ {
+- ASSERT(outIons->data[ui].getMassToCharge() == 1);
++ sumV+=outIons->data[ui].getMassToCharge();
+ }
++ TEST( EQ_TOL(sumV,7.0f),"mass-to-charge check");
+
+ wxRemoveFile(ionFile);
+
+@@ -4678,7 +4912,6 @@
+ return true;
+ }
+
+-
+ //--- Local concentration tests --
+ const IonStreamData *createLCIonStream()
+ {
+diff -r d478204af715 -r effd078610a7 src/backend/filters/spectrumPlot.cpp
+--- a/src/backend/filters/spectrumPlot.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/spectrumPlot.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -517,6 +517,8 @@
+
+ getOut.push_back(d);
+
++ progress.filterProgress=100;
++
+ return 0;
+ }
+
+diff -r d478204af715 -r effd078610a7 src/backend/filters/transform.cpp
+--- a/src/backend/filters/transform.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/filters/transform.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -998,8 +998,10 @@
+ break;
+ }
+
++ }
+ }
+- }
++
++ progress.filterProgress=100;
+ }
+ else
+ {
+@@ -1526,6 +1528,11 @@
+ case KEY_CROP_MINIMUM:
+ {
+ ASSERT(scalarParams.size() ==2);
++ float tmp;
++ if(stream_cast(tmp,value) || tmp >=scalarParams[1])
++ return false;
++
++
+ if(!applyPropertyNow(scalarParams[0],value,needUpdate))
+ return false;
+ break;
+@@ -1533,6 +1540,9 @@
+ case KEY_CROP_MAXIMUM:
+ {
+ ASSERT(scalarParams.size() ==2);
++ float tmp;
++ if(stream_cast(tmp,value) || tmp <=scalarParams[0])
++ return false;
+ if(!applyPropertyNow(scalarParams[1],value,needUpdate))
+ return false;
+ break;
+diff -r d478204af715 -r effd078610a7 src/backend/plot.cpp
+--- a/src/backend/plot.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/plot.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -29,7 +29,7 @@
+ NTRANS("Moving avg.")
+ };
+
+-const char *plotTypeStrings[]= {
++const char *traceStyleStrings[]= {
+ NTRANS("Lines"),
+ NTRANS("Bars"),
+ NTRANS("Steps"),
+@@ -119,15 +119,15 @@
+ string plotString(unsigned int plotMode)
+ {
+ ASSERT(plotMode< PLOT_TYPE_ENUM_END);
+- return TRANS(plotTypeStrings[plotMode]);
++ return TRANS(traceStyleStrings[plotMode]);
+ }
+
+ unsigned int plotID(const std::string &plotString)
+ {
+- COMPILE_ASSERT(THREEDEP_ARRAYSIZE(plotTypeStrings) == PLOT_TYPE_ENUM_END);
++ COMPILE_ASSERT(THREEDEP_ARRAYSIZE(traceStyleStrings) == PLOT_TYPE_ENUM_END);
+ for(unsigned int ui=0;ui<PLOT_TYPE_ENUM_END; ui++)
+ {
+- if(plotString==TRANS(plotTypeStrings[ui]))
++ if(plotString==TRANS(traceStyleStrings[ui]))
+ return ui;
+ }
+
+@@ -298,7 +298,7 @@
+
+ PlotWrapper::PlotWrapper()
+ {
+- //COMPILE_ASSERT(THREEDEP_ARRAYSIZE(plotTypeStrings) == PLOT_TYPE_ENUM_END);
++ //COMPILE_ASSERT(THREEDEP_ARRAYSIZE(traceStyleStrings) == PLOT_TYPE_ENUM_END);
+
+ applyUserBounds=false;
+ plotChanged=true;
+@@ -684,6 +684,12 @@
+ return visibleMode;
+ }
+
++unsigned int PlotWrapper::getPlotMode(unsigned int plotId) const
++{
++ ASSERT(plotId < plottingData.size());
++ return plottingData[plotId]->getPlotMode();
++}
++
+ void PlotWrapper::getVisibleIDs(vector<unsigned int> &visiblePlotIDs ) const
+ {
+
+@@ -791,7 +797,7 @@
+ if(!plottingData[ui]->visible)
+ continue;
+
+- if(plottingData[ui]->getType()!= PLOT_MODE_1D)
++ if(plottingData[ui]->getMode()!= PLOT_MODE_1D)
+ continue;
+
+ if(((Plot1D*)plottingData[ui])->wantLogPlot())
+@@ -809,7 +815,7 @@
+ float minYVal=0.1;
+ for(size_t ui=0;ui<plottingData.size();ui++)
+ {
+- if(!plottingData[ui]->visible || plottingData[ui]->getType() !=PLOT_MODE_1D)
++ if(!plottingData[ui]->visible || plottingData[ui]->getMode() !=PLOT_MODE_1D)
+ continue;
+
+ float tmp ;
+@@ -929,7 +935,7 @@
+ Plot2DFunc *curPlot;
+ curPlot=(Plot2DFunc*)plottingData[ui];
+
+- if(curPlot->getType() == PLOT_2D_DENS)
++ if(curPlot->getMode() == PLOT_2D_DENS)
+ {
+ wantColourbar=true;
+ }
+@@ -1047,11 +1053,6 @@
+ plottingData[plotIDHandler.getPos(plotId)]->regionGroup.getRegion(regionId,region);
+ }
+
+-unsigned int PlotWrapper::plotType(unsigned int plotId) const
+-{
+- return plottingData[plotIDHandler.getPos(plotId)]->getPlotMode();
+-}
+-
+
+ void PlotWrapper::moveRegion(unsigned int plotID, unsigned int regionId, bool regionSelfUpdate,
+ unsigned int movementType, float newX, float newY) const
+@@ -1135,7 +1136,7 @@
+
+ void PlotBase::copyBase(PlotBase *target) const
+ {
+- target->plotType=plotType;
++ target->traceStyle=traceStyle;
+ target->minX=minX;
+ target->maxX=maxX;
+ target->minY=minY;
+@@ -1157,12 +1158,12 @@
+
+ unsigned int PlotBase::getType() const
+ {
+- return plotType;
++ return traceStyle;
+ }
+
+ unsigned int PlotBase::getMode() const
+ {
+- switch(plotType)
++ switch(traceStyle)
+ {
+ case PLOT_LINE_LINES:
+ case PLOT_LINE_BARS:
+@@ -1181,7 +1182,7 @@
+ Plot1D::Plot1D()
+ {
+ //Set the default plot properties
+- plotType=PLOT_LINE_LINES;
++ traceStyle=PLOT_LINE_LINES;
+ plotMode=PLOT_MODE_1D;
+ xLabel="";
+ yLabel="";
+@@ -1489,7 +1490,7 @@
+
+
+ //Plot the appropriate form
+- switch(plotMode)
++ switch(traceStyle)
+ {
+ case PLOT_LINE_LINES:
+ //Unfortunately, when using line plots, mathgl moves the data points to the plot boundary,
+@@ -1632,7 +1633,7 @@
+ Plot2DFunc::Plot2DFunc()
+ {
+ plotMode = PLOT_MODE_2D;
+- plotType=PLOT_2D_DENS;
++ traceStyle=PLOT_2D_DENS;
+ }
+
+ void Plot2DFunc::setData(const Array2D<float> &a,
+@@ -1705,7 +1706,8 @@
+
+ Plot2DScatter::Plot2DScatter()
+ {
+- plotType=PLOT_2D_SCATTER;
++ plotMode=PLOT_2D_SCATTER;
++ traceStyle=PLOT_LINE_POINTS;
+ scatterIntensityLog=false;
+ }
+
+diff -r d478204af715 -r effd078610a7 src/backend/plot.h
+--- a/src/backend/plot.h Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/plot.h Tue Jun 21 12:45:20 2016 +0100
+@@ -217,7 +217,7 @@
+ class PlotBase
+ {
+ protected:
+- //!Sub type of plot (eg lines, bars for 1D)
++ //!Type of plot
+ unsigned int plotMode;
+ //!xaxis label
+ std::string xLabel;
+@@ -229,8 +229,9 @@
+ //plot colour (for single coloured plots)
+ float r,g,b;
+
+- //The type of plot (ie what class is it?)
+- unsigned int plotType;
++ //The sub-style of the plot trace (eg lines, points, bars, etc)
++ // FIXME: This is badly named, change to traceStyle, or dataStyle, or something
++ unsigned int traceStyle;
+
+ void copyBase(PlotBase *target) const;
+
+@@ -297,8 +298,12 @@
+ void setStrings(const std::string &x,
+ const std::string &y,const std::string &t);
+
++ //Set the colour of the plot trace
+ void setColour(float rNew, float gNew, float bNew);
+
++ //set the visual style for the trace (dots, lines, etc)
++ void setTraceStyle(unsigned int newStyle) { traceStyle=newStyle;}
++
+ std::string getXLabel() const { return xLabel;}
+ std::string getTitle() const { return title;}
+ std::string getYLabel() const { return yLabel;}
+@@ -309,6 +314,7 @@
+ void setPlotMode(unsigned int newMode) { plotMode= newMode;}
+
+
++ //get the colour of the trace
+ void getColour(float &r, float &g, float &b) const ;
+
+ #ifdef DEBUG
+@@ -613,7 +619,7 @@
+
+
+ //!obtain the type of a plot, given the plot's uniqueID
+- unsigned int plotType(unsigned int plotId) const;
++ unsigned int getPlotMode(unsigned int plotId) const;
+
+ //Retrieve the types of visible plots
+ unsigned int getVisibleMode() const;
+diff -r d478204af715 -r effd078610a7 src/backend/viscontrol.cpp
+--- a/src/backend/viscontrol.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/backend/viscontrol.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -249,7 +249,7 @@
+ plotData->yLabel,plotData->dataLabel);
+
+ //set the appearance of the plot
+- //plotNew->setTraceStyle(plotStyle);
++ plotNew->setTraceStyle(plotData->plotStyle);
+ plotNew->setColour(plotData->r,plotData->g,plotData->b);
+
+
+@@ -275,7 +275,7 @@
+ unsigned int plotID;
+
+ PlotBase *plotNew;
+- switch(plotData->plotType)
++ switch(plotData->plotStyle)
+ {
+ case PLOT_2D_DENS:
+ {
+diff -r d478204af715 -r effd078610a7 src/common/basics.cpp
+--- a/src/common/basics.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/common/basics.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -1347,7 +1347,8 @@
+ while(CFile.good() && !CFile.eof() && atHeader)
+ {
+ //Grab a line from the file
+- CFile.getline(inBuffer,BUFFER_SIZE);
++ if(!CFile.getline(inBuffer,BUFFER_SIZE))
++ break;
+
+ if(!CFile.good())
+ return ERR_FILE_FORMAT;
+@@ -1457,10 +1458,8 @@
+
+ }
+ //Grab a line from the file
+- CFile.getline(inBuffer,BUFFER_SIZE);
+-
+- if(!CFile.good() && !CFile.eof())
+- return ERR_FILE_FORMAT;
++ if(!CFile.getline(inBuffer,BUFFER_SIZE))
++ break;
+ }
+
+ return 0;
+diff -r d478204af715 -r effd078610a7 src/gui/mainFrame.cpp
+--- a/src/gui/mainFrame.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/gui/mainFrame.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -1391,7 +1391,7 @@
+ updateWxTreeCtrl(treeFilters);
+
+ if(!noUpdate)
+- return doSceneUpdate(true);
++ doSceneUpdate(true);
+
+ return true;
+ }
+@@ -3834,7 +3834,7 @@
+
+ }
+
+-bool MainWindowFrame::doSceneUpdate(bool ensureVisible)
++void MainWindowFrame::doSceneUpdate(bool ensureVisible)
+ {
+ //Update scene
+ ASSERT(!currentlyUpdatingScene);
+@@ -3864,6 +3864,11 @@
+ ensureResultVisible=ensureVisible;
+
+ ASSERT(!refreshControl);
++
++ //Hack to prevent crash on double-refresh
++ if(refreshControl)
++ return;
++
+ refreshControl = new RefreshController(visControl.state.treeState);
+ refreshThread=new RefreshThread(this,refreshControl);
+ progressTimer->Start(PROGRESS_TIMER_DELAY);
+@@ -3871,7 +3876,8 @@
+ refreshThread->Create();
+ refreshThread->Run();
+
+- return true;
++ cerr << "Updating scene complete"<< endl;
++ return;
+ }
+
+ void MainWindowFrame::updateWxTreeCtrl( wxTreeCtrl *t, const Filter *f)
+@@ -3971,6 +3977,11 @@
+ ASSERT(!visControl.state.treeState.isRefreshing());
+ progressTimer->Stop();
+
++ //Hack to prevent crash on re-entry during refresh. Should never trigger.
++ if(!refreshControl)
++ return;
++
++
+ vector<std::pair<const Filter*, std::string> > consoleMessages;
+ consoleMessages=refreshControl->getConsoleMessages();
+
+diff -r d478204af715 -r effd078610a7 src/gui/mainFrame.h
+--- a/src/gui/mainFrame.h Mon Jun 27 11:07:17 2016 +0100
++++ b/src/gui/mainFrame.h Tue Jun 21 12:45:20 2016 +0100
+@@ -124,7 +124,7 @@
+ //!Update the progress information in the status bar
+ void updateProgressStatus();
+ //!Perform an update to the 3D Scene. Returns false if refresh failed
+- bool doSceneUpdate(bool ensureResultVisible=false);
++ void doSceneUpdate(bool ensureResultVisible=false);
+
+ //!Complete the scene update. Returns false if failed
+ void finishSceneUpdate(unsigned int errCode);
+diff -r d478204af715 -r effd078610a7 src/gui/mathglPane.cpp
+--- a/src/gui/mathglPane.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/gui/mathglPane.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -627,7 +627,7 @@
+ thePlot->getRegion(plotId,regionId,r);
+
+ //TODO: Implement a more generic region handler?
+- ASSERT(thePlot->plotType(plotId) == PLOT_MODE_1D);
++ ASSERT(thePlot->getPlotMode(plotId) == PLOT_MODE_1D);
+
+ float mglStartX,mglStartY;
+ toPlotCoords(draggingStart.x, draggingStart.y,mglStartX,mglStartY);
+@@ -1471,7 +1471,7 @@
+ return;
+
+
+- ASSERT(thePlot->plotType(startMousePlot) == PLOT_MODE_1D);
++ ASSERT(thePlot->getPlotMode(startMousePlot) == PLOT_MODE_1D);
+
+ //See where extending the region is allowed up to.
+ thePlot->findRegionLimit(startMousePlot,startMouseRegion,
+@@ -1550,7 +1550,7 @@
+ {
+ //This needs to be extended to support more
+ //plot types.
+- ASSERT(thePlot->plotType(startMousePlot) == PLOT_MODE_1D);
++ ASSERT(thePlot->getPlotMode(startMousePlot) == PLOT_MODE_1D);
+
+ //Draw "ghost" limits markers for move,
+ //these appear as moving vertical bars to outline
+diff -r d478204af715 -r effd078610a7 src/wx/wxcomponents.cpp
+--- a/src/wx/wxcomponents.cpp Mon Jun 27 11:07:17 2016 +0100
++++ b/src/wx/wxcomponents.cpp Tue Jun 21 12:45:20 2016 +0100
+@@ -188,14 +188,14 @@
+
+ void CopyGrid::saveData()
+ {
+- wxFileDialog *wxF = new wxFileDialog(this,TRANS("Save Data..."), wxT(""),
++ wxFileDialog wxF(this,TRANS("Save Data..."), wxT(""),
+ wxT(""),TRANS("Text File (*.txt)|*.txt|All Files (*)|*"),wxFD_SAVE);
+
+- if( (wxF->ShowModal() == wxID_CANCEL))
++ if( (wxF.ShowModal() == wxID_CANCEL))
+ return;
+
+
+- std::string dataFile = stlStr(wxF->GetPath());
++ std::string dataFile = stlStr(wxF.GetPath());
+ ofstream f(dataFile.c_str());
+
+ if(!f)
diff --git a/debian/patches/lowercase-textdomain.patch b/debian/patches/lowercase-textdomain.patch
index 2c24b61..10fdaf0 100644
--- a/debian/patches/lowercase-textdomain.patch
+++ b/debian/patches/lowercase-textdomain.patch
@@ -1,11 +1,11 @@
Description: Debian uses different text domain for the lang files
Forwarded: not-needed
Author: D Haley <mycae - gmx - com>
-Index: 3depict-0.0.18/src/3Depict.cpp
+Index: 3depict-0.0.19/src/3Depict.cpp
===================================================================
---- 3depict-0.0.18.orig/src/3Depict.cpp 2015-05-02 00:01:30.047635141 +0200
-+++ 3depict-0.0.18/src/3Depict.cpp 2015-05-02 00:01:30.043635141 +0200
-@@ -157,7 +157,7 @@
+--- 3depict-0.0.19.orig/src/3Depict.cpp 2016-08-04 00:12:38.260085712 +0200
++++ 3depict-0.0.19/src/3Depict.cpp 2016-08-04 00:12:38.256085765 +0200
+@@ -179,7 +179,7 @@
else
{
//Set the gettext language
@@ -14,7 +14,7 @@ Index: 3depict-0.0.18/src/3Depict.cpp
setlocale (LC_ALL, "");
#ifdef __WXMAC__
bindtextdomain( PROGRAM_NAME, paths->GetResourcesDir().mb_str(wxConvUTF8) );
-@@ -189,8 +189,8 @@
+@@ -211,8 +211,8 @@
break;
}
#else
diff --git a/debian/patches/series b/debian/patches/series
index f1e4846..e898cbe 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,4 +1,4 @@
+diff_0.0.19_to_effd078610a7
debian-desktop-naming.patch
lowercase-textdomain.patch
desktop-category.patch
-diff-upstream-0.0.18_to_212d6e1e6b14
--
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