//- ****************************************************************************
//- 
//- Copyright 2009 Sandia Corporation. Under the terms of Contract
//- DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
//- retains certain rights in this software.
//- 
//- BSD Open Source License.
//- All rights reserved.
//- 
//- Redistribution and use in source and binary forms, with or without
//- modification, are permitted provided that the following conditions are met:
//- 
//-    * Redistributions of source code must retain the above copyright notice,
//-      this list of conditions and the following disclaimer.
//-    * Redistributions in binary form must reproduce the above copyright
//-      notice, this list of conditions and the following disclaimer in the
//-      documentation and/or other materials provided with the distribution.
//-    * Neither the name of Sandia National Laboratories nor the names of its
//-      contributors may be used to endorse or promote products derived from
//-      this software without specific prior written permission.
//- 
//- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
//- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//- POSSIBILITY OF SUCH DAMAGE.
//-
//- ****************************************************************************

#ifndef GEOTESSGRID_OBJECT_H
#define GEOTESSGRID_OBJECT_H

// **** _SYSTEM INCLUDES_ ******************************************************

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <set>
#include <list>
#include <set>
#include <sstream>

// use standard library objects
using namespace std;

// **** _LOCAL INCLUDES_ *******************************************************

#include "CPPUtils.h"
#include "GeoTessUtils.h"
#include "ArrayReuse.h"
#include "GeoTessException.h"
#include "OptimizationType.h"

// **** _BEGIN GEOTESS NAMESPACE_ **********************************************

namespace geotess
{

// **** _FORWARD REFERENCES_ ***************************************************

class IFStreamAscii;
class IFStreamBinary;

// **** _CLASS DEFINITION_ *****************************************************

/**
 * \brief Manages the geometry and topology of one or more multi-level triangular
 * tessellations of a unit sphere. Has many functions to retrieve information about
 * the grid but knows nothing about Data.
 *
 * Manages the geometry and topology of one or more multi-level triangular
 * tessellations of a unit sphere. It knows:
 * <ul>
 * <li>the positions of all the vertices,
 * <li>the connectivity information that defines how vertices are connected to form triangles,
 * <li>for each triangle it knows the indexes of the 3 neighboring triangles,
 * <li>for each triangle it knows the index of the triangle which is a descendant at the next higher
 * tessellation level, if there is one.
 * <li>information about which triangles reside on which tessellation level
 * </ul>
 * <p>
 * GeoTessGrid is thread-safe in that its internal state is not modified after its data has been
 * loaded into memory. The design intention is that single instances of a GeoTessGrid object and
 * GeoTessData object can be shared among all the threads in a multi-threaded application and each
 * thread will have it's own instance of a GeoTessPosition object that references the common
 * GeoTessGrid + GeoTessData combination.
 *
 * <p>
 * References Ballard, S., J. R. Hipp and C. J. Young, 2009, Efficient and Accurate Calculation of
 * Ray Theory Seismic Travel Time Through Variable Resolution 3D Earth Models, Seismological
 * Research Letters, v.80, n. 6 p. 989-999.
 *
 * @author Sandy Ballard
 */
class GEOTESS_EXP_IMP GeoTessGrid
{
protected:

	/**
	 * An nVertices x 3 array of tessellation vertices. Each vertex is
	 * represented by a 3-component unit vector with it's origin at the center
	 * of the earth. The x-component points toward lat,lon = 0, 0. The
	 * y-component points toward lat,lon = 0, 90. The z-component points toward
	 * north pole.
	 */
	double** vertices;

	/**
	 * Number of vertices.
	 */
	int nVertices;

	/**
	 * An nTriangles x 3 array of integers. Each triangle is represented by the
	 * indexes of the 3 vertices that form the corners of the triangle, listed
	 * in clockwise order when viewed from outside the tessellation.
	 */
	int** triangles;

	/**
	 * Number of triangles.
	 */
	int nTriangles;

	/**
	 * An n x 2 array where n is the number of tessellation levels in all the
	 * tessellations that constitute this model. For each tessellation level,
	 * the first element of the int[2] specifies the index of the first
	 * triangle in the tess level and the second element specifies the index
	 * of the last triangle on the tess level + 1.
	 * <p>
	 * A level is a single-level tessellation of a unit sphere, which is to say
	 * that it is a set of triangles that completely spans the surface of a unit
	 * sphere without gaps or overlaps.
	 */
	int** levels;

	/**
	 * Number of levels.
	 */
	int nLevels;

	/**
	 * tessellations is a n x 2 int array where n is the number of tessellations
	 * in the topology of the model. Each element specifies [0] the index of
	 * the first level and [1] last level + 1 that make up the tessellation.
	 * <p>
	 * A tessellation is a multi-level tessellation of a unit sphere, which is
	 * to say that it is a hierarchical set of single-level tessellations (see
	 * 'levels' above).
	 * <p>
	 * To loop over the triangles of tessellation tessid, level levelid: <br>
	 * for (int i=getFirtTriangle(tessid, levelid); i < getLastTriangle(tessid,
	 * levelid); ++i) <br> { // do something with triangles[i] }
	 */
	int** tessellations;

	/**
	 * Number of tessellations.
	 */
	int nTessellations;

