//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2016 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#ifndef MESH_HPP
#define MESH_HPP

/**
 * \file Mesh.hpp
 *
 * This files contains the definition of a mesh for the Process API
 */

#include <Config.hpp>

#include <Types.hpp>
#include <Attributes.hpp>

#include <cuda/CudaExport.hpp>
#include <CellTissue.hpp>
#include <Stack.hpp>
#include <TransferFunction.hpp>

#include <omp.h>
#include <QImage>
#include <string.h>
#include <typeinfo>

namespace mgx 
{
  /// Map of an integer to a host vector of 3 unsigned integers
  typedef std::unordered_map<int, HVec3U> IntHVec3uMap;
  /// Element in IntHVec3uMap
  typedef std::pair<int, HVec3U> IntHVec3uPair;

  class SetupProcess;
  
  /**
   * \class Mesh Mesh.hpp <Mesh.hpp>
   *
   * This class holds the actual mesh as a VV Graph and all sort of properties
   * for it, including visualization ones.
   *
   * Note that, in MorphoGraphX, the user sees the surface, or the mesh. The
   * surface is continuous, when the mesh is the actual connectivity of the
   * vertices.
   */
  class mgx_EXPORT Mesh 
  {
    friend class SetupProcess;
  
  public:
    /**
     * Surface visualization type
     */
    enum SurfView 
    {
      SURF_VERTEX,			///< Vertex level rendering such as projected signal
      SURF_LABEL,				///< Label level rendering
      SURF_TRIANGLE,    ///< Triangle level rendering
      SURF_VIEW_COUNT   ///< Count of SurfView entries
    };
  
    /**
     * Create an empty mesh attached to the stack
     */
    //Mesh(const Stack* stack);
  
    /**
     * Create an empty mesh attached to the stack
     */
    Mesh(int id, const Stack* stack);
  
    /**
     * Copy the mesh
     */
    //Mesh(const Mesh &copy);
  
    /**
     * Mesh destructor
     */
    ~Mesh();
  
    //@{
    ///\name Global properties
    /// Properties for both mesh and surface. If any of these properties are saved, it will
    /// be in the project file.
  
    /**
     * Id of the current mesh
     *
     * This is the same id used in the Process:mesh(int) method.
     */
    int id() const { return _id; }
  
    /**
     * Change the id of the mesh.
     *
     * Please do not use this method for meshes attached to a process.
     */
    void setId(int i) { _id = i; }
  
    /**
     * Id as seen by the user
     *
     * This is, typically id()+1
     */
    int userId() const { return _id + 1; }

    /**
     * Returns the stack associated to this mesh
     */
    const Stack* stack() const { return _stack; }

    /**
     * Returns the name of the mesh file
     */
    const QString &file() const { return _file; }

    /**
     * Set the name of the mesh file.
     *
     * This is called when the mesh is loaded or saved. Processes that create
     * a new mesh should call this without a parameter to reset the filename to null.
     */
    void setFile(const QString &file = QString());

    /**
     * Returns true if the mesh is scaled
     */
    bool scaled() const { return _scaled; }

    /**
     * Set if the mesh is scaled
     */
    void setScaled(bool on = true) { _scaled = on; }
  
    /**
     * Returns true if the mesh is transformed
     */
    bool transformed() const { return _transformed; }

    /**
     * Set if the mesh is transformed
     */
    void setTransformed(bool on = true) { _transformed = on; }
  
    /**
     * Returns true if the bounding box is shown
     */
    bool showBBox() const { return _showBBox; }
  
    /**
     * Set if the bounding box is shown
     */
    void setShowBBox(bool on = true) { _showBBox = on; }
  
    /**
     * Returns the current label, without modifying it
     */
    int viewLabel() const { return T.viewLabel(); }

    /**
     * Sets the current label
     */
    void setLabel(int l) { T.setLabel(l); }

    /**
     * Increment the current label and return
     */
    int nextLabel() { return T.nextLabel(); }

    //@}
  
    //@{
    ///\name Mesh Attributes. These are saved along with the mesh and can be extended by the user.

    /**
     * Get the mesh attributes
     */
    const Attributes &attributes() const
    {
      return _attributes;
    }

    Attributes &attributes()
    {
      return _attributes;
    }

    /**
     * Reference to the map from each label to its parent
     */
    IntIntAttr &parents() 
    {
      return _attributes.attrMap<int, int>("Cell Parent");
    }

    /**
     * Returns the mesh type
     */
    const QString &meshType()
    {
      return T.meshType();
    }

    /**
     * Set the mesh type
     */
    const QString &setMeshType(const QString &mType)
    {
      return T.setMeshType(mType);
    }

