//- ****************************************************************************
//-
//- Copyright 2009 National Technology & Engineering Solutions of Sandia, LLC
//- (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, 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:
//-
//-   1. Redistributions of source code must retain the above copyright notice,
//-      this list of conditions and the following disclaimer.
//-
//-   2. 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.
//-
//-   3. Neither the name of the copyright holder 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 "GeoTessOptimizationType.h"

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

namespace geotess
{

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

class IFStreamAscii;
class IFStreamBinary;

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

/**
 * \brief Stores information about the connection between two adjacent vertices which
 * separates two neighboring triangles.
 *
 * An Edge stores information about the connection between two adjacent vertices which
 * separates two neighboring triangles.  These Edge objects are used in two contexts:
 * (1) every triangle in the grid has an array of three Edges, stored in variable
 * edgeList.  (2) at every level of the grid, each vertex has a circular linked
 * list of Edges which define the Edges emanating from the vertex, in clockwise order.
 * These Edges are stored in variable spokeLists.  These two structures store
 * references to the same set of Edge objects.
 *
 * edgeList - For a triangle formed by vertices i, j and k, edge[i] is the
 * edge opposite vertex i. Put another way, edge[i] is the edge that does not contain
 * vertex i.  edge[i]->vj and edge[i]->vk are the indices of the other two vertices of
 * the triangle accessed, in clockwise order.
 * edge->tLeft is the index of the triangle on the left side of the edge from
 * vj to vk (the triangle that does not contain vertex i). edge->tRight is the
 * index of the triangle on the right side of the edge from vj to vk (the
 * triangle that contains vertex i).  edge(i)->normal is the unit vector normal
 * to edge from vj to vk, pointing toward vertex i (edge->vk cross edge->vj),
 * edge->normal is NOT normalized to unit length.
 *
 * <p>Note that edgeList and spokeList contain pointers to the same instantiations
 * of Edge objects.  edgeList does not use the "Edge* next" field in the Edge objects
 * but spokeList relies on those fields.  Hence the 'next' pointers in Edge objects
 * should not be manipulated via edgeList.
 */
struct Edge
{
    /**
     * vertex index j
     */
    int vj;

    /**
     * vertex index k
     */
    int vk;

    int cornerj;

    /**
     * lndex of triangle to the left of edge from vj to vk
     */
    int tLeft;

    /**
     * index of triangle to the right of edge from vj to vk
     */
    int tRight;

    /**
     * vertex k cross vertex j, not normalized to unit length
     */
    double normal[3]; //

    /**
     * pointer to next edge in circular list of edges emanating from vertex vj.
     * Used by spokeList but not by edgeList.
     */
    Edge* next; //
};

/**
 * \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;

    /**
     * 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.
     */
    void initialize();

    /**
     * Standard constructor. Builds this grid from the input file name.
     */
    GeoTessGrid(const string& gid) :
        vertices(NULL), nVertices(0),
        triangles(NULL), nTriangles(0),
        levels(NULL), nLevels(0),
        tessellations(NULL), nTessellations(0),
        descendants(NULL), gridID(gid),
        gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
        gridGenerationDate(""), refCount(0)
    {
    }

private:

    /**
     * For every triangle, its descendant is the index of a triangle on the next
     * higher tessellation level. In the normal course of events, a triangle on
     * tessellation level i will be subdivided into 4 triangles on tessellation level i+1.
     * A triangle's descendant will be the central one of those 4 triangles.
     * For triangles on the top level of a given tessellation, their descendants are -1.
     */
    int* descendants;

    /**
     * An nTriangles by 3 array of Edge objects. For a triangle formed by vertices
     * i, j and k, edge[i] is the edge opposite vertex i. Put another way, edge i
     * is the edge that does not contain vertex i.  For edge(i), edge->vj and
     * edge->vk are the other two vertices of the triangle accessed clockwise order.
     * edge->tLeft is the index of the triangle on the left side of the edge from
     * vj to vk (the triangle that does not contain vertex i). edge->tRight is the
     * index of the triangle on the right side of the edge from vj to vk (the
     * triangle that contain vertex i).  edge(i)->normal is the unit vector normal
     * to edge from vj to vk.  It was computed as edge->vk cross edge->vj, NOT normalized
     * to unit length.
     *
     * <p>Note that edgeList and spokeList contain pointers to the same instantiations
     * of Edge objects.  edgeList does not use the "Edge* next" field in the Edge objects
     * but spokeList relies on those fields.  Hence the 'next' pointers in Edge objects
     * should not be manipulated via edgeList.
     */
    vector<vector<Edge*> > edgeList;