	/**
	 * An nTriangles x 4 array of integers. Neighbors[n][0..2] are the indexes
	 * of the triangles that reside on the other side of one of the edges of
	 * triangle[n]. If edge(i) is the edge that connects vertex[n][j] and
	 * vertex[n][k], i.e., edge(i) is the edge that does not contain
	 * vertex[n][i] then neighbor[n][i] is the triangle that resides on the
	 * other side of edge(i). The last element, neighbor[n][3] is the index
	 * of the descendant of triangle[n], if it has one. If triangle[n] has no
	 * descendants, then neighbor[n][3] = -1.
	 */
	int** neighbors;

	/**
	 * an nTriangles x 3 x 3 array of doubles. For every edge of every
	 * triangle, store the inward pointing normal to the edge, i.e., in a
	 * triangle formed by nodes ni, nj and nk, set edge[i] = nk cross nj.
	 * <p>
	 * This variable can be large and hence it is optional. If it is computed
	 * then the triangle walking algorithm will be much faster because it will
	 * only have to compute dot products instead of scalar triple products. If
	 * it remains null (is never computed) then the walking triangle algorithm
	 * will be slower.
	 * <p>
	 * Whether or not edges are computed is determined by the setting of
	 * variable <i>optimization</i>. If set to SPEED, the edges are computed,
	 * otherwise they are not.
	 */
	double*** edges;

	/**
	 * An nTriangles x 3 array that stores the circumCenters of each triangle
	 * in the grid.  Lazy evaluation is used.
	 */
	mutable double** circumCenters;

	/**
	 * A String ID that uniquely identifies this GeoTessGrid. It must be true
	 * that two GeoTessGrid objects that have different geometry or topology
	 * also have different uniqueID values. An MD5 hash of the primary data
	 * structures (tessellations, levels, triangles and vertices) would be an
	 * excellent choice for the uniqueId, but the uniqueId can be any String
	 * that uniquely identifies the grid.
	 */
	string gridID;

	/**
	 * The name of the file from which the grid was loaded.
	 */
	string gridInputFile;

	/**
	 * The name of the file from which the grid was loaded.
	 */
	string gridOutputFile;

	/**
	 * Name and version number of the software that generated this grid.
	 */
	string gridSoftwareVersion;

	/**
	 * The date when this grid was generated. Not necessarily the same
	 * as the date that the grid file was copied or translated.
	 */
	string gridGenerationDate;

	/**
	 * Reference count.
	 */
	int refCount;

	/**
	 * An nLevels x nVertices x n array that stores the indices of the n
	 * triangles of which each vertex is a member.
	 */
	mutable vector< vector< vector<int> > > vtxTriangles;

	/**
	 * An nLevels x n array that stores the indexes of the n vertices
	 * that are connected together by triangles on the corresponding
	 * level.  Lazy evaluation is used to constuct this array of sets.
	 */
	mutable vector< set<int> > connectedVertices;

	/**
	 * Execution can be optimized either for speed or memory. If optimization is
	 * set to SPEED, then for each edge of a triangle the unit vector normal to
	 * the plane of the great circle containing the edge will be computed during
	 * input of the grid from file and stored in memory. With this information,
	 * the walking triangle algorithm can use dot products instead of scalar
	 * triple products when determining if a point resides inside a triangle.
	 * While much more computationally efficient, it requires a lot of memory to
	 * store all those unit vectors.
	 */
	const	OptimizationType*		optimization;

	/**
	 * Builds this grid from the contents of the input ascii file stream.
	 */
	GeoTessGrid* loadGridAscii(const string& inputFile);

	/**
	 * Read grid from a Scanner in ascii format. Scanner is not closed by this method.
	 */
	GeoTessGrid* loadGridAscii(IFStreamAscii& input);

	static void loadGridAsciiFront(IFStreamAscii& input, int& gridFileFormat,
			string& gridSWVersion, string& fileCreationDate,
			string& gridid, const string& grdInptFile);

	/**
	 * Load the 2D grid from a File.
	 */
	GeoTessGrid* loadGridBinary(const string& inputFile);

	static void loadGridBinaryFront(IFStreamBinary& ifs, int& gridFileFormat,
			string& gridSWVersion, string& fileCreationDate,
			string& gridid, const string& grdInptFile);

	/**
	 * For every edge of every triangle, compute the inward pointing normal to the edge, i.e., in a
	 * triangle formed by nodes ni, nj and nk, set edge[i] = nk cross nj.
	 * <p>
	 * This variable can be large and hence it is optional. If it is computed then the triangle
	 * walking algorithm will be much faster because it will only have to compute dot products
	 * instead of scalar triple products. If it remains null (is never computed) then the walking
	 * triangle algorithm will be slower.
	 * <p>
	 * Whether or not edges are computed is determined by the setting of variable
	 * <i>optimization</i>. If set to SPEED, the edges are computed, otherwise they are not.
	 */
	void findEdges();

	/**
	 * Builds this grid from the contents of the input binary file stream.
	 */
	virtual GeoTessGrid* loadGridBinary(IFStreamBinary& ifs);

	/**
	 * Identify the neighbors and descendants of each triangle. This method is called during
	 * construction of a GeoTessGrid object (i.e., when it is loaded from a file). Applications
	 * should not call this method.
	 *
	 * <p>
	 * If optimization is set to SPEED, then for each edge of a triangle the unit vector normal to
	 * the plane of the great circle containing the edge will be computed during input of the grid
	 * from file and stored in memory. With this information, the walking triangle algorithm can use
	 * dot products instead of scalar triple products when determining if a point resides inside a
	 * triangle. While much more computationally efficient, it requires alot of memory to store all
	 * those unit vectors.
	 */
	int** findNeighbors();

	/**
	 * Standard constructor. Builds this grid from the input file name.
	 */
	GeoTessGrid(const string& gid, const OptimizationType* opttype) :
		vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
		neighbors(NULL), edges(NULL), circumCenters(NULL), gridID(gid),
		gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
		gridGenerationDate(""), refCount(0), optimization(opttype)
	{
	}

public:

	/**
	 * Default constructor. Optimization defaults to OptimizationType::SPEED.
	 * All grid information initialized to NULL.  Applications need to call
	 *
	 */
	GeoTessGrid() :
		vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
		neighbors(NULL), edges(NULL), circumCenters(NULL), gridID(""),
		gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
		gridGenerationDate(""), refCount(0), optimization(&OptimizationType::SPEED)
	{
	}

	/**
	 * Standard constructor. Sets optimiztion.
	 */
	GeoTessGrid(const OptimizationType* opttype) :
		vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
		neighbors(NULL), edges(NULL), circumCenters(NULL), gridID(""),
		gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
		gridGenerationDate(""), refCount(0), optimization(opttype)
	{
	}

	/**
	 * Copy constructor.
	 */
	GeoTessGrid(GeoTessGrid &other);

	/**
	 * Equal operator.
	 */
	GeoTessGrid& operator = (const GeoTessGrid& other);

	/**
	 * Load GeoTessGrid object from a File.
	 */
	GeoTessGrid* loadGrid(const string& inputFile);

	/**
	 * Open the specified file using the appropriate format, and read only enough of the file to
	 * retrieve the gridID.
	 */
	static string getGridID(const string& fileName);

	/**
	 * Test a file to see if it is a GeoTessGrid file.
	 *
	 * @param inputFile
	 * @return true if inputFile is a GeoTessGrid file.
	 */
	static bool isGeoTessGrid(const string& inputFile);

	/**
	 * Return true if the input Grid object (g) gridID equals this Grid objects gridID.
	 */
	bool					operator == (const GeoTessGrid& g) const
											{	return (gridID == g.gridID); }

	/**
	 * Return true if the input Grid object (g) gridID is not equal to this Grid objects gridID.
	 */
	bool					operator != (const GeoTessGrid& g) const
											{	return !(*this == g); }

	/**
	 * A String ID that uniquely identifies this GeoTessGrid. It must be true
	 * that two GeoTessGrid objects that have different geometry or topology
	 * also have different uniqueID values. An MD5 hash of the primary data
	 * structures (tessellations, levels, triangles and vertices) would be an
	 * excellent choice for the uniqueId, but the uniqueId can be any String
	 * that uniquely identifies the grid.
	 *
	 * @return String gridID
	 */
	const string& getGridID() const
	{
		return gridID;
	}

	/**
	 * Returns the optimization type setting.
	 */
	const OptimizationType* getOptimizationType() const { return optimization; }

	/**
	 * Set the name and version number of the software that generated
	 * the contents of this grid.
	 * @param swVersion the name and version number of the software that generated
	 * the contents of this grid.
	 */
	void setGridSoftwareVersion(const string& swVersion) {gridSoftwareVersion = swVersion; };

	/**
	 * Get the name and version number of the software that generated
	 * the contents of this grid.
	 * @return the name and version number of the software that generated
	 * the contents of this grid.
	 */
	const string& getGridSoftwareVersion() const {return gridSoftwareVersion; };

	/**
	 * Set the date when this grid was generated.
	 * This is not necessarily the same as the date when the file was
	 * copied or translated.
	 * @param gridDate
	 */
	void setGridGenerationDate(const string& gridDate) {gridGenerationDate = gridDate; };

	/**
	 * Retrieve the date when the contents of this grid was generated.
	 * This is not necessarily the same as the date when the file was
	 * copied or translated.
	 * @return the date when the contents of this grid was generated.
	 */
	const string& getGridGenerationDate() const {return gridGenerationDate; };

	/**
	 * Set the grid input file.
	 */
	void setGridInputFile(const string& gridFile) { gridInputFile = gridFile; }

	/**
	 * Retrieve the name of the file from which the grid was loaded. This will
	 * be the name of a GeoTessModel file if the grid was stored in the same
	 * file as the model.
	 *
	 * @return the name of the file from which the grid was loaded.
	 */
	const string& getGridInputFile() const {return gridInputFile; }

	/**
	 * Retrieve the name of the file to which this grid was most recently
	 * written, or the string "null" if it has not been written.
	 *
	 * @return the name of the file to which this grid was most recently
	 *         written, or the string "null" if it has not been written.
	 */
	const string& getGridOutputFile() const { return gridOutputFile; }

	/**
	 * Retrieve the unit vector that corresponds to the specified vertex.
	 */
	const double* getVertex(int vertex) const
	{
		return vertices[vertex];
	}