    /**
     * Convenience function to tell if a 3D mesh (from viewpoint of rendering)
     */
    bool mesh3D()
    {
      if(meshType() == "MGX3D")
        return true;
      return false;
    }

    /**
     * Reference to the map from label to a center position.
     *
     * This position will be interpreted as the center of the label, and used to
     * draw the label number on the mesh or growth directions on cellular mesh.
     *
     */
    IntPoint3fAttr &labelCenter() 
    {
      return _attributes.attrMap<int, Point3f>("Cell Center");
    }

    /**
     * Reference to the map from label to a normal.
     *
     * This vector will be intepreted as the normal of the label, and used to
     * draw the cell axis (e.g. principal directions of growth, MT orientation...).
     *
     */
    IntPoint3fAttr &labelNormal() 
    {
      return _attributes.attrMap<int, Point3f>("Cell Normal");
    }

    /**
     * Reference to the map from label to a position.
     *
     * This position will be intepreted as the center of the label, and used to
     * draw growth directions on a non-cellular mesh.
     *
     */
    IntPoint3fAttr &labelCenterVis() 
    {
      return _attributes.attrMap<int, Point3f>("Cell CenterVis");
    }

    /**
     * Reference to the map from label to a normal.
     *
     * This vector will be intepreted as the normal of the label, and used to
     * draw the cell axis (e.g. principal directions of growth, MT orientation...).
     *
     */
    IntPoint3fAttr &labelNormalVis() 
    {
      return _attributes.attrMap<int, Point3f>("Cell NormalVis");
    }
  
    /**
     * Reference to the map from parent label to a position.
     *
     * This position will be interpreted as the center of the parent label, and used to
     * draw the parent label number on the mesh or growth directions on cellular mesh.
     *
     */
    IntPoint3fAttr &parentCenter() 
    {
      return _attributes.attrMap<int, Point3f>("Parent Center");
    }

    /**
     * Reference to the map from parent label to a normal.
     *
     * This vector will be intepreted as the normal of the parent label, and used to
     * draw the cell axis (e.g. principal directions of growth, MT orientation...).
     *
     */
    IntPoint3fAttr &parentNormal() 
    {
      return _attributes.attrMap<int, Point3f>("Parent Normal");
    }

    /**
     * Reference to the map from parent label to a position.
     *
     * This position will be intepreted as the center of the parent label, and used to
     * draw growth directions on a non-cellular mesh.
     *
     */
    IntPoint3fAttr &parentCenterVis() 
    {
      return _attributes.attrMap<int, Point3f>("Parent CenterVis");
    }

    /**
     * Reference to the map from parent label to a normal.
     *
     * This vector will be intepreted as the normal of the parent label, and used to
     * draw the cell axis (e.g. principal directions of growth, MT orientation...).
     *
     */
    IntPoint3fAttr &parentNormalVis() 
    {
      return _attributes.attrMap<int, Point3f>("Parent NormalVis");
    }


    /**
     * Reference to a map of 2D texture coordinates, this is used to load 3D images
     * like that from the Keyance
     */
    VtxPoint2fAttr &texCoord2d()
    {
      return _attributes.attrMap<vertex, Point2f>("Vertex TexCoord2D");
    }

    /**
     * Reset the whole mesh and its attributes
     *
     * In the end, the mesh is empty, so doesn't contain cells, texture and is neither 
     * scaled nor transformed. All of the attributes are deleted.
     *
     * The next label stays untouched, as it is important to keep coordination between 
     * different meshes/stacks.
     */
    void reset();
    //@}
  
    //@{
    ///\name Structure
  
    /**
     * Get the VV graph of the mesh
     */
    vvGraph &graph() { return T.S; }

    /**
     * Get the VV graph of the mesh
     */
    const vvGraph &graph() const { return T.S; }
  
    /**
     * Get the VV junction graph
     */
    vvGraph &junctions() { return T.J; }

    /**
     * Get the VV junction graph
     */
    const vvGraph &junctions() const { return T.J; }

    /**
     * Get the Cell Tissue
     */
    const CellTissue &tissue() const { return T; }

    /**
     * Get the Cell Tissue
     */
    CellTissue &tissue() { return T; }

    /**
     * Get the cell graph
     */
    cellGraph &cells() { return T.C; }

    /**
     * Get the cell graph
     */
    const cellGraph &cells() const { return T.C; }

    /**
     * True if the mesh is empty (i.e. the graph is empty)
     */
    bool empty() const { return T.S.empty() && T.C.empty(); }

    /**
     * Get the neighborhood object for the S graph
     */
    CellTissue::DistNhbdS &nhbdS() { return T.nhbdS; }

    /**
     * Get the neighborhood object for the cell graph
     */
    CellTissue::DistNhbdC &nhbdC() { return T.nhbdC; }

    /**
     * Returns the number of vertices in the mesh
     */
    //size_t size() const { return T.S.size(); }

    /**
     * Returns the label or parent of the triangle (v1,v2,v3)
     */
    int getLabel(const vertex &v1, const vertex &v2, const vertex &v3, 
                                           const IntIntAttr &parents);
    /**
     * Returns the label or parent, given a label
     */
    int getLabel(int label, const IntIntAttr &parents);

    /**
     * Check the graph for consistency
     *
     * Returns true if any problems were found
     */
    bool chkGraph(vvGraph &S) { return T.chkGraph(S); }  
    bool chkGraph() { return T.chkGraph(T.S); }

     /**
     * Reference to the map from each wall to the list of vertexes in the wall.
     *
     * A wall is identified as the interface between two labels, and as such, 
     * is given as a pair of labels. Note that there is a difference between 
     * the wall (i,j) and (j,i), as the first label is considered as the interior of the
     * wall, and used as such when calculating the signal along a wall.
     *
     * \note You shouldn't need to modify this structure directly. You should
     * instead call Mesh::updateWallGeometry()
     *
     * RSS Should this then be private?
     */
    IntIntVIdSetMap &wallVId() { return _wallVId; }

    /**
     * Returns the map from each wall to the list of vertexes in the wall.
     */
    const IntIntVIdSetMap &wallVId() const { return _wallVId; }

    /**
     * Reference to the map from each wall to the length of the wall.
     *
     * The length is calculated as the sum of the edges making the wall. This means the 
     * number returned is will depend on the discretization of the surface.
     *
     * \note You shouldn't need to modify this structure directly. You should
     * instead call Mesh::updateWallGeometry()
     */
    IntIntFloatAttr &wallGeom() 
    {
      return _attributes.attrMap<IntIntPair, float>("Wall Geom");
    }

     /**
     * Reference to the map from labels to the set of neighbor labels.
     *
     * A label is neighbors of another ones if they share at least an edge of the mesh.
     *
     * \note You shouldn't need to modify this structure directly. You should
     * instead call Mesh::updateWallGeometry()
     */
    IntIntSetMap &labelNeighbors() { return _labelNeighbors; }

    /**
     * Returns the map from labels to the set of neighbors labels.
     */
    const IntIntSetMap &labelNeighbors() const { return _labelNeighbors; }
  
    /**
     * Update labelNeighbors, wallVId and wallGeom to reflect current data structure
     * \param borderSize Distance from the wall up to which the triangles are considered 
     * part of the wall. This is important mostly for signal intensity.
     */
    void updateWallGeometry(float borderSize);

    /**
     * True if (v,n,m) is on the border of the \c label.
     *
     * \c rp will be set to the wall the triangle is on, if any.
     */
    bool isBordTriangle(int label, vertex v, vertex n, vertex m, IntIntPair &rp) const;
  
    /**
     * Mark all triangles closer than borderSize from a border as being
     * a border triangle
     */
    void markBorder(float borderSize);
  
    /**
     * Search for the vertex closest to position of cell center
     * fills in labelCenter, labelNormal, labelCenterVis, labelNormalVis
     */
    void updateCentersNormals();
  
    //@}
  
    //@{
    ///\name Surface methods
    /**
     * Return the transfer function used to draw the surface in normal mode
     */
    TransferFunction surfFct() const { return _surf_fct; }

    /**
     * Change the transfer function used to draw the surface in normal mode
     */
    void setSurfFct(const TransferFunction &f)
    {
      if(_surf_fct != f) {
        _surf_fct = f;
        changed_surf_function = true;
      }
    }
    /**
     * Returns true if the normal transfer function has been changed during the
     * current process.
     */
    bool surfFctChanged() const { return changed_surf_function; }
  
    /**
     * Return the transfer function used to draw the surface in heat mode
     */
    TransferFunction heatFct() const { return _heat_fct; }

    /**
     * Change the transfer function used to draw the surface in heat mode
     */
    void setHeatFct(const TransferFunction &f)
    {
      if(_heat_fct != f) {
        _heat_fct = f;
        changed_heat_function = true;
      }
    }
    /**
     * Returns true if the heat transfer function has been changed during the
     * current process.
     */
    bool heatFctChanged() const { return changed_heat_function; }
  
    /**
     * Get the current opacity level of the surface
     */
    float opacity() const { return _opacity; }

    /**
     * Change the current opactity level of the surface
     */
    void setOpacity(float f)
    {
      if(f < 0)
        _opacity = 0;
      else if(f > 1)
        _opacity = 1;
      else
        _opacity = f;
    }
    /**
     * Get the current brightness of the surface
     */
    float brightness() const { return _brightness; }

    /**
     * Change the current brightness of the surface
     */
    void setBrightness(float f)
    {
      if(f < 0.0)
        _brightness = 0.0;
      else if(f > 1.0)
        _brightness = 1.0;
      else
        _brightness = f;
    }
  
    /**
     * True if the surface is currently visible to the user
     */
    bool showSurface() const { return _showSurface; }

    /**
     * Show the surface to the user
     */
    void setShowSurface(bool val = true) { _showSurface = val; }

    /**
     * Set the surface vertex display
     */
    void setShowVertex(const QString &s = "", bool setView = true) 
    { 
      if(setView)
        _surfView = SURF_VERTEX; 
      if(s != "")
        _surfVertexView = s;
    }

    /**
     * Set the surface triangle display
     */
    void setShowTriangle(const QString &s = "", bool setView = true) 
    {  
      if(setView)
        _surfView = SURF_TRIANGLE; 
      if(s != "")
        _surfTriangleView = s; 
    }

    /**
     * Set the surface label display
     */
    void setShowLabel(const QString &s = "", bool setView = true) 
    {
      if(setView)
        _surfView = SURF_LABEL;
      if(s != "")
        _surfLabelView = s;
    }
  
    /**
     * Returns if the back surface is culled
     */
    bool culling() const { return _culling; }

    /**
     * Cull the back surface
     */
    void setCulling(bool cul) { _culling = cul; }
  
    /**
     * Return if the surface is rendered blended or not
     */
    bool blending() const { return _blending; }

    /**
     * Set the blending attribute
     */
    void setBlending(bool b) { _blending = b; }
  
    /**
     * Returns the current visualization for the surface
     */
    SurfView surfView() const { return _surfView; }

    /**
     * Change the view mode
     */
    void setSurfView(SurfView view) { _surfView = view; }

    /**
     * Returns the vertex visualization
     */
    QString surfVertexView() const { return _surfVertexView; }

    /**
     * Returns the triangle visualization
     */
    QString surfTriangleView() const { return _surfTriangleView; }

    /**
     * Returns the label visualization
     */
    QString surfLabelView() const { return _surfLabelView; }

    /**
     * Convenience functions
     */
    bool showSignal() const { return showSurface() and surfView() == SURF_VERTEX and surfVertexView() == "Signal"; }
    bool showLabels() const { return showSurface() and surfView() == SURF_LABEL and surfLabelView() == "Label"; }
    bool showHeat() const { return showSurface() and surfView() == SURF_LABEL and surfLabelView() == "Label Heat"; }
    bool showWallHeat() const { return showSurface() and surfView() == SURF_LABEL and surfLabelView() == "Wall Heat"; }
    bool showTriangleValue() const { return showSurface() and surfView() == SURF_TRIANGLE and surfTriangleView() == "Triangle Value"; }

    /**
     * Returns if we should use parents or labels
     */
    bool useParents() { return _useParents; }

    /**
     * Show the color of the surface
     */
    void setUseParents(bool val) { _useParents = val; }

    /**
     * True if the surface has a texture attached to it
     */
    bool &hasImgTex() 
    { 
      return _attributes.attrMap<QString, bool>("HasImageTex")["HasImageTex"];
    }

    /**
     * Get the current texture attached to the surface
     */
    const QImage &imgTex() const { return _image; }
    QImage &imgTex() { return _image; }

    /**
     * Set the texture attached to the surface
     */
    void setImgTex(const QImage &img)
    {
      hasImgTex() = true;
      _image = img;
    }

    /**
     * Remove any texture attached to the surface
     */
    void clearImgTex()
    {
      _imgtex = false;
      _attributes.attrMap<QString, QByteArray>("ImageTex").erase("ImageTex");
      _image = QImage();
    }
  
    //@}
  
    //@{
    ///\name Mesh methods
    /**
     * Is the mesh currently visible to the user
     */
    bool showMesh() const { return _showMesh; }

    /**
     * Return the current view mode for the mesh
     */
    QString meshView() const { return _meshView; }

    /**
     * Set the mesh visibility
     */
    void setShowMesh(bool show = true) { _showMesh = show; }

    /**
     * Set the mesh display and view
     */
    void setMeshView(const QString &s, bool setShow = true) 
    { 
      if(setShow)
        _showMesh = true; 
      _meshView = s;
    }

    /**
     * Is the axis currently visible to the user
     */
    bool showAxis() const { return _showAxis; }

    /**
     * Return the current view mode for the axis
     */
    QString axisView() const { return _axisView; }

    /**
     * Set the axis display
     */
    void setShowAxis(bool show = true) { _showAxis = show; }

    /**
     * Set the axis display and view
     */
    void setAxisView(const QString &s, bool setShow = true) 
    { 
      if(setShow)
        _showAxis = true; 
      _axisView = s;
    }

    /**
     * Are mesh lines visible
     */
    bool showMeshLines() const { return _showMeshLines; }

    /**
     * Are mesh points visible
     */
    bool showMeshPoints() const { return _showMeshPoints; }

    /**
     * Are cell numbers visible
     */
    bool showMeshCellMap() const { return _showMeshCellMap; }

    /**
     * Set if the mesh lines are visible
     */
    void setShowMeshLines(bool show) { _showMeshLines = show; }

    /**
     * Set if the mesh points are visible
     */
    void setShowMeshPoints(bool show) { _showMeshPoints = show; }

    /**
     * Set if the cell numbers are visible
     */
    void setShowMeshCellMap(bool show) { _showMeshCellMap = show; }

    /**
     * Returns a vector with the list of selected vertices.
     */
    std::vector<vertex> selectedVertices() const;

    /**
     * Returns the count of selected vertices (from S).
     */
    int selectedCount() const;

    /**
     * Returns a vector with the list of active vertices.
     *
     * These are either the selected vertices, or all of them if no vertex was selected.
     */
    std::vector<vertex> activeVertices() const;

    // These next two should really be algorithms for the graph as they don't rely on
    // any Mesh variables.
    /**
     * Starting with a set of vertices, extend to connected region
     */
    void getConnectedVertices(const vvGraph &S, vvGraph &vSet) const;

    /**
     * Get a list of connected regions (3D cells)
     */
    int getConnectedRegions(const vvGraph &S, VVGraphVec &cellVId, VtxIntMap &vtxCell) const;
  
    /**
     * Get the neighborhood of a vertex
     */
    static void getNhbd(const vvGraph &S, const vertex &v, float radius, VtxSet &nbs);
     /**
     * Clear selection
     *
     * Returns true if anything cleared
     */
    bool clearSelection(); 
    /**
     * Correct selection
     *
     * Make sure the vertices are "correctly" selected. This means that:
     *  - border vertices will be selected if all their non-border neighbors are selected
     *  - border vertices will be selected if they don't have a non-border neighbors and 
     *    at least one border neighbor is  selected
     *  - if the selection is inclusive, border vertices will be selected if at least one 
     *    non-border neighbor is selected
     */
    void correctSelection(bool inclusive);
  
    //@}
  
    //@{
    ///\name Updating the graphical representation
    /**
     * To be called when the mesh structure changed
     */
    void updateAll();
    /**
     * To be called if properties of the triangles changed
     */
    void updateTriangles();
    /**
     * To be called if properties of the lines changed
     */
    void updateLines();
    /**
     * To be called if the position of the points changed
     */
    void updatePositions();
    /**
     * To be called if the selection of the points changed
     */
    void updateSelection();
    /**
     * Returns what changed in the current process
     */
    int changes() const { return _changed; }
    //@}
  
    //@{
    /**
     * \name Heat Map methods
     * The heat map associates a heat to a label or a wall. Heat map data is stored
     * in the attributes, so it is save/restored with the mesh.
     */

    /**
     * Reference to map of heat data by label 
     */
    IntFloatAttr &labelHeat() 
    {
      return _attributes.attrMap<int, float>("Cell Heat");
    }

    /**
     * Reference to the unit used for the current heat map.
     *
     * It is shown on the color bar.
     */
    QString &heatMapUnit() 
    {
      return _attributes.attrMap<QString, QString>("Cell Heat Unit")["Cell Heat Unit"];
    }

    QString &heatMapScaling() 
    {
      return _attributes.attrMap<QString, QString>("Cell Heat Unit")["Cell Heat Scaling"];
    }

    /**
     * Return the upper and lower bounds for the heat.
     */
    Point2f &heatMapBounds() 
    {
      return _attributes.attrMap<QString, Point2f>("Cell Heat Bounds")["Cell Heat Bounds"];
    }

    /**
     * Scale the heat map bounds to the existing range.
     */
    Point2f calcHeatMapBounds();

    /** 
     * Reference to map of heat data by wall (i.e. pair of vertex id) to intensity
     */
    IntIntFloatAttr &wallHeat() 
    {
      return _attributes.attrMap<IntIntPair, float>("Wall Heat");
    }

    /**
     * Upper and lower bounds for the heat.
     */
    Point2f &wallHeatBounds() 
    {
      return _attributes.attrMap<QString, Point2f>("Wall Heat Bounds")["Wall Heat Bounds"];
    }

    /**
     * Wall heat unit
     */
    QString &wallHeatUnit() 
    {
      return _attributes.attrMap<QString, QString>("Wall Heat Unit")["Wall Heat Unit"];
    }
    //@}
  
    //@{
    /**
     * Triangle colors
     */
    TriVec3ColorbAttr &triangleColor() 
    {
      return _attributes.attrMap<Triangle, Vec3Colorb>("Triangle Color");
    }

    /**
     * Triangle index for indexed color map mode 
     */
    TriIntAttr &triangleIndex() 
    {
      return _attributes.attrMap<Triangle, int>("Triangle Index");
    }

    /**
     * Triangle value for interpolated color map mode 
     */
    TriFloatAttr &triangleValue() 
    {
      return _attributes.attrMap<Triangle, float>("Triangle Value");
    }

    /**
     * Return the colormap for the triangle values
     */
    ColorbVec &triangleValueColors()
    {
      return _attributes.attrMap<QString, ColorbVec>("Triangle Value Color Map")["Triangle Value Color Map"];
    }

    /**
     * Return the upper and lower bounds for the triangle value.
     */
    Point2f &triangleValueBounds()
    {
      AttrMap<QString, Point2f> &a = _attributes.attrMap<QString, Point2f>("Triangle Value Bounds");
      a.defaultVal() = Point2f(0,1);
      return a["Triangle Value Bounds"];
    }

    /**
     * Reference to the unit used for triangle values
     *
     * It is shown on the color bar.
     */
    QString &triangleValueUnit() 
    {
      return _attributes.attrMap<QString, QString>("Triangle Value Unit")["Triangle Value Unit"];
    }

    /**
     * Return the colormap for the triangle values
     */
    ColorbVec &triangleIndexColors()
    {
      return _attributes.attrMap<QString, ColorbVec>("Triangle Index Color Map")["Triangle Index Color Map"];
    }

    /**
     * Cell colors
     */
    CellVec2ColorbAttr &cellColor() 
    {
      return _attributes.attrMap<cell, Vec2Colorb>("Cell Color");
    }
    //@}
  
    //@{
    // Axis methods 

    /**
     * Set an axis color based on sign
     */
    bool setAxisColor(const Colorb &pos, const Colorb &neg, const SymmetricTensor &s, Vec3Colorb &color);

    /*
     * Returns the axis line width
     */
    float axisWidth() 
    {
      float width = _attributes.attrMap<QString, float>("Axis Width")["Axis Width"];
      if(width < 1.0)
        width = 1.0;
      return width;
    }

    /*
     * Set the axis line width
     */
    float setAxisWidth(float width) 
    {
      if(width < 1.0)
        width = 1.0;
      _attributes.attrMap<QString, float>("Axis Width")["Axis Width"] = width;
      return width;
    }

    /*
     * Returns the axis z-offset for drawing
     */
    float axisOffset() 
    {
      return _attributes.attrMap<QString, float>("Axis Offset")["Axis Offset"];
    }

    /*
     * Sets the axis z-offset for drawing
     */
    float setAxisOffset(float offset) 
    {
      _attributes.attrMap<QString, float>("Axis Offset")["Axis Offset"] = offset;
      return offset;
    }
    //@}
  
    //@{
    /**
     * Cell axis tensor quantity for each cell
     *
     * The tensors are encoded as three vectors: ev1, ev2, evals.  Where ev1 and ev2 are 
     * the two first eigenvectors and evals is the vector with the three eigenvalues.
     *
     * This map does not get drawn, but rather one populates cellAxisVis with the correct
     * scaling from this map.
     */
    IntSymTensorAttr &cellAxis() 
    {
      return _attributes.attrMap<int, SymmetricTensor>("Cell Axis");
    }
  
    /**
     * Cell axis for visualization 
     */
    IntMatrix3fAttr &cellAxisVis() 
    {
      return _attributes.attrMap<int, Matrix3f>("Cell Axis Vis");
    }

    /**
     * Returns the map from label to cells axis colors (array of 3 Point3f)
     */
    IntVec3ColorbAttr &cellAxisColor() 
    {
      return _attributes.attrMap<int, Vec3Colorb>("Cell Axis Color");
    } 

    /**
     * Set the cell axis color based on the sign for each eigenvalue
     */
    bool setCellAxisColor(const Colorb &pos, const Colorb &neg);

