/*
This work is part of the Core Imaging Library developed by
Visual Analytics and Imaging System Group of the Science Technology
Facilities Council, STFC

Copyright 2003 Hamish Carr
Copyright 2017 Srikanth Nagella, Edoardo Pasca

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*!	IsoSurface II
//	Hamish Carr, 1999

//	HeightField.h:		class representing the height field
//	Palatino-12; 5 n-spaces/tab
**/
#ifndef HEIGHTFIELD_H
#define HEIGHTFIELD_H 1

#define HEIGHTFIELD_DEBUG_PRINT 1

#include <fstream>														//!	include file streams
#include "Component.h"													//!	include the Component class for the Join Tree & Split Tree
#include "Superarc.h"													//!	include the Superarc class for the contour tree
#include "Supernode.h"													//!	include the Supernode class for the contour tree
#include "Array3D.h"													//!	and the template class for 3-D arrays
#include <iostream>
using namespace std;
#if defined(_WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
#include <windows.h>
#include <cmath>
#else
#include <sys/time.h>
#include <cmath>
#endif


#include <vector>
#include <boost/tuple/tuple.hpp>


#define TIMING_BUFFER_SIZE 2048576L 						//!	declare a large memory buffer into which we can dump
extern char *timingBuffer, *timingStart;					//!	some timing structures
extern struct timeval startTime, lastTime, thisTime, thatTime;

void printTimingBuffer();									//!	and a function to call at exit to print the buffer

void flushTimingBuffer();									//!	this routine flushes the buffer to standard out

#define PRIORITY_HEIGHT 1
#define PRIORITY_VOLUME 2
#define PRIORITY_HYPERVOLUME 3
#define PRIORITY_APPROX_HYPERVOLUME 4


extern int pathLength, triangleCount;						//!	these are for use in computing actual path lengths, &c.
/*!
	we start by defining a function for use when comparing heights:  this is passed to qsort(), and used any time we need to compare heights
	thus, it includes the symbolic perturbation scheme
*/

/*!	compareHeightVoid():	compares two heights in an array */
int compareHeightVoid(const void *e1, const void *e2);					//!	comparison function for passing to qsort()
/*!	compareHeight():		compares two heights in an array */
int compareHeight(const float *d1, const float *d2);					//!	comparison function for all other purposes

/*!
 * 	this class is largely intended to encapsulate the height field, and the algorithms to compute the contour tree, and render the result
 */
const long maxNeighbours = 24;											//!	actually, it's less than this, but this covers all versions so far

const long noContourSelected = -1;										//!	constant for empty selection

const long nDotLayout = 256;											//!	no. of vertices to use for dot layout

#define N_SURFACE_COLOURS 9
//extern GLfloat surface_colour[N_SURFACE_COLOURS][4];					//!	colours for individual contours
//extern GLfloat select_colour[4];										//!	colour for selected component
//extern GLfloat basic_colour[4];											//!	colour for most components
	