    /**
     * An nLevels x nVertices array of Edge objects that define spokes emanating from each
     * vertex in clockwise order. spokeList[level][vertex] returns a pointer to single Edge
     * object which is the entry point into a circular list of Edge objects.  Given an Edge
     * object, subsequent edges are accessed with edge->next.  This is a circular list, so
     * you can't simply follow next forever (infinite loop).  You have to keep track of the
     * first edge (head) and loop until edge == head.
     *
     * Each Spoke stores the index of the vertex, the index of the neighboring vertex,
     * the triangle to the right of the spoke and the triangle to the left of the spoke.
     * Following edge->next iterates over the spokes in clockwise order.
     */
    mutable vector<vector<Edge*> > spokeList;

    /**
     * An nTriangles x 3 array that stores the circumCenters of each triangle
     * in the grid.  Lazy evaluation is used.  circumCenters are only needed by
     * GeoTessPositionNaturalNeighbor and computeCircumCenters() is called in its
     * constructor.
     */
    mutable vector<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.
     */
    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 construct this array of sets.
     */
    mutable vector< set<int> > connectedVertices;

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

    /**
     * Read grid from an input stream in ascii format. Stream is not closed by this method.
     * @param input stream from which to read grid
     */
    GeoTessGrid* loadGridAscii(IFStreamAscii& input);

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

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

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

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

    /**
     * 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);

    void computeSpokeLists(const int& level) const;

public:

    /**
     * Default constructor.
     * All grid information initialized to NULL.  Applications need to call
     *
     */
    GeoTessGrid() :
        vertices(NULL), nVertices(0),
        triangles(NULL), nTriangles(0),
        levels(NULL), nLevels(0),
        tessellations(NULL), nTessellations(0),
        descendants(NULL), gridID(""),
        gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
        gridGenerationDate(""), refCount(0)
    { }

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

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

    /**
     * Copy constructor.  Makes a deep copy
     * @param other the other GeoTessGrid whose values are to be duplicated here.
     */
    GeoTessGrid(GeoTessGrid &other);

    /**
     * Equal operator. Makes a deep copy.
     * @param other the other GeoTessGrid whose values are to be duplicated here.
     * @return reference to a deep copy of this grid
     */
    GeoTessGrid& operator= (const GeoTessGrid& other);

    /**
     * Retrieve the amount of memory required by this GeoTessGrid object in bytes.
     * @return the amount of memory required by this GeoTessGrid object in bytes.
     */
    LONG_INT getMemory()
    {
        LONG_INT memory = (LONG_INT)sizeof(GeoTessGrid);

        // double** vertices
        memory += nVertices * (LONG_INT)sizeof(double*) + nVertices * 3 * (LONG_INT)sizeof(double);

        // int** triangles
        memory += nTriangles * (LONG_INT)sizeof(int*) + nTriangles * 3 * (LONG_INT)sizeof(int);

        // int** levels
        memory += nLevels * (LONG_INT)sizeof(int*) + nLevels * 2 * (LONG_INT)sizeof(int);

        // int** tessellations
        memory += nTessellations * (LONG_INT)sizeof(int*) + nTessellations * 2 * (LONG_INT)sizeof(int);

        // int* descendants
        memory += nTriangles * (LONG_INT)sizeof(int);

        // vector<vector<Edge*> > edgeList : nTriangles x 3 array of Edges
        memory += (LONG_INT) (edgeList.capacity() * sizeof(vector<Edge*>)
                + edgeList.size() * 3 * (sizeof(Edge*) + sizeof(Edge)));

        // vector<vector<Edge*> > spokeList;
        memory += (LONG_INT) (spokeList.capacity() * sizeof(vector<Edge*>)
                + spokeList.size() * 3 * sizeof(Edge*));

        // vector<double*> circumCenters is nTriangles x 3 array of doubles
        memory += (LONG_INT) (circumCenters.capacity() * sizeof(double*));
        for (int i=0; i<(int)circumCenters.size(); ++i)
            if (circumCenters[i]) memory += 3 * (LONG_INT)sizeof(double);

        // An nLevels x nVertices x n array that stores the indices of the n
        // triangles of which each vertex is a member.
        // vector< vector< vector<int> > > vtxTriangles;
        memory += (LONG_INT) (vtxTriangles.capacity() * sizeof(vector< vector<int> >));
        for (int i=0; i<(int)vtxTriangles.size(); ++i)
        {
            memory += (LONG_INT) (vtxTriangles[i].capacity() * sizeof(vector<int>));
            for (int j=0; j<(int)vtxTriangles[i].size(); ++j)
                memory += (LONG_INT) (vtxTriangles[i][j].capacity() * sizeof(int));
        }

        // 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 construct this array of sets.
        // vector< set<int> > connectedVertices;
        memory += (LONG_INT) (connectedVertices.capacity() * sizeof(set<int>));
        for (int i=0; i<(int)connectedVertices.size(); ++i)
            memory += (LONG_INT) (connectedVertices[i].size() * sizeof(int));

        // add memory requirements for all the string variables.
        memory += (LONG_INT) (gridID.length() + gridInputFile.length() + gridOutputFile.length()
                + gridSoftwareVersion.length() + gridGenerationDate.length());

        return memory;
    }