    /**
     * Return the type of the current cell axis.
     *
     * If an empty string, there is no cell axis.
     */
    QString cellAxisType()
    {
      return _attributes.attrMap<QString, QString>("Axis Type")["Axis Type"];
    }

    /**
     * Set the type of the current cell axis.
     *
     * If an empty string, there is no cell axis.
     */
    QString setCellAxisType(const QString &s) 
    {
      _attributes.attrMap<QString, QString>("Axis Type")["Axis Type"] = s;
      return s;
    }

    /**
     * Unit for the length of the cell axis
     */
    QString cellAxisUnit()
    {
      return _attributes.attrMap<QString, QString>("Axis Unit")["Axis Unit"];
    }

    /**
     * Unit for the length of the cell axis
     */
    QString setCellAxisUnit(const QString &s) 
    {
      _attributes.attrMap<QString, QString>("Axis Unit")["Axis Unit"] = s;
      return s;
    }

    /**
     * Remove any cell axis
     */
    void clearCellAxis();
		//@}
  
    //@{
    /**
     * Tensor quantity for each triangle
     *
     * The tensors are encoded as three vectors: ev1, ev2, evals.  Where ev1 and ev2 are 
     * the two first eigenvectors and evals is the vector with the three eigenvalues.
     *
     * This map does not get drawn, but rather one populates triangleAxisVis with the correct
     * scaling from this map.
     */
    TriSymTensorAttr &triangleAxis() 
    {
      return _attributes.attrMap<Triangle, SymmetricTensor>("Triangle Axis");
    } 
  
    /**
     * Cell axis for visualization 
     */
    TriMatrix3fAttr &triangleAxisVis() 
    {
      return _attributes.attrMap<Triangle, Matrix3f>("Triangle Axis Vis");
    }

    /**
     * Returns the map from label to cells axis colors (array of 3 Point3f)
     */
    TriVec3ColorbAttr &triangleAxisColor() 
    {
      return _attributes.attrMap<Triangle, Vec3Colorb>("Triangle Axis Color");
    }
    /**
     * Set the cell axis color based on the sign for each eigenvalue
     */
    bool setTriangleAxisColor(const Colorb &pos, const Colorb &neg);
    //@}

		//@{
    /**
     * Tensor quantity for each vertex
     *
     * The tensors are encoded as three vectors: ev1, ev2, evals.  Where ev1 and ev2 are 
     * the two first eigenvectors and evals is the vector with the three eigenvalues.
     *
     * This map does not get drawn, but rather one populates vertexAxisVis with the correct
     * scaling from this map.
     */
		typedef std::pair<vertex, SymmetricTensor> VtxSymTensorPair;

    VtxSymTensorAttr &vertexAxis() 
    {
      return _attributes.attrMap<vertex, SymmetricTensor>("Vertex Axis");
    } 
  
    /**
     * Cell axis for visualization 
     */
    VtxMatrix3fAttr &vertexAxisVis() 
    {
      return _attributes.attrMap<vertex, Matrix3f>("Vertex Axis Vis");
    }

    /**
     * Returns the map from label to cells axis colors (array of 3 Point3f)
     */
    VtxVec3ColorbAttr &vertexAxisColor() 
    {
      return _attributes.attrMap<vertex, Vec3Colorb>("Vertex Axis Color");
    }

    /**
     * Set the cell axis color based on the sign for each eigenvalue
     */
    bool setVertexAxisColor(const Colorb &pos, const Colorb &neg);

    /** 
     * Returns a reference to the map of correspondence between vertices in mesh1 
     * and mesh2 (store vertices positions)
     */
    IntMatrix3fMap &vvCorrespondence() 
    {
      return _VVCorrespondence;
    }                                                                    

    /*
		 * Returns a boolean for visualization of lines between corresponding vertices
     */
    bool &showVVCorrespondence() 
    {
      return _showVVCorrespondence;
    }                                                                
    //@}
  
    //@{
    /**
     * \name Signal methods. The signal can arise from a fluorescence intensity 
     * projection, a curvature projection, or from another process.
     *
     * These methods specifies the range and the units.
     */

    /**
     * Reference to the unit used for the signal.
     *
     * It is shown on the color bar.
     */
    QString &signalUnit() 
    {
      return _attributes.attrMap<QString, QString>("Vertex Signal Unit")["Vertex Signal Unit"];
    }

    /**
     * Reference to the upper and lower bounds for the signal.
     *
     * This defines the range for the color bar.
     */
    Point2f &signalBounds() 
    {      
      return _attributes.attrMap<QString, Point2f>("Vertex Signal Bounds")["Vertex Signal Bounds"];
    }
    //@}
  
