[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