[3depict] 01/02: * Add patch from upstream 0.0.18 to upstream hg repo 212d6e1e6b14
D Haley
mycae-guest at moszumanska.debian.org
Mon Feb 8 02:04:09 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 4559d9aad338b5befa04627f635c771c5588ef46
Author: D Haley <mycae at gmx.com>
Date: Mon Feb 8 02:51:47 2016 +0100
* Add patch from upstream 0.0.18 to upstream hg repo 212d6e1e6b14
---
.../patches/diff-upstream-0.0.18_to_212d6e1e6b14 | 1490 ++++++++++++++++++++
debian/patches/series | 1 +
2 files changed, 1491 insertions(+)
diff --git a/debian/patches/diff-upstream-0.0.18_to_212d6e1e6b14 b/debian/patches/diff-upstream-0.0.18_to_212d6e1e6b14
new file mode 100644
index 0000000..3053a6f
--- /dev/null
+++ b/debian/patches/diff-upstream-0.0.18_to_212d6e1e6b14
@@ -0,0 +1,1490 @@
+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/series b/debian/patches/series
index 2b9da52..f1e4846 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
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