    /**
     * Load GeoTessGrid object from a File.
     * @param inputFile name of file from which to load grid.
     * @return pointer to a Grid object
     */
    GeoTessGrid* loadGrid(const string& inputFile);

    /**
     * Open the specified file using the appropriate format, and read only enough of the file to
     * retrieve the gridID.
     * @param fileName name of file
     * @return the grid id of the grid stored in the specified file.
     */
    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.
     * @param g the other grid object to which this grid is to be compared.
     * @return true if this grid and other grid have same gridIDs.
     */
    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.
     * @param g the other grid object to which this grid is to be compared.
     * @return true if this grid and other grid have different gridIDs.
     */
    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;
    }

    /**
     * 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 name.
     * @param gridFile name of grid 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.
     * @param vertex the index of the vertex
     * @return unit vector of vertex
     */
    const double* getVertex(int vertex) const
    {
        return vertices[vertex];
    }

    /**
     * Retrieve the index of the vertex that is closest to the supplied
     * unit vector.  Only vertices connected at the specified tessellation
     * index are searched.
     * @param unit_vector a unit vector
     * @param tessId tessellation to search for the specified unit vector.
     * @return index of closest vertex.
     */
    int findClosestVertex(double* unit_vector, int tessId)
    {
        int* t = triangles[getTriangle(getFirstTriangle(tessId, 0), unit_vector)];

        int index = 0;
        double dot = GeoTessUtils::dot(unit_vector, vertices[t[0]]);

        double doti = GeoTessUtils::dot(unit_vector, vertices[t[1]]);
        if (doti > dot)
        {
            index = 1;
            dot = doti;
        }

        doti = GeoTessUtils::dot(unit_vector, vertices[t[2]]);
        if (doti > dot)
        {
            index = 2;
            dot = doti;
        }

        return t[index];
    }

    /**
     * Get the index of the vertex that occupies the specified position in the
     * hierarchy.
     *
     * @param triangle the i'th triangle in the grid
     * @param corner the i'th corner of the specified triangle
     * @return index of a vertex
     */
    int getVertexIndex(int triangle, int corner) const
    { return triangles[triangle][corner]; }

    /**
     * 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];
    }

    /**
     * Retrieve the index of the vertex that is colocated with the supplied
     * unit vector.
     * @param u a unit vector
     * @return index of colocated vertex, or -1 if there is no such vertex.
     */
    int getVertexIndex(const double* u)
    {
        for (int i=nTessellations-1; i>=0; --i)
        {
            int vid = getVertexIndex(u, i);
            if (vid >= 0)
                return vid;
        }
        return -1;
    }

    /**
     * Retrieve the index of the vertex that is colocated with the supplied
     * unit vector.  Only vertices connected at the specified tessellation
     * index are searched.
     * @param u a unit vector
     * @param tessId tessellation to search for the specified unit vector.
     * @return index of colocated vertex, or -1 if there is no such vertex.
     */
    int getVertexIndex(const double* u, int tessId)
    {
        int* t = triangles[getTriangle(getFirstTriangle(tessId, 0), u)];

        if (GeoTessUtils::dot(u, vertices[t[0]]) > cos(1e-7))
            return t[0];
        if (GeoTessUtils::dot(u, vertices[t[1]]) > cos(1e-7))
            return t[1];
        if (GeoTessUtils::dot(u, vertices[t[2]]) > cos(1e-7))
            return t[2];
        return -1;
    }

    /**
     * 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.
     * @return nVertices x 3 array of unit vectors.
     */
    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 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); }

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

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

    /**
     * Retrieve number of tessellation levels that define the specified
     * multi-level tessellation of the model.
     *
     * @param tessellation
     * @return number of levels
     */
    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 relative to
     *            the first level on tessellation.
     * @return the index of the level relative to all tessellation levels.
     */
    int getLevel(int tessellation, int i) const
    { return tessellations[tessellation][0] + i; }

    /**
     * Retrieve the index of the last level on the specified tessellation, relative to all
     * levels in all tessellations.
     *
     * <p>Levels for all tessellations are stored internally in a single array of level indices.
     * In some instances, the index of a level relative to all the levels in all tessellations
     * is needed. Use this method, getLastLevel(tessId), to retrieve this index.
     * In other instances, the index of a level relative to the first level of
     * a specified tessellation is needed.  Use method getTopLevel(tessid) to retrieve that
     * index.
     *
     * @param tessellation
     * @return the index of the last level on the specified tessellation
     * relative to all levels of all tessellations.
     */
    int getLastLevel(int tessellation) const
    { return tessellations[tessellation][1] - 1; }

    /**
     * Retrieve the index of the last level on the specified tessellation, relative to first
     * level of the specified tessellation.
     *
     * <p>Levels for all tessellations are stored internally in a single array of level indices.
     * In some instances, the index of a level relative to the first level of
     * a specified tessellation is needed.  Use this method, getTopLevel(tessId), to retrieve this index.
     * In other instances, the index of a level relative to all the levels in all tessellations
     * is needed.  Use method getLastLevel(tessid) to retrieve that index.
     *
     * @param tessellation
     * @return the index of the last level on the specified tessellation
     * relative to first level of the tessellation.
     */
    int getTopLevel(int tessellation) const
    { return tessellations[tessellation][1] - tessellations[tessellation][0] - 1; }

    /**
     * Retrieve the number of triangles that define the specified level of the
     * specified multi-level tessellation of the model.
     *
     * @param tessellation
     * @param level index of a level relative to the first level of the specified
     *            tessellation
     * @return number of triangles on specified tessellation and level.
     */
    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 index of a level relative to the first level of the specified
     *            tessellation
     * @param i
     * @return a triangle index
     *
     */
    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 index of a level relative to the first level of the specified
     *            tessellation
     * @return a triangle index
     */
    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 index of a level relative to the first level of the specified
     *            tessellation
     * @return a triangle index
     */
    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];
    }

    /**
     * Compute the circumcenters of all triangles if they have not already
     * been computed.
     */
    const void computeCircumCenters()
    {
        if (circumCenters.empty()) circumCenters.resize(nTriangles, NULL);

        for (int triangle=0; triangle<nTriangles; ++triangle)
            if (circumCenters[triangle] == NULL)
            {
                int* corners = triangles[triangle];
                circumCenters[triangle] = GeoTessUtils::circumCenterPlus(vertices[corners[0]],
                        vertices[corners[1]], vertices[corners[2]]);
            }
    }

    /**
     * Compute the circumcenters of all triangles on the specified level if they have not already
     * been computed.
     */
    const void computeCircumCenters(const int& level)
    {
        if (circumCenters.empty()) circumCenters.resize(nTriangles);

        if (circumCenters[levels[level][0]] == NULL)
        {
            for (int triangle=levels[level][0]; triangle<levels[level][1]; ++triangle)
            {
                int* corners = triangles[triangle];
                circumCenters[triangle] =  GeoTessUtils::circumCenterPlus(vertices[corners[0]],
                        vertices[corners[1]], vertices[corners[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.
     *
     * <p>The fourth element of returned circumcenter is the dot product of the new
     * circumcenter with one of the vertices.  In other words, cc[3] = cos(ccRadius).
     *
     * <p>This method will fail if method computeCircumCenters() has not already
     * been called.  computeCircumCenters() is called from the GeoTessPositionNaturalNeighbor
     * constructor.
     *
     * @param triangle Triangle for which the circumcenter will be returned.
     * @return unit vector that defines circumCenter. Fourth element is cos(ccRadius)
     */
    const double* getCircumCenter(const int& triangle) const { return circumCenters[triangle]; }

    /**
     * Copy 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.
     *
     * <p>The fourth element of returned circumcenter is the dot product of the new
     * circumcenter with one of the vertices.  In other words, cc[3] = cos(ccRadius).
     *
     * <p>This method will fail if method computeCircumCenters() has not already
     * been called.  computeCircumCenters() is called from the GeoTessPositionNaturalNeighbor
     * constructor.
     *
     * @param triangle Triangle for which the circumcenter will be returned.
     * @param cc the 4-element array into which the circumCenter will be copied.
     * The first three elements will get the unit vector that defines circumCenter.
     * Fourth element will get cos(ccRadius)
     */
    void getCircumCenter(const int& triangle, double* cc) const
    { cc[0]=circumCenters[triangle][0]; cc[1]=circumCenters[triangle][1]; cc[2]=circumCenters[triangle][2]; }

    /**
     * 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(const int& triangleIndex, const int& neighborIndex) const
    { return neighborIndex == 3 ? descendants[triangleIndex] : edgeList[triangleIndex][neighborIndex]->tLeft; }

    /**
     * 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 getNeighbor(getTriangle(tessellation, level, triangle), side); }

    /**
     * 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.
     * @param neighbors an array that will be cleared and populated with the three triangle neighbors
     * and the descendant of the supplied triangle.
     */
    void getNeighbors(int triangleIndex, vector<int>& neighbors)
    {
        neighbors.clear();
        vector<Edge*> edges = edgeList[triangleIndex];
        neighbors.push_back(edges[0]->tLeft);
        neighbors.push_back(edges[1]->tLeft);
        neighbors.push_back(edges[2]->tLeft);
        neighbors.push_back(descendants[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
     * @param neighbors an array that will be cleared and populated with the three triangle neighbors
     * and the descendant of the supplied triangle.
     */
    void getNeighbors(const int& tessellation, const int& level, const int& triangle, vector<int>& neighbors)
    { getNeighbors(getTriangle(tessellation, level, triangle), 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 (edgeList[tid][0]->tLeft == nid)
            return 0;
        if (edgeList[tid][1]->tLeft == nid)
            return 1;
        if (edgeList[tid][2]->tLeft == nid)
            return 2;
        return -1;
    }

    int const* getDescendants() const { return descendants; }

    int getDescendant(const int& triangle) const { return descendants[triangle]; }

    int getDescendant(const int& tessId, const int& level, const int& triangle) const
    { return descendants[getTriangle(tessId, level, triangle)]; }

    /**
     * @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, const double* vector);

    /**
     * Retrieve a list of the triangles a particular vertex is a member of, considering only
     * triangles in the specified tessellation/level.
     *
     * @param level index of a level relative to all levels in the grid.
     * @return vector of vertex indexes
     */
    const vector<vector<int> >& getVertexTriangles(const int& level) const { return vtxTriangles[level]; }

    /**
     * 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
                            { return vtxTriangles[tessellations[tessId][0] + level][vertex]; }

    /**
     * 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 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

    /**
     * Deprecated because GeoTessOptimizationType is no longer used.
     * GeoTess is always optimized for speed.
     * @param opttype
     */
    GeoTessGrid(const GeoTessOptimizationType* opttype) :
        vertices(NULL), nVertices(0),
        triangles(NULL), nTriangles(0),
        levels(NULL), nLevels(0),
        tessellations(NULL), nTessellations(0),
        descendants(NULL), gridID(""),
        gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
        gridGenerationDate(""), refCount(0)
    { }

    /**
     * Deprecated because GeoTessOptimizationType is no longer used.
     * GeoTess is always optimized for speed.
     */
    GeoTessGrid(IFStreamAscii& input, const GeoTessOptimizationType* opttype) :
        vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
        descendants(NULL), gridID(""),
        gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
        gridGenerationDate(""), refCount(0)
    { loadGridAscii(input); }

    /**
     * Deprecated because GeoTessOptimizationType is no longer used.
     * GeoTess is always optimized for speed.
     */
    GeoTessGrid(IFStreamBinary& input, const GeoTessOptimizationType* opttype) :
        vertices(NULL), triangles(NULL), levels(NULL), tessellations(NULL),
        descendants(NULL), gridID(""),
        gridInputFile("null"), gridOutputFile("null"), gridSoftwareVersion(""),
        gridGenerationDate(""), refCount(0)
    { loadGridBinary(input); }

    /**
     * Deprecated because GeoTessOptimizationType is no longer used.
     * GeoTess is always optimized for speed.
     */
    GeoTessGrid(double** _vertices, int& _nVertices,
            int** _triangles, int& _nTriangles,
            int** _levels, int& _nLevels,
            int** _tessellations, int& _nTessellations,
            string& _gridID,
            string& _gridInputFile,
            string& _gridOutputFile,
            string& _gridSoftwareVersion,
            string& _gridGenerationDate) :
                vertices(_vertices), nVertices(_nVertices),
                triangles(_triangles), nTriangles(_nTriangles),
                levels(_levels), nLevels(_nLevels),
                tessellations(_tessellations), nTessellations(_nTessellations),
                descendants(NULL),
                gridID(_gridID),
                gridInputFile(_gridInputFile),
                gridOutputFile(_gridOutputFile),
                gridSoftwareVersion(_gridSoftwareVersion),
                gridGenerationDate(_gridGenerationDate),
                refCount(0)
    { initialize(); }

    /**
     * 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);

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

    // deprecated. GeoTessOptimizationType is no longer used.  Always optimized for speed.
    const GeoTessOptimizationType& getOptimizationType() const { return GeoTessOptimizationType::SPEED; }

    /// @endcond

    /**
     * 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();

    /**
     * Returns the number of tessellation levels defined for this grid.
     *
     * @return The number of tessellation levels defined for this grid.
     */
    int getNLevels() const { return nLevels; }

    /**
     * Retrieve a reference to all of the tessellation levels. Levels consists of
     * an nLevels x 2 array of ints. The int[2] array associated with each
     * level is the first ([0]) and last ([1]) + 1 index of the triangles on the
     * level.
     * <p>
     * Users should not modify the contents of the array.
     *
     * @return nLevels x 2 array of unit triangle start and end indices for
     *         each tessellation.
     */
    int const* const* getLevels() const { return levels; }

    /**
     * Retrieve a reference to all of the tessellations of this grid.
     * 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>
     * Users should not modify the contents of the array.
     * @return nLevels x 2 array of unit triangle start and end indices for
     *         each tessellation.
     */
    int const* const* getTessellations() const { return tessellations; }

    /**
     * Retrieve the total number of triangles including those on all levels of
     * all tessellations.
     *
     * @return the total number of triangles including those on all levels of
     *         all tessellations.
     */
    int getNTriangles() const { return nTriangles; }

    vector<Edge*>& getSpokeList(const int& level) const
    { computeSpokeLists(level); return spokeList[level]; }

    const vector<vector<Edge*> >& getEdgeList() const { return edgeList; }

    const vector<Edge*>& getEdgeList(const int& triangle) const { return edgeList[triangle]; }

    /**
     * Compute the unit vector that resides at the center of the specified triangle.
     * @param triangle the index of the triangle
     * @param center unit vector that is populated with the location of the center of the
     * specified triangle;
     */
    void getCenter(const int& triangle, double* center)
    {
        vector<double*> corners;
        corners.push_back(vertices[triangles[triangle][0]]);
        corners.push_back(vertices[triangles[triangle][1]]);
        corners.push_back(vertices[triangles[triangle][2]]);
        GeoTessUtils::center(corners, center);
    }

    /**
     * Convert tessellation to a Delaunay tessellation.
     *
     * @return number of changes.
     */
    int delaunay();

};
// end class GeoTessGrid

}// end namespace geotess

#endif  // GEOTESSGRID_OBJECT_H