	/**
	 * Get the index of the vertex that occupies the specified position in the
	 * hierarchy.
	 *
	 * @param tessId
	 *            tessellation index
	 * @param level
	 *            index of a level relative to the first level of the specified
	 *            tessellation
	 * @param triangle
	 *            the i'th triangle in the specified tessellation/level
	 * @param corner
	 *            the i'th corner of the specified tessellation/level/triangle
	 * @return index of a vertex
	 */
	int getVertexIndex(int tessId, int level, int triangle, int corner) const
	{
		return triangles[levels[tessellations[tessId][0] + level][0] + triangle][corner];
	}

	/**
	 * Get the unit vector of the vertex that occupies the specified position in
	 * the hierarchy.
	 *
	 * @param tessId tessellation index
	 * @param level index of a level relative to the first level of the specified
	 *            tessellation
	 * @param triangle the i'th triangle in the specified tessellation/level
	 * @param corner the i'th corner of the specified tessellation/level/triangle
	 * @return unit vector of a vertex
	 */
	double* getVertex(int tessId, int level, int triangle, int corner)
	{
		return vertices[triangles[levels[tessellations[tessId][0] + level][0] + triangle][corner]];
	}

	/**
	 * Retrieve a reference to all of the vertices. Vertices consists of an
	 * nVertices x 3 array of doubles. The double[3] array associated with each
	 * vertex is the 3 component unit vector that defines the position of the
	 * vertex.
	 * <p>
	 * Users should not modify the contents of the array.
	 */
	double const* const* getVertices() const { return vertices; }

	/**
	 * Retrieve a set containing the unit vectors of all the vertices that are
	 * connected together by triangles on the top level of the specified tessellation.
	 *
	 * @param tessellation
	 * @param vectors (output) a set containing the unit vectors of all the vertices that are
	 * connected together by triangles on the top level of the specified tessellation.
	 */
	void getVerticesTopLevel(const int& tessellation, set<const double*>& vectors)
	{
		getVertices(tessellation, getNLevels(tessellation)-1, vectors);
	}

	/**
	 * Return a set containing the unit vectors of all the vertices that are
	 * connected together by triangles on the specified tessellation and level.
	 *
	 * @param tessellation
	 * @param level the level relative to the first level of the specified tessellation
	 * @param vectors (output) a set containing the unit vectors of all the vertices that are
	 * connected together by triangles on the specified tessellation and level.
	 */
	void getVertices(const int& tessellation, const int& level, set<const double*>& vectors);

	/**
	 * Retrieve a set containing the indices of all the vertices that are connected
	 * together by triangles on the specified level.  The index of the level is relative
	 * to all the levels in all tessellations.
	 * <p>
	 * Lazy evaluation is used to generate and store these sets.
	 *
	 * For parallel application where thread safety of the GeoTessGrid object
	 * is important, this method will need to be synchronized.
	 *
	 * @param level index of the level is relative to all the levels in all tessellations.
	 * @return a set containing the indices of all the vertices that are connected
	 * together by triangles on the specified level.
	 */
	const set<int>&	getVertexIndices(const int& level);

	/**
	 * Retrieve a set containing the indices of all the vertices that are connected
	 * together by triangles on the specified level.  The index of the level is relative
	 * to the first level of the specified tessellation.
	 * <p>
	 * Lazy evaluation is used to generate and store these sets.
	 *
	 * @param tessId index of the tessellation.
	 * @param level index of the level relative to the first level of the specified tessellation.
	 * @return a set containing the indices of all the vertices that are connected
	 * together by triangles on the specified level.
	 */
	const set<int>&	getVertexIndices(const int& tessId, const int& level)
	{ return getVertexIndices(getLevel(tessId, level)); }

	/**
	 * Retrieve a set containing the indices of all the vertices that are connected
	 * together by triangles on the top level of the specified tessellation.
	 *
	 * <p>
	 * Lazy evaluation is used to generate and store these sets.
	 *
	 * @param tessId index of the tessellation.
	 * @return a set containing the indices of all the vertices that are connected
	 * together by triangles on the top level of the specified tessellation.
	 */
	const set<int>&	getVertexIndicesTopLevel(const int& tessId)
	{ return getVertexIndices(tessellations[tessId][1] - 1); }

	/**
	 * Clear all the sets generated by getVertexIndices(level) and
	 * getVertexIndicesTopLevel(tessId)
	 *
	 * For parallel application where thread safety of the GeoTessGrid object
	 * is important, this method will need to be synchronized.
	 *
	 */
	void clearVertexIndices() { connectedVertices.clear(); }

	/**
	 * Returns the number of vertices in the vectices array.
	 */
	int getNVertices() const { return nVertices; }

	/**
	 * Returns the number of tessellations in the tessellations array.
	 */
	int getNTessellations() const { return nTessellations; }

	/**
	 * Returns the number of levels in the level array.
	 */
	int getNLevels() const { return nLevels; }

	/**
	 * Retrieve number of tessellation levels that define the specified
	 * multi-level tessellation of the model.
	 *
	 * @param tessellation
	 * @return number of levels
	 * @since 2.0
	 */
	int getNLevels(int tessellation) const
	{ return tessellations[tessellation][1] - tessellations[tessellation][0]; }

	/**
	 * Retrieve the index of one of the levels on the specified tessellation
	 *
	 * @param tessellation
	 * @param i
	 *            the index of the desired level (zero would return the index of
	 *            the first level on tessellation.
	 * @return the index of the i'th level on the specified tessellation.
	 */
	int getLevel(int tessellation, int i) const
	{ return tessellations[tessellation][0] + i; }