    /**
     * Reference to the mesh bounding box
     */ 
    const BoundingBox3f &boundingBox() const 
    {
      return _bbox;
    }
    BoundingBox3f &boundingBox() 
    {
      return _bbox;
    }
    /**
     * Set the mesh bounding box
     */ 
    void setBoundingBox(const BoundingBox3f &bbox) 
    {
      _bbox = bbox;
    }
    /**
     * Update the bounding box from the mesh
     */ 
    void updateBBox();
    /**
     * Cell complex tab
     */
    int &ccTab()
    {
      return _ccTab;
    }
    /**
     * Current cell complex
     */
    QString &ccName()
    {
       return _ccName;
    }
    /**
     * Process use to to delete cells or vertices from different mesh types
     */
    QString &deleteProcessName(QString &meshType)
    {
      return _attributes.attrMap<QString, QString>("Delete Process Name")[meshType];
    }

    /**
     * Create the mesh from a triangle list
     */

    /**
     * This function creates a graph from a triangle soup.
     *
     * \note The graph will not be cleared, the triangles will be added to the
     * graph.
     *
     * \param S Graph that will be updated.
     * \param vertices List of vertices to insert in S, must be unique
     * \param triangles List of triplet of indices in \c vertices defining
     * triangles
     *
     * \returns true on success, false on failure
     *
     * \ingroup ProcessUtils
     */
    static bool meshFromTriangles(vvGraph &S, const std::vector<vertex> &vertices,
                                const std::vector<Point3i> &triangles, bool checkUnique = true);

    /**
      * Map vertex saveId to vertex
      */
    IntVtxMap &vMap() { return _vMap; }

    /**
      * Map cell saveId to cell
      */
    IntCellMap &cMap() { return _cMap; }

    /**
      * Read in vertices
      */
    bool readVertices(QIODevice &file, VtxVec &V, bool transform);

    /**
      * Read in vertex list
      */
    bool readVertexList(QIODevice &file, vvGraph &S);

    /**
      * Read in neighborhoods
      */
    bool readNhbds(QIODevice &file, vvGraph &S);

    /**
      * Read in a cellular mesh
      */
    bool readCellMesh(QIODevice &file, bool transform);

    /**
      * Read in a mesh
      */
    bool read(QIODevice &file, bool transform);

    /**
      * Write out vertices
      */
    bool writeVertices(QIODevice &file, const vvGraph &S, bool transform);

    /**
      * Write the vertex list
      */
    bool writeVertexList(QIODevice &file, const vvGraph &S);

    /**
      * Write out neighborhoods
      */
    bool writeNhbds(QIODevice &file, const vvGraph &S);

    /**
      * Write out a cellular mesh
      */
    bool writeCellMesh(QIODevice &file, bool transform);

    /**
     * Write out a mesh
     */
    bool write(QIODevice &file, bool transform);

    // Draw a cell
    //void drawCell(const cell &c);

    // Draw the nrmls
    //void drawNormals(double s);

    // Draw all the lines in the S graph
    //void drawGraph();
     
    // Draw the cell graph
    //void drawCellGraph()

    //// Do quad calculation for rendering of borders
    //double calcQuad(const vertex &c, const vertex &k, const vertex &l);
    // Draw a cell face
    //void drawCellFace(const cell &c);

    // Draw a cell border
    //void drawCellBorder(const cell &c);

    //Palette &palette; // color palette
    //int currLabel;
    //
  private:
    void init();
    void resetModified();
  
    CellTissue T; 
    Attributes _attributes;

    TransferFunction _surf_fct, _heat_fct;
    IntMatrix3fMap _VVCorrespondence;
    bool _showVVCorrespondence;
    IntIntSetMap _labelNeighbors;
    IntIntVIdSetMap _wallVId;
    bool changed_surf_function, changed_heat_function;
    int _changed;
    bool _culling, _blending;
    bool _showSurface, _showMesh, _showAxis;
    float _opacity, _brightness;
    SurfView _surfView;
    QString _surfVertexView, _surfTriangleView, _surfLabelView;
    QString _meshView, _axisView;
    bool _showMeshLines, _showMeshPoints, _showMeshCellMap;
		bool _useParents;
    bool _imgtex;
    QString _file;
    bool _scaled;
    bool _transformed;
    bool _showBBox;
    int _id;
    const Stack* _stack;
    QImage _image;
  
    BoundingBox3f _bbox;
    int _ccTab;
    QString _ccName;
    QString _deleteProcess;
 
    IntVtxMap _vMap; // Map vertex saveId to vertex
    IntCellMap _cMap; // Map cell saveId to vertex
  };
}

#endif 