class HeightField														//!	our class for a height field
	{
	public:
	bool differentColouredContours;										//!	flag for whether all the contours should be same colour

	private:
	//	the actual data array exists for the life of the height field
	long xDim, yDim, zDim;												//!	size of the data array
	long nVertices;														//!	total # of vertices
	Array3D<float> height;												//!	3-D array holding the height values
	float maxHeight, minHeight;											//!	maximum & minimum height value

	/*!
	 * these flags are principally used for rendering, BUT are also used during the contour-tree algorithm
	 * to mark vertices that have already been assigned to individual superarcs
	*/
	Array3D<unsigned long> visitFlags;									//!	1-D array for flags used in contour-following rendering

	/*!	the following are working storage, shared between several routines, and
	 * can be disposed of when the contour tree has been found:
	 */
	float **heightSort;													//!	1-D array for sorting the heights
	Array3D<Component *> joinComponent;								    //!	3-D array of pointers into Union-Find (also stores join tree, implicitly)
	Array3D<Component *> splitComponent;								//!	ditto for the split tree
	Array3D<long> nodeLookup;											//!	temporary array to set supernodes with
	Array3D<float *> joinArcs, splitArcs;								//!	used to keep track of arcs in join (split) tree: low level

	long neighbourQueue[maxNeighbours][3];								//!	queue for finding neighbours
	long nNeighbours;													//!	logical size of the queue
	float **leafQueue;													//!	leaf queue for merge step
	long leafQSize;														//!	current size of leaf queue
	long vertex;														//!	index used by CreateJoinTree() & CreateSplitTree()
	long *supernodeQueue;												//!	queue used by CollapseEpsilonEdges()
	bool *wasChecked;													//!	flag array for CollapseEpsilonEdges()
	long supernodeQueueSize;											//!	logical size of queue

	float minus_infinity, plus_infinity;								//!	these are to simplify processing of join tree and split tree
	Component *joinRoot, *splitRoot;									//!	pointers to bottom (top) components of join (split) tree
	
	/*!	storage for the contour tree once computed */
	Superarc *superarcs;												//!	array holding all the edges of the contour tree
	Supernode *supernodes;												//!	and one holding all the nodes
	long nSuperarcs;													//!	number of superarcs in the final tree
	long nSupernodes;													//!	number of supernodes in the final tree
	long nValidArcs, nActiveArcs, nSelectedArcs, nRestorableArcs;		//!	number of arcs in each category
	long nValidNodes;													//!	number of valid nodes
	long *valid, *active, *selected, *restorable, *validNodes;			//!	arrays holding various classes of objects

	long nJoinSupernodes, nSplitSupernodes;								//!	running count of nodes in join & split trees
	long nextSuperarc, savedNextSuperarc;								//!	next available superarc in contour tree
	long nextSupernode;													//!	next available supernode ID

	/*!	these variables allow us to do flexible isosurfaces */
	public:
	long selectionRoot;													//!	ID of component being dragged
	float currentSelectionValue;										//!	current value of drag
	private:
	float selectionRootValue;											//!	value at which drag started
	long restorableSelectionRoot;										//!	ID of component being dragged
	float restorableCurrentValue;										//!	current value of drag
	float restorableRootValue;											//!	value at which drag started
	long restorableOrigin;												//!	origin of "restorables": must be one of:
	static const long restorableSelection = 0;							//!	selection, or
	static const long restorableActive = 1;								//!	complement of selection

	/*!	and some dealing with tree collapse */
	private:
	long *collapseRecord;												//!	record of which vertices were collapsed
	long nNonEpsilonArcs;												//!	the number of non-epsilon arcs
	public:
	long *collapseBounds;												//!	here's the array to store them
	int collapsePriority;
	/*!	used by log collapse pane */
	float logTreeSize, logPriorityBound;								//!	logs of the current tree size & bound
	long *nodeColour, *arcColour;										//!	colours assigned to arc, node respectively

	private:
	long *pathLengths;													//!	length of path used to construct the contour
	long *nContourTriangles;											//!	size of particular surface (# of triangles)
	float *extractionTime;												//!	time to extract a particular surface
	long maxPathLength;													//!	the longest path length found
	float avgPathLength;												//!	average path length
	long totalTriangles;												//!	total triangles displayed
	float totalExtractionTime;											//!	sum of extraction times for surfaces
	float frameRate;													//!	make frame rate available for display
	struct timeval lastFrameTime, thisFrameTime;						//!	for computing frame time & rate
	
	int baseDisplayListID;												//!	base ID for set of display lists

	/*!	these are members intended for use in measuring performance */
	public:
	long recursionDepth, maxRecursionDepth;								//!	for measuring depth of recursion
	long nCellsVisited, nTrianglesGenerated;							//!	number of cells visited & triangles generated
	long nCellsIntersected;
	long nSimplicesToDraw, nSimplicesToUnFlag;							//!	used only when debugging - how many we've drawn into
	long constructionState;												//!	the state of construction
	long nSteps;														//!	number of steps to perform before returning (for debug)
	int sampleSize;														//!	size (in bytes) of individual samples
	
	/*!	this one is a hack for computing correct Riemann sums */
	float sampleSum;



	HeightField(int argc, char **argv);									//!	constructor: constructs the object

	~HeightField();														//!	destructor: destroys the object, and deallocates dynamically allocated storage (including height array)
	HeightField();														//! empty constructor

	/*!	loads a file from ASCII text */
	void LoadFromASCII(char *fileName);
	void LoadFromRaw(FILE *inFile);

	/*!	CreateJoinTree() */
	void CreateJoinTree();
	/*!	does the down sweep to create the join tree
		may be called repeatedly, for partial processing
		returns TRUE iff the join tree has now been computed */

	//	CreateSplitTree()
	void CreateSplitTree();
	/*!	does the up sweep to create the split tree
	*	may be called repeatedly, for partial processing
	*	returns TRUE iff the split tree has now been computed */

	//	AugmentTrees()
	void AugmentTrees();												//!	augments join and split trees with nodes of other

	//	CombineTrees()
	void CombineTrees();												//!	combines join and split trees to produce contour tree
																		//!	returns TRUE only when the contour tree has been computed

private:		//	used internally
	//	QueueNeighbour()
	void QueueNeighbour(long x, long y, long z);						//!	queues up the given neighbour, if it is in the field

	//	QueueJoinNeighbours()
	void QueueJoinNeighbours(long x, long y, long z);					//!	queues up all neighbours in the join sweep

	//	QueueJoinNeighbours()
	void QueueSplitNeighbours(long x, long y, long z);					//!	queues up all neighbours in the split sweep

	long AddSuperarc(float *hiEnd, float *loEnd, float *seedHiFrom, float *seedHiTo, float *seedLoFrom, float *seedLoTo);
																		//!	adds a superarc to the contour tree
	long AddSuperarc(long topID, long bottomID, float *seedHiFrom, float *seedHiTo, float *seedLoFrom, float *seedLoTo);
																		//!	adds a superarc to the contour tree
	long GetSupernode(float *theVertex);								//!	get supernode for a vertex, creating it if necessary
	void AddUpArc(long theNode, long theArc);							//!	add an up arc at a given node
	void AddDownArc(long theNode, long theArc);							//!	add an down arc at a given node
	//	routine to find seeds for edges that do not otherwise have them	
	float *FindDescendingNeighbour(float *theVertex);					//!	find a descending neighbour. Any descending neighbour
	bool RemoveEdgeIfEpsilonHeight(long theArc);						//!	checks arc, removes it if necessary, returns true if it did

public:	//	public drawing routines
	//	drawing routines
	void MarchingCubes(float ht);										//!	draws level set using marching cubes
	
	//	These routines implement the flexible isosurface interface
	void SetIsosurface(float ht);										//!	sets the selected components to an isosurface
	void SetLocal(float ht);											//!	sets the selected components to a local set

	void SetComponentHeight(int component, float height);				//!	sets the seed value for a specific component
	void SelectComponent(int newSelectionRoot);							//!	initializes the selection arrays, using existing value
	void SelectComponent(int newSelectionRoot, float selectionValue);	//!	initializes the selection arrays
	void UpdateSelection(float height);									//!	updates the selection arrays during a drag
	void ProportionalUpdateSelection(float height);						//!	version of update selection constrained to edge
	void CommitSelection();												//!	commits the selection

	void ComputeStatistics();											//!	computes statistics on average path length, &c.

	void DeleteSelection();												//!	deactivates the selected components
	void DeleteComplement();											//!	deactivates the complement of the selection
	void RestoreDeleted();												//!	restores the last saved set
	
	bool ArcSelected(int arcIndex);										//!	accessor for selected flag
	int PickNode(float x, float y);										//!	picks a node: returns -1 if it fails
	void UpdateNodeXPosn(int node, float x);							//!	updates a node's x position
	int PickArc(float x, float y);										//!	picks an arc: returns -1 if it fails
	long GetSuperarcColour(long theArc);								//!	accessor to retrieve arc colour
	void SetSuperarcColour(long theArc, long theColour);				//!	accessor to set arc colour


	void FlexibleContours(bool useDisplayLists = false, bool pickColours = false);	//!	renders flexible contours, using contour-following
	void RenderContour(long arc, bool useDisplayLists, bool pickColours);			//!	renders an individual contour

	void DrawEdges();													//!	draws the edges of the voxels
	void DrawContourTree();												//!	draws the contour tree
	void DrawPlanarContourTree(bool useColouredTree);					//!	draws a planar version of the contour tree
	void PlotLogCollapse();												//!	plots the log collapse curve
	void FollowHierarchicalPathSeed(int sArc, float ht);				//!	follows hier. path seed to generate contour
	void SetNodeXPositions();											//!	sets the x-positions for the nodes
	void UseDotToSetPositions(int nArcs);								//!	sets the x-positions for nodes by calling dot
	void SetInitialColours();											//!	sets the initial colours
	
	//	routines needed for collapsing
	void ResetCollapsePriority(long whichCollapsePriority);				//!	resets the collapse priority & recollapses
	long CollapseVertex(long whichSupernode);							//!	collapses a vertex: returns the new superarcs ID
	void CollapseToSuperarc(long whichSuperarc);						//!	collapses to a known superarc
	void CollapseEpsilonEdges();										//!	collapses the epsilon-height edges
	void CollapseLeafPruning(int targetSize, long prunedVolumeBound);	//!	leaf-prunes until one of the bounds is reached
	void RemoveArc(long theArc);										//!	routine to remove an arc from the tree
	
	void UpdateFromLogPriorityBound();									//!	updates the size of the tree
	void UpdateFromLogTreeSize();										//!	ditto, but from tree size
	long FindLogBound(float logBound);									//!	given a fixed tree size, finds the corresponding bound
	long FindLogTreeSize(float logSize);								//!	and vice versa
    void UpdateToFixedSize(long targetSize);							//!	ditto, but from tree size
	void SingleCollapse();												//!	collapses a single node after constructing collapse tree
	void SingleUnCollapse();											//!	similarly, uncollapses a single node
	float InitialLogPriorityBound();									//!	utility routine for initializing slider

// *************	
// ** WARNING **
// *************	
//
// This routine assumes that the fromNode's arcs have already had the hiID/loID and hiEnd/loEnd correctly reset to the onto node
//
	void TransferArcLists(int ontoNode, int fromNode);					//!	transfer's arcs from one node to another

	//	housekeeping routines for flexible isosurfaces
	void ClearAllArrays();												//!	clears active[], selected[], restorable[]
	void ClearActive();													//!	clears active list
	void ClearSelection();												//!	clears selected list
	void ClearRestorable();												//!	clears restorable list
	void ClearSuppressed();												//!	resets all suppressed arcs to active
	void ClearBackQueue();												//!	removes all vertices from the back queue
	void AddToActive(long arc, float seedValue);						//!	adds an arc to the active list
	void RemoveFromActive(long arc);									//!	removes arc from the active list
	void AddToValid(long arc);											//!	adds an arc to the valid list
	void RemoveFromValid(long arc);										//!	removes arc from the valid list
	void AddToSelected(long arc);										//!	adds an arc to the selected list
	void AddToRestorable(long arc);										//!	adds an arc to the restorable list
	void RemoveFromRestorable(long arc);								//!	removes arc from the restorable list
	void AddToValidNodes(long node);									//!	adds an node to the valid list
	void RemoveFromValidNodes(long node);								//!	removes node from the valid list

	//	routine to simplify changing metric	
	long Priority(long arc, bool upSweep);								//!	computes priority for a given arc

	//	base-level drawing routines
	void FollowContour(float ht, Superarc &theArc);						//!	given a superarc spanning ht, draws the corresponding contour

	//	routines called by ContourFollowing()
	void FollowSurface(float ht, float *p1, float *p2);					//!	routine to follow surface from seed edge
	void IntersectSurface(float ht, long x, long y, long z, int theEntryFaceEdge);		//!	intersects surface starting at specified cell & edge
	void Visit(long xc, long yc, long zc, long cubeContour);			//!	sets the flag for a particular contour in a cell
	void UnVisit(long xc, long yc, long zc, long cubeContour);			//!	resets the flag for a contour
	bool Visited(long xc, long yc, long zc, long cubeContour);			//!	tests whether flag set for contour
	void UnFlagSurface(float ht, long xc, long yc, long zc, int theEntryFaceEdge);	//!	clean out the flags
	void RenderTriangle(float ht, long x, long y, long z, float *cubeVert, int edge1, int edge2, int edge3);
																		//!	renders the triangle specified by three edges
	void CentralDifferenceNormal(long x, long y, long z, float *normal);		//!	uses c.d. to estimate normal at a vertex of the mesh
	void InterpolateVertex(long x, long y, long z, int edge, float *cubeVert, float ht); //!	interpolates a vertex (with normal) & sends to OpenGL
	void InterpolateVertex(long x, long y, long z, int edge, float * cubeVert, float ht, float * m_vertex);//!	interpolates a vertex (with normal) & sends to OpenGL and keeps a copy of it
																		
	//	accessor functions
	float MaxHeight() { return maxHeight; };							//!	accessor function
	float MinHeight() { return minHeight; };
	long Size();														//!	returns the largest dimension

	long XDim() { return xDim; }										//!	accessors for individual dimensions
	long YDim() { return yDim; }
	long ZDim() { return zDim; }

	//	debug routines
	void PrintPointerIndices(float *vertex);							//!	prints out the pointer indices
	void PrintField();													//!	prints out the contents of the height field
	void PrintParameters();												//!	prints out the dimensions, offset, &c.
	void PrintSortOrder();												//!	prints out the heights in sorted order
	void PrintVisitFlags();												//!	prints out the "visited" flags
	void PrintJoinComponents();											//!	prints out the Union-Find info for the join sweep
	void PrintJoinTree();												//!	prints out the join tree (i.e. join components, with duplicates suppressed)
	void PrintSplitComponents();										//!	prints out the Union-Find info for the split sweep
	void PrintSplitTree();												//!	prints out the split tree (i.e. split components, with duplicates suppressed)
	void PrintContourComponents();										//!	prints out the contour components computed so far
	void PrintContourTree();											//!	prints out the contour tree, once it is fully computed
	void PrintNeighbourQueue();											//!	prints off the queue that identifies the neighbours of a vertex
	void PrintLeafQueue();												//!	prints off the leaf queue
	//	this routine generates a dot file for generating graph layouts
	//	filename is: dot/basefilename_serialNum.dot
	void ContourTreeToDotFile(char *basefilename, int serialNum, bool postscriptOutput = true, bool forceYPosition = false, long highlightEdge = -1);
																		//!	prints out the contour tree, once it is fully computed
	void JoinArcsToDotFile(char *basefilename, int serialNum);			//!	prints the contents of the joinArcs array
	void SplitArcsToDotFile(char *basefilename, int serialNum);			//!	prints the contents of the splitArcs array
	void PrintCollapseRecord();											//!	prints the array storing collapse details

	void CheckJoinTree();												//!	checks join tree for consistency
	void CheckVisitFlags();												//!	checks the "visited" flags
	void CheckSplitTree();												//!	checks split tree for consistency
	void CheckContourTree();											//!	checks contour tree for consistency
	void CheckNodeCounts();												//!	checks consistency of node counts on arcs

	void PrintConstructionState();										//!	print the current construction state

	void DoDotLayout();													//!	perform dot-based layout at user request
	void SaveTreeLayout();												//!	save the contour tree's current layout
	void LoadTreeLayout();												//!	load the contour tree's current layout


	//! added by Edoardo Pasca
	public:
		void loadFieldFromFile(int, char **);
		void doTheJob();
		
		//void SetInputData(Array3D<unsigned char> * imageData, int * dims, int sampleSize);
		template<typename T> void SetInputData(Array3D<T> * imageData, int * dims, int sampleSize) {


			//int* dims = imageData->GetDimensions();
			xDim = dims[0]; yDim = dims[1]; zDim = dims[2];



			// from LoadFromRaw()
			long index;	//	loop index
						
			if (sampleSize < 1) { printf("Sample sizes less than 1 don't make sense.\n"); throw 0; }
			if (sampleSize > 2) { printf("Sample sizes greater than 2 not yet implemented.\n"); throw 0; }

			//	B.	set nVertices
			nVertices = xDim * yDim * zDim;

			//	C.	allocate leafQueue to a default size, and set leafQSize
			leafQueue = NULL;															//!	allocate space on leaf queue
			leafQSize = 0;																//!	set logical size to zero

																						//	D.	allocate height, heightSort, and visitFlags
			heightSort = (float **)malloc(sizeof(float *) * nVertices);					//!	allocate the array
			visitFlags.Construct(xDim, yDim, zDim);										//!	call template function to set up array

																						//	E.	read in the data, setting pointers in heightSort, and finding maxHeight and minHeight in the process
			maxHeight = -HUGE_VAL; minHeight = HUGE_VAL;
			//	allocate memory 
			float *floatData = (float *)malloc(sizeof(float) * nVertices);				//!	allocate the memory for the float representation
			
																		
																						// !I wonder if this is really correct
			//unsigned char *rawData = (unsigned char *)malloc(sizeof(unsigned char) * sampleSize * nVertices);

			T * rawData = (T*)malloc(sizeof(T)*nVertices);

			// fill the structures from Hamish with a loop
			/*int myindex = 0;
			while (myindex < nVertices) {
			rawData[myindex] = imageData->getElementAtIndex(myindex++);
			}*/

			// fill the structures from Hamish with a loop
			for (int z = 0; z < dims[2]; z++)
			{
				for (int y = 0; y < dims[1]; y++)
				{
					for (int x = 0; x < dims[0]; x++)
					{
						//unsigned char* pixel = static_cast<unsigned char*>(imageData->GetScalarPointer(x, y, z));
						long index = z + dims[2] * y + (dims[2] * dims[1]) * x;
						rawData[index] = imageData->getElementAt(x, y, z);										//! assign the data 
					}
				}
			}
			//set up radix sort bins
			long nBins = (sampleSize == 1) ? 256 : 65536L;

			long *firstInBin = new long[nBins];
			for (int i = 0; i < nBins; i++) firstInBin[i] = -1;								//!	initialize to "NONE"
			long *nextInBin = (long *)malloc(nVertices * sizeof(long));					//!	and initialize the "next" array
			for (int i = 0; i < nVertices; i++) nextInBin[i] = -1;

			if (sampleSize == 1)
				for (index = 0; index < nVertices; index++)									//!	walk through the data
				{ // walk through data
					nextInBin[index] = firstInBin[rawData[index]];							//!	push into linked list at front of sorting bin
					firstInBin[rawData[index]] = index;										//!	and reset the front of the bin
					floatData[index] = (float)rawData[index];								//!	copy into the float array
					sampleSum += rawData[index];											//!	add to the running sum
				} // walk through data
			else
			{ // 2-byte data
				unsigned short *rawShort = (unsigned short *)rawData;
				for (index = 0; index < nVertices; index++)									//	walk through the data
				{ // walk through data
					unsigned short newShort = rawShort[index];
#ifdef ENDIAN_SWAP_SHORTS
					newShort = (newShort >> 8) | ((newShort & 0x00FF) << 8);
#endif
					nextInBin[index] = firstInBin[newShort];							//	push into linked list at front of sorting bin
					firstInBin[newShort] = index;									//	and reset the front of the bin
					floatData[index] = (float)newShort;								//	copy into the float array
					sampleSum += newShort;						//	add to the running sum
				} // walk through data
			} // 2-byte data		

			  /**
			  *	we have now loaded up the float array, and need to setup heightSort properly
			  *	our bin sort has now pushed the elements into bins IN REVERSE ORDER, so we have to
			  *	flip again in reading them out
			  **/

			int bin = nBins;															//!	which bin we are reading from
			long nextSample = -1;														//!	which sample comes next
			for (index = nVertices - 1; index >= 0; index--)
			{ // filling in heightSort
				while (nextSample == -1)												//!	this bin is empty
					nextSample = firstInBin[--bin];										//!	grab the first item in the next bin
				heightSort[index] = floatData + nextSample;								//!	generate & store the pointer
				nextSample = nextInBin[nextSample];										//!	grab the next item
			} // filling in heightSort

			height.Construct(xDim, yDim, zDim, floatData);								//!	call function to initialize the height array
			plus_infinity = HUGE_VAL;													//!	set plus infinity in case we ever compare against it
			minus_infinity = -HUGE_VAL;													//!	and minus infinity
			joinRoot = splitRoot = NULL;												//!	set these to something predictable
			maxHeight = *(heightSort[nVertices - 1]); minHeight = *(heightSort[0]);		//!	set min. and max. height
																						//	PrintSortOrder();

			free(nextInBin);
			free(rawData);
			delete[] firstInBin;


		}

		template<typename T> void SetInputDataBlock(T * imageDataBlock, int * dims, int sampleSize) {


			//int* dims = imageData->GetDimensions();
			xDim = dims[0]; yDim = dims[1]; zDim = dims[2];



			// from LoadFromRaw()
			long index;	//	loop index

			if (sampleSize < 1) { printf("Sample sizes less than 1 don't make sense.\n"); throw 0; }
			if (sampleSize > 2) { printf("Sample sizes greater than 2 not yet implemented.\n"); throw 0; }

			//	B.	set nVertices
			nVertices = xDim * yDim * zDim;

			//	C.	allocate leafQueue to a default size, and set leafQSize
			leafQueue = NULL;															//!	allocate space on leaf queue
			leafQSize = 0;																//!	set logical size to zero

																						//	D.	allocate height, heightSort, and visitFlags
			heightSort = (float **)malloc(sizeof(float *) * nVertices);					//!	allocate the array
			visitFlags.Construct(xDim, yDim, zDim);										//!	call template function to set up array

																						//	E.	read in the data, setting pointers in heightSort, and finding maxHeight and minHeight in the process
			maxHeight = -HUGE_VAL; minHeight = HUGE_VAL;
			//	allocate memory 
			float *floatData = (float *)malloc(sizeof(float) * nVertices);				//!	allocate the memory for the float representation


																						// !I wonder if this is really correct
																						//unsigned char *rawData = (unsigned char *)malloc(sizeof(unsigned char) * sampleSize * nVertices);

			//T * rawData = (T*)malloc(sizeof(T)*nVertices);

			// fill the structures from Hamish with a loop
			/*int myindex = 0;
			while (myindex < nVertices) {
			rawData[myindex] = imageData->getElementAtIndex(myindex++);
			}*/

			//// fill the structures from Hamish with a loop
			//for (int z = 0; z < dims[2]; z++)
			//{
			//	for (int y = 0; y < dims[1]; y++)
			//	{
			//		for (int x = 0; x < dims[0]; x++)
			//		{
			//			//unsigned char* pixel = static_cast<unsigned char*>(imageData->GetScalarPointer(x, y, z));
			//			long index = z + dims[2] * y + (dims[2] * dims[1]) * x;
			//			rawData[index] = imageData->getElementAt(x, y, z);										//! assign the data 
			//		}
			//	}
			//}
			//set up radix sort bins
			long nBins = (sampleSize == 1) ? 256 : 65536L;

			long *firstInBin = new long[nBins];
			for (int i = 0; i < nBins; i++) firstInBin[i] = -1;								//!	initialize to "NONE"
			long *nextInBin = (long *)malloc(nVertices * sizeof(long));					//!	and initialize the "next" array
			for (int i = 0; i < nVertices; i++) nextInBin[i] = -1;

			if (sampleSize == 1)
				for (index = 0; index < nVertices; index++)									//!	walk through the data
				{ // walk through data
					nextInBin[index] = firstInBin[imageDataBlock[index]];							//!	push into linked list at front of sorting bin
					firstInBin[imageDataBlock[index]] = index;										//!	and reset the front of the bin
					floatData[index] = (float)imageDataBlock[index];								//!	copy into the float array
					sampleSum += imageDataBlock[index];											//!	add to the running sum
				} // walk through data
			else
			{ // 2-byte data
				unsigned short *rawShort = (unsigned short *)imageDataBlock;
				for (index = 0; index < nVertices; index++)									//	walk through the data
				{ // walk through data
					unsigned short newShort = rawShort[index];
#ifdef ENDIAN_SWAP_SHORTS
					newShort = (newShort >> 8) | ((newShort & 0x00FF) << 8);
#endif
					nextInBin[index] = firstInBin[newShort];							//	push into linked list at front of sorting bin
					firstInBin[newShort] = index;									//	and reset the front of the bin
					floatData[index] = (float)newShort;								//	copy into the float array
					sampleSum += newShort;						//	add to the running sum
				} // walk through data
			} // 2-byte data		

			  /**
			  *	we have now loaded up the float array, and need to setup heightSort properly
			  *	our bin sort has now pushed the elements into bins IN REVERSE ORDER, so we have to
			  *	flip again in reading them out
			  **/

			int bin = nBins;															//!	which bin we are reading from
			long nextSample = -1;														//!	which sample comes next
			for (index = nVertices - 1; index >= 0; index--)
			{ // filling in heightSort
				while (nextSample == -1)												//!	this bin is empty
					nextSample = firstInBin[--bin];										//!	grab the first item in the next bin
				heightSort[index] = floatData + nextSample;								//!	generate & store the pointer
				nextSample = nextInBin[nextSample];										//!	grab the next item
			} // filling in heightSort

			height.Construct(xDim, yDim, zDim, floatData);								//!	call function to initialize the height array
			plus_infinity = HUGE_VAL;													//!	set plus infinity in case we ever compare against it
			minus_infinity = -HUGE_VAL;													//!	and minus infinity
			joinRoot = splitRoot = NULL;												//!	set these to something predictable
			maxHeight = *(heightSort[nVertices - 1]); minHeight = *(heightSort[0]);		//!	set min. and max. height
																						//	PrintSortOrder();

			free(nextInBin);
			//free(rawData);
			delete[] firstInBin;


		}
		void NewTriangleVertices();
		vector<float> points;
		vector<int> surfaces;

		void SetCollapsePriority(int priority) {
			switch (priority) {
			case PRIORITY_HEIGHT:
				break;
			case PRIORITY_VOLUME:
				break;
			case PRIORITY_HYPERVOLUME:
				break;
			case PRIORITY_APPROX_HYPERVOLUME:
				break;
			default:
				priority = PRIORITY_HEIGHT;
			}
			collapsePriority = priority;
		}
		void SetLogPriorityBound(float);
		void SetLogTreeSize(float);
		long GetNSuperarcs();
		long GetNValidArcs();
		boost::tuple<long, long, long> GetSuperNodeTopCoord(int);
		boost::tuple<long, long, long> GetSuperNodeBottomCoord(int);
		boost::tuple<float, float> GetSuperArcTopBottom(int, int);
		boost::tuple<float, float> GetSuperArcTop(int arc) { return GetSuperArcTopBottom(arc, 1); };
		boost::tuple<float, float> GetSuperArcBottom(int arc) { return GetSuperArcTopBottom(arc, -1); };
		int GetValidArc(int);

		float GetLogPriorityBound();
		float GetLogTreeSize();
}; // end of class HeightField

#endif