	/**
	 * Retrieve the index of the last level on the specified tessellation
	 *
	 * @param tessellation
	 * @return The index of the last level on the specified tessellation.
	 */
	int getLastLevel(int tessellation) const
	{ return tessellations[tessellation][1] - 1; }

	/**
	 * Returns the number of Triangles in the Triangle array.
	 */
	int getNTriangles() const { return nTriangles; }

	/**
	 * Retrieve the number of triangles that define the specified level of the
	 * specified multi-level tessellation of the model.
	 *
	 * @param tessellation
	 * @param level
	 * @return number of triangles on specified tessellation and level.
	 * @since 2.0
	 */
	int getNTriangles(int tessellation, int level) const
	{
		return levels[tessellations[tessellation][0] + level][1]
		 - levels[tessellations[tessellation][0] + level][0];
	}

	/**
	 * Retrieve the index of the i'th triangle on the specified level of the
	 * specified tessellation of the model.
	 *
	 * @param tessellation
	 * @param level
	 * @param i
	 * @return a triangle index
	 * @since 2.0
	 */
	int getTriangle(int tessellation, int level, int i) const
	{ return levels[tessellations[tessellation][0] + level][0] + i; }

	/**
	 * Retrieve the index of the first triangle on the specified level of the specified tessellation
	 * of the model.
	 *
	 * @param tessellation
	 * @param level
	 * @return a triangle index
	 * @since 2.0
	 */
	int getFirstTriangle(int tessellation, int level) const
	{ return levels[tessellations[tessellation][0] + level][0]; }

	/**
	 * Retrieve the index of the last triangle on the specified level of the specified tessellation
	 * of the model.
	 *
	 * @param tessellation
	 * @param level
	 * @return a triangle index
	 * @since 2.0
	 */
	int getLastTriangle(int tessellation, int level) const
	{ return levels[tessellations[tessellation][0] + level][1]-1; }

	/**
	 * Retrieve a reference to the nTriangles x 3 array of int that specifies
	 * the indexes of the 3 vertices that define each triangle of the
	 * tessellation.
	 * <p>
	 * Users should not modify the contents of the array.
	 *
	 * @return a reference to the triangles.
	 */
	int const* const* getTriangles() const { return triangles; }

	/**
	 * Retrieve an int[3] array containing the indexes of the vertices that form
	 * the corners of the triangle with index triangleIndex.
	 * <p>
	 * Users should not modify the contents of the array.
	 *
	 * @param triangleIndex
	 *            triangleIndex
	 * @return an int[3] array containing the indexes of the vertices that form
	 *         the corners of the specified triangle.
	 */
	const int* getTriangleVertexIndexes(int triangleIndex) const
	{ return triangles[triangleIndex]; }

	/**
	 * Retrieve the index of the i'th vertex (0..2) that represents one of the
	 * corners of the specified triangle.
	 *
	 * @param triangleIndex
	 *            triangleIndex
	 * @param cornerIndex
	 *            0..2
	 * @return the index of the vertex at the specified corner of the specified
	 *         triangle
	 */
	int getTriangleVertexIndex(int triangleIndex, int cornerIndex) const
	{ return triangles[triangleIndex][cornerIndex]; }

	/**
	 * Retrieve the unit vector of the vertex located at one of the corners of
	 * the specified triangle.
	 *
	 * @param triangleIndex
	 *            triangleIndex
	 * @param cornerIndex
	 *            0..2
	 * @return the unit vector of the vertex at the specified corner of the
	 *         specified triangle
	 */
	const double* getTriangleVertex(int triangleIndex, int cornerIndex) const
	{ return vertices[triangles[triangleIndex][cornerIndex]]; }


	/**
	 * Get the 3 vertices that form the corners of the specified triangle, in clockwise order.
	 *
	 * @param triangle index of the desired triangle
	 * @param triVrt the 3 vertices (unit vectors).
	 * @return 3 x 3 array of doubles with the unit vectors that define the 3 corners of the
	 *         specified triangle.
	 */
	void getTriangleVertices(int triangle, double** triVrt)
	{
		int* corners = triangles[triangle];
		triVrt[0][0] = vertices[corners[0]][0];
		triVrt[0][1] = vertices[corners[0]][1];
		triVrt[0][2] = vertices[corners[0]][2];
		triVrt[1][0] = vertices[corners[1]][0];
		triVrt[1][1] = vertices[corners[1]][1];
		triVrt[1][2] = vertices[corners[1]][2];
		triVrt[2][0] = vertices[corners[2]][0];
		triVrt[2][1] = vertices[corners[2]][1];
		triVrt[2][2] = vertices[corners[2]][2];
	}

	/**
	 * Retrieve the circumCenter of the specified triangle. The circumCenter of
	 * a triangle is the center of the circle that has all three corners of the
	 * triangle on its circumference.
	 *
	 * For parallel application where thread safety of the GeoTessGrid object
	 * is important, this method will need to be synchronized.
	 *
	 * @param triangle Triangle for which the circumcenter will be returned.
	 * @param pA       The array list of circumcenter pointers created by this
	 *                 method that are not stored in the Grid circumCenters
	 *                 array. This list is empty when SPEED optimization is used.
	 * @return unit vector that defines circumCenter.
	 */
	const double* getCircumCenter(int triangle, double* const pA) const
	{
		// if SPEED optimization is off calculate circumcenter and store into pA

		if (edges == NULL)
		{
			// edges == null means that optimization level is MEMORY, not SPEED
			int* corners = triangles[triangle];
			GeoTessUtils::circumCenter(vertices[corners[0]], vertices[corners[1]],
					vertices[corners[2]], pA);
			return pA;
		}

		// SPEED optimization is on ... ensure circumcenter array is created and
		// initialized

		if (circumCenters == NULL)
		{
			circumCenters = CPPUtils::new2DArray<double>(nTriangles, 3);
			CPPUtils::resetArray<double>(nTriangles*3, circumCenters[0], -2.0);
		}

		// define circumcenter if it has not been evaluated and return result

		if (circumCenters[triangle][0] == -2.0)
		{
			int* corners = triangles[triangle];
			GeoTessUtils::circumCenter(vertices[corners[0]], vertices[corners[1]],
					vertices[corners[2]], circumCenters[triangle]);
		}
		return circumCenters[triangle];
	}

	/**
	 * Retrieve the index of one of the triangles that is a neighbor of the specified triangle. A
	 * triangle has at least 3 neighbors and usually has 4. For triangle T, neighbors 0, 1, and 2
	 * reside on the same tessellation level as T and refer to the triangles that share an edge with
	 * T. If T has a fourth neighbor it is a descendent of T and resides on the next higher
	 * tessellation level relative to T. In other words, neighbor(3) is one of the triangles into
	 * which T was subdivided when the tessellation was constructed. If T does not have a
	 * descendant, then getNeighbor(3) will return -1. getNeighbor(i) will always return a valid
	 * triangle index for i=[0,1,2] but may or may not return a valid triangle index for i=3.
	 *
	 * @param triangleIndex index of the triangle whose neighbor is desired.
	 * @param neighborIndex (0..3)
	 * @return int index of the triangle that is a neighbor of triangle.
	 */
	int getNeighbor(int triangleIndex, int neighborIndex) const
	{ return neighbors[triangleIndex][neighborIndex]; }

	/**
	 * Retrieve the indexes of the triangles that are neighbors of the specified triangle. A
	 * triangle has at least 3 neighbors and usually has 4. For triangle T, neighbors 0, 1, and 2
	 * reside on the same tessellation level as T and refer to the triangles that share an edge with
	 * T. If T has a fourth neighbor it is a descendent of T and resides on the next higher
	 * tessellation level relative to T. In other words, neighbor(3) is one of the triangles into
	 * which T was subdivided when the tessellation was constructed. If T does not have a
	 * descendant, then getNeighbor(3) will return -1. getNeighbor(i) will always return a valid
	 * triangle index for i=[0,1,2] but may or may not return a valid triangle index for i=3.
	 *
	 * @param triangleIndex index of the triangle whose neighbors are desired.
	 * @return int[] indexes of the triangles that are neighbors of triangle.
	 */
	const int* getNeighbors(int triangleIndex) const
	{ return neighbors[triangleIndex]; }

	/**
	 * Retrieve the indexes of the triangles that are neighbors of the specified
	 * triangle. A triangle has at least 3 neighbors and usually has 4. For
	 * triangle T, neighbors 0, 1, and 2 reside on the same tessellation level
	 * as T and refer to the triangles that share an edge with T. If T has a
	 * fourth neighbor it is a descendent of T and resides on the next higher
	 * tessellation level relative to T. In other words, neighbor(3) is one of
	 * the triangles into which T was subdivided when the tessellation was
	 * constructed. If T does not have a descendant, then getNeighbor(3) will
	 * return -1. getNeighbor(i) will always return a valid triangle index for
	 * i=[0,1,2] but may or may not return a valid triangle index for i=3.
	 *
	 * @param tessellation
	 *            tessellation index
	 * @param level
	 *            index of a level relative to the first level of the specified
	 *            tessellation
	 * @param triangle
	 *            the i'th triangle in the specified tessellation/level
	 * @return the indexes of the triangles that are neighbors of the specified
	 *         triangle.
	 */
	const int* getNeighbors(const int& tessellation, const int& level, const int& triangle)
	{ return neighbors[getTriangle(tessellation, level, triangle)]; }

	/**
	 * Retrieve the index of the triangle that is the i'th neighbor of the
	 * specified triangle. A triangle has at least 3 neighbors and usually has
	 * 4. For triangle T, neighbors 0, 1, and 2 reside on the same tessellation
	 * level as T and refer to the triangles that share an edge with T. If T has
	 * a fourth neighbor it is a descendent of T and resides on the next higher
	 * tessellation level relative to T. In other words, neighbor(3) is one of
	 * the triangles into which T was subdivided when the tessellation was
	 * constructed. If T does not have a descendant, then getNeighbor(3) will
	 * return -1. getNeighbor(i) will always return a valid triangle index for
	 * i=[0,1,2] but may or may not return a valid triangle index for i=3.
	 *
	 * @param tessellation
	 *            tessellation index
	 * @param level
	 *            index of a level relative to the first level of the specified
	 *            tessellation
	 * @param triangle
	 *            the i'th triangle in the specified tessellation/level
	 * @param side
	 *            the index of the triangle side (0..2)
	 * @return the index of the triangle that is the i'th neighbor of the
	 *         specified triangle.
	 */
	int getNeighbor(const int& tessellation, const int& level, const int& triangle, const int& side)
	{ return neighbors[getTriangle(tessellation, level, triangle)][side]; }

	/**
	 *
	 * @return a reference to the neighbors array.
	 */
	int const* const* getNeighbors() const { return neighbors; }

	/**
	 * If triangle with index tid has a neighbor with index nid, then return the
	 * index of neighbor in triangle's neighbor array.
	 * <p>
	 * In other words, if triangle nid is a neighbor of triangle tid, i.e.,
	 * neighbors[tid][i] == nid, then this method returns i.
	 *
	 * @param tid
	 *            the index of a triangle
	 * @param nid
	 *            the index of another triangle
	 * @return the index of neighbor in triangle's array of neighbors.
	 */
	int getNeighborIndex(const int& tid, const int& nid)
	{
		if (neighbors[tid][0] == nid)
			return 0;
		if (neighbors[tid][1] == nid)
			return 1;
		if (neighbors[tid][2] == nid)
			return 2;
		return -1;
	}

	/**
	 * @return summary information about this GeoTessGrid object.
	 */
	string toString();

	/**
	 * Perform walking triangle search to find the index of the triangle that contains position
	 * defined by vector and which has no descendant.
	 * @param triangleIndex the triangle from which to start the search
	 * @param vector the unit vector of the point that is to be searched for.
	 * @return the index of the triangle that contains vector
	 */
	int getTriangle(int triangleIndex, double* vector);

	/**
	 * Retrieve a list of the triangles a particular vertex is a member of, considering only
	 * triangles in the specified tessellation/level.
	 * <p>
	 * Lazy evaluation is used here. The list of indexes is initially empty and is computed and
	 * stored on demand. Once computed the indexes remain in memory for the next time they might be
	 * called.
	 * @param tessId the tessellation index
	 * @param level index of a level relative to the first level of the specified tessellation
	 * @param vertex the index of the vertex
	 * @return vector of vertex indexes
	 */
	const vector<int>& getVertexTriangles(const int& tessId, const int& level, const int& vertex) const;

	/**
	 * Retrieve a list of the triangles a particular vertex is a member of,
	 * considering only triangles in the top level of the specified tessellation.
	 * <p>
	 * Lazy evaluation is used here. The list of indexes is initially empty and
	 * is computed and stored on demand. Once computed the indexes remain in
	 * memory for the next time they might be called.
	 *
	 * @param tessId
	 *            tessellation index
	 * @param vertex
	 * @return list of triangle indeces
	 */
	const vector<int>& getVertexTriangles(int tessId, int vertex) const
	{ return getVertexTriangles(tessId, getNLevels(tessId)-1, vertex); }

	/**
	 * GeoTessGrid maintains a list of the triangles that each vertex is a member of.
	 * there is a separate list for every tessellation level in the grid.  Lazy
	 * evaluation is used to build this list.
	 * <p>This method clears the list only for the specified tessellation level.
	 */
	void clearVertexTriangles(const int& level);

	/**
	 * GeoTessGrid maintains a list of the triangles that each vertex is a member of.
	 * there is a separate list for every tessellation level in the grid.  Lazy
	 * evaluation is used to build this list.
	 * <p>This method clears the list for all tessellation levels.
	 */
	void clearVertexTriangles();

	/**
	 * Retrieve a list of the indexes of all the vertexes that are connected to the specified vertex
	 * by a single edge, considering only triangles in the specified tessellation and level. The
	 * vertices will be arranged in clockwise order when viewed from outside the unit sphere.
	 * @param tessId the tessellation index
	 * @param level index of a level relative to the first level of the specified tessellation
	 * @param vertex index of central vertex
	 * @param v vector of vertex indexes
	 */
	void getVertexNeighborsOrdered(const int& tessId, const int& level, const int& vertex, vector<int>& v);

	/**
	 * Retrieve a list of the indexes of all the vertexes that are connected to the specified vertex
	 * by a single edge, considering only triangles in the specified tessellation and level.
	 * <p>
	 * Equivalent to calling this function with extra parameter "order" = 1.
	 *
	 * @param tessId tessellation index
	 * @param level index of a level relative to the first level of the specified tessellation
	 * @param vertex index of a vertex
	 * @param nbrs indexes of vertices
	 */
	void getVertexNeighbors(const int& tessId, const int& level, const int& vertex, set<int>& nbrs)
	{ getVertexNeighbors(tessId, level, vertex, 1, nbrs); }

	/**
	 * Retrieve a list of the indexes of all the vertexes that are within a neighborhood of the
	 * specified vertex. The neighborhood is defined by the argument "order". If order is 1, then
	 * all the vertices that are connected by a single edge to vertex are included. If order is 2,
	 * then take the order 1 neighborhood and add all the vertices that are connected to any vertex
	 * in the order-1 neighborhood by a single edge. Keep doing that to as high order as desired.
	 * Only triangles in the specified tessellation and level are considered.
	 *
	 * <p>Supplied set nbrs is cleared at the beginning of this method and it will not contain
	 * starting vertex upon return.
	 *
	 * @param tessId tessellation index
	 * @param level index of a level relative to the first level of the specified tessellation
	 * @param vertex
	 * @param order
	 * @param nbrs list of vertex indices
	 */
	void getVertexNeighbors(const int& tessId, const int& level, const int& vertex,
			const int& order, set<int>& nbrs);

	// All methods below this point are public but are not documented in the doxygen documentation.
	// These are methods that typical applications will never need to call.  They have to be
	// public because other classes in the GeoTess namespace need to access them.
	//
	/// @cond PROTECTED

	/**
	 * Standard constructor. Builds this grid from an ascii file.
	 */
	GeoTessGrid(IFStreamAscii& input, const OptimizationType* opttype) :
		vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
		neighbors(NULL), edges(NULL), circumCenters(NULL), gridID(""),
		gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
		gridGenerationDate(""), refCount(0), optimization(opttype)
	{ loadGridAscii(input); }

	/**
	 * Standard constructor. Builds this grid from a binary file.
	 */
	GeoTessGrid(IFStreamBinary& input, const OptimizationType* opttype) :
		vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
		neighbors(NULL), edges(NULL), circumCenters(NULL), gridID(""),
		gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
		gridGenerationDate(""), refCount(0), optimization(opttype)
	{ loadGridBinary(input); }

	/**
	 * Destructor.
	 */
	virtual ~GeoTessGrid();

	/**
	 * Retrieve reference count;
	 */
	int getReferenceCount() { return refCount; }

	/**
	 * Add reference count;
	 */
	void addReference() { ++refCount; }

	/**
	 * Remove reference count;
	 */
	void removeReference()
	{
		if (isNotReferenced())
		{
			ostringstream os;
			os << endl << "ERROR in GeoTessGrid::removeReference" << endl
					<< "Reference count (" << refCount << ") is already zero." << endl;
			throw GeoTessException(os, __FILE__, __LINE__, 2001);
		}

		--refCount;
	}

	/**
	 * Returns true if reference count is zero.
	 */
	bool isNotReferenced() { return (refCount == 0); }

	/**
	 * Write the grid out to a file.  If the extension is 'ascii'
	 * the grid is written to an ascii file. Otherwise it
	 * is written to a binary file.
	 */
	void writeGrid(const string& fileName);

	/**
	 * Write the grid out to an ascii file.
	 */
	void writeGridAscii(const string& fileName);

	/**
	 * Write the grid out to an ascii file.
	 */
	void writeGridAscii(IFStreamAscii& output);

	/**
	 * Write the grid out to an binary file.
	 */
	void writeGridBinary(const string& fileName);

	/**
	 * Write the 2D grid to a binary file.
	 */
	void writeGridBinary(IFStreamBinary& output);

	/**
	 * an nTriangles x 3 x 3 array of doubles. For every edge of every
	 * triangle, store the inward pointing normal to the edge, i.e., in a
	 * triangle formed by nodes ni, nj and nk, set edge[i] = nk cross nj.
	 * <p>
	 * This variable can be large and hence it is optional. If it is
	 * computed then the triangle walking algorithm will be much faster
	 * because it will only have to compute dot products instead of scalar
	 * triple products. If it remains null (is never computed) then the
	 * walking triangle algorithm will be slower.
	 * <p>
	 * Whether or not edges are computed is determined by the setting of
	 * variable <i>optimization</i>. If set to SPEED, the edges are
	 * computed, otherwise they are not.
	 *
	 * @return a reference to edges
	 */
	double const* const* const* getEdges() const { return edges; }

	/**
	 * Retrieve list of edges that emanate from the specified vertex.
	 * Each edge is defined by 4 indexes:
	 * <ol start="0">
	 * <li>index of the specified vertex
	 * <li>index of a neighboring vertex
	 * <li>index of triangle that is to the 'left' of edge.
	 * <li>index of triangle that is to the 'right' of edge.
	 * </ol>
	 * The first edge will extend from vertex to a random neighboring vertex. Subsequent edges will
	 * be ordered such that the left triangle of a given edge will be equal to the right triangle of
	 * the previous edge (clockwise ordering).
	 *
	 * @param tessId tessellation index
	 * @param level index of a level relative to the first level of the specified tessellation
	 * @param vertex vertex of the vertex whose edges are desired.
	 * @param store
	 * @param e
	 * @throws GeoTessException
	 */
	void getEdgeList(const int& tessId, const int& level, const int& vertex, ArrayReuse<int>& store,
			list<int*>& e)
	{ return getEdgeList(tessId, level, vertex, -1, store, e); }

	/**
	 * Retrieve list of edges that emanate from the specified vertex.
	 */
	void getEdgeList(const int& tessId, const int& level, const int& vertex, const int& firstNeighborVertex,
			ArrayReuse<int>& store, list<int*>& e) const;

	/// @endcond

	/**
	 * Returns true if the input format version is supported.
	 */
	bool isSupportedFormatVersion(int frmtVrsn)
	{ return (frmtVrsn == 2); }

	/**
	 * Tests the integrity of the grid. Visits every triangle T, and (1) checks
	 * to ensure that every neighbor of T includes T in its list of neighbors,
	 * and (2) checks that every neighbor of T shares exactly two nodes with T.
	 *
	 * @throws GeoTessException
	 *             if anything is amiss.
	 */
	void testGrid();

};
// end class GeoTessGrid

}// end namespace geotess

#endif  // GEOTESSGRID_OBJECT_H
