//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2015 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_PROCESS_MEASURES_HPP
#define MESH_PROCESS_MEASURES_HPP

#include <Process.hpp>
#include <Progress.hpp>
#include <Information.hpp>

#include <limits>

namespace mgx
{
  typedef std::pair<vertex, vertex> VertexPr;
  typedef std::set<vertex> Set;
  typedef std::pair<VertexPr, Set> VertexPrSet;
  //typedef std::pair<int, int> IntInt;


  class mgxBase_EXPORT MeasureSignal : public Process
  {

  public:
    MeasureSignal(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Signal/Signal Parameters");
      setDesc("Generate heat map based on signal for the current mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Type","Type of signal","Cell Total", QStringList() 
          << "Cell Total" << "Cell Border" << "Cell Interior" << "Cell Border/Total" << "Cell Interior/Total" << "Cell Border/Interior");	// 0
      addParm("Average","Count the signal average or total?","Yes",booleanChoice());
      addParm("Border Size","Size of the cell border","1.0");

	}

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat(), parm("Type"), stringToBool(parm("Average")), parm("Border Size").toDouble());

    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap, QString type, bool signalAvg, double borderSize);

  };

  class mgxBase_EXPORT MeasureSignalBorder : public Process
  {

  public:
    MeasureSignalBorder(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Signal/Signal Border");
      setDesc("Generate heat map based on signal close to the cell border for the current mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());

    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureSignalInterior : public Process
  {

  public:
    MeasureSignalInterior(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Signal/Signal Interior");
      setDesc("Generate heat map based on signal in the cell interior for the current mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());

    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureSignalTotal : public Process
  {

  public:
    MeasureSignalTotal(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Signal/Signal Total");
      setDesc("Generate heat map based on signal in the cells of the current mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());

    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureArea : public Process
  {
  public:
    MeasureArea(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Geometry/Area");
      setDesc("Computes area of cells on the mesh.");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    void calculateArea(vvGraph &S, IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());

    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasurePerimeter : public Process
  {
  public:
    MeasurePerimeter(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Geometry/Perimeter");
      setDesc("Computes the perimeter of cells on the mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    void calculatePerimeter(vvGraph& S, IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);
  };

  class mgxBase_EXPORT MeasureBending : public Process
  {
  public:
    MeasureBending(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/ToBeDeleted/Measures/Shape/Bending");
      setDesc("Computes bending of cells on the mesh.\n"
        "adds up the norm of the scalar product of the border segments.");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    void calculateBending(vvGraph &S, IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureStomatalBending : public Process
  {
  public:
    MeasureStomatalBending(const Process& process) : Process(process)
    {
	  setName("Mesh/Heat Map/ToBeDeleted/Measures/Shape/Common Bending");
      setDesc("Computes bending of a cell together with its closest neighbor on the mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	}

    void calculateStomatalBending(vvGraph& T, IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureAspectRatio : public Process
  {
  public:
    MeasureAspectRatio(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Geometry/Aspect Ratio");
      setDesc("Computes the ratio of the length of the major over the minor axis of\n"
              "the cells by using the PCA Shape Analysis 2D process in Cell Axis");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    void calculateAspectRatio(vvGraph& S, IntFloatAttr& heatMap);
    bool run(IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);
  };

  class mgxBase_EXPORT MeasureMajorAxis : public Process
  {
  public:
    MeasureMajorAxis(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Geometry/Length Major Axis");
      setDesc("Computes the length of the major axis of the cells by using the PCA Shape Analysis 2D process in Cell Axis");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run(IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };


  class mgxBase_EXPORT MeasureMinorAxis : public Process
  {
  public:
    MeasureMinorAxis(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Geometry/Length Minor Axis");
      setDesc("Computes the length of the minor axis of the cells by using the PCA Shape Analysis 2D process in Cell Axis");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run(IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureNeighbors : public Process
  {
  public:
    MeasureNeighbors(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Network/Neighbors");
      setDesc("Computes the number of neighbors of cells");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    void findNeighbourVertices(vvGraph& S, std::map<int, std::set<vertex> > &Nhbr);

    void calculateNeighbors(vvGraph& S, IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureMinRadius : public Process
  {
  public:
    MeasureMinRadius(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Geometry/Minimum Radius");
      setDesc("Computes the minimum distance from the cell center to the border");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureMaxRadius : public Process
  {
  public:
    MeasureMaxRadius(const Process& process) : Process(process)
    {
	  setName("Mesh/Heat Map/Measures/Geometry/Maximum Radius");
      setDesc("Computes the maximum distance from the cell center to the border");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureAvgRadius : public Process
  {
  public:
    MeasureAvgRadius(const Process& process) : Process(process)
    {
	  setName("Mesh/Heat Map/Measures/Geometry/Average Radius");
      setDesc("Computes the average distance from the cell center to the border");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureDistanceToMesh : public Process
  {
  public:
    MeasureDistanceToMesh(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Location/Distance to Mesh");
      setDesc("Computes the closest distance to the other mesh");
      setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *m = currentMesh();
      Mesh *m2 = mesh(1);
      if(m == m2)
        m2 = mesh(0);
      Stack *s1 = currentStack();
      Stack *s2 = stack(1);
      if(s1 == s2)
        s2 = stack(0);
      return run(s1, s2, m, m2, m->labelHeat());
    }

    bool run(const Stack *s1, const Stack *s2, Mesh* mesh, Mesh* m2, IntFloatAttr &data);

  };

  class mgxBase_EXPORT MeasureMajorAxisTheta : public Process
  {
  public:
    MeasureMajorAxisTheta(const Process& process) : Process(process)
    {
	  setName("Mesh/Heat Map/Measures/Location/Major Axis Theta");
      setDesc("Computes the angle between the major axis of a cell and a reference direction");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));

    addParm("Reference Direction","Reference Direction","X-Axis",
        QStringList() << "X-Axis" << "Y-Axis" << "Z-Axis" << "Custom X"<< "Custom Y"<< "Custom Z");
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      Stack *s1 = currentStack();
      return run(s1, mesh, mesh->labelHeat(), parm("Reference Direction"));
    }

    bool run(const Stack *s1, Mesh* mesh, IntFloatAttr& heatMap, QString refDir);

  };

  class mgxBase_EXPORT MeasureDistanceToBezier : public Process
  {
  public:
    MeasureDistanceToBezier(const Process& process) : Process(process)
    {
		setName("Mesh/Heat Map/Measures/Location/Distance to Bezier");
        setDesc("Computes for each cell the distance to a defined Bezier grid or line");
        setIcon(QIcon(":/images/MakeHeatMap.png"));

       addParm("Consider Orientation","Consider Orientation","Yes",booleanChoice());
       addParm("Reverse Orientation","Reverse Orientation","No",booleanChoice());
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      Stack *s1 = currentStack();
      return run(s1, mesh, mesh->labelHeat());
    }

    bool run(const Stack *s1, Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureBezierCoord : public Process
  {
  public:
    MeasureBezierCoord(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Location/Bezier Coord");
      setDesc("Computes for each cell centroid the nearest point on a Bezier grid or line and assigns it the Bezier coordinate");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Coordinate","Coordinate","X", QStringList() << "X" << "Y"); // 1
    }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      Stack *s1 = currentStack();
      return run(s1, mesh, parm("Coordinate"), mesh->labelHeat());
    }

    bool run(const Stack *s1, Mesh* mesh, QString bezCoord, IntFloatAttr& heatMap);
  };

  class mgxBase_EXPORT MeasureBezierLineCoord : public Process
  {
  public:
    MeasureBezierLineCoord(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Location/Bezier Line Coord");
      setDesc("Computes for each cell centroid the nearest point on a Bezier grid or line and assigns it the Bezier coordinate");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Reverse Line","Reverse Line","No", booleanChoice()); // 1
    }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      Stack *s1 = currentStack();
      return run(s1, mesh, stringToBool(parm("Reverse Line")), mesh->labelHeat());
    }

    bool run(const Stack *s1, Mesh* mesh, bool reverse, IntFloatAttr& heatMap);
  };



  class mgxBase_EXPORT MeasurePolarCoord : public Process
  {
  public:
    MeasurePolarCoord(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/Measures/Location/Polar Coord");
      setDesc("Computes a position of cells according to a defined polar coordinate system.\n"
        "This process writes all coordinates in attribute maps and shows the selected option as heat map.");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Central Axis","Central Axis","Z", QStringList() << "X" << "Y" << "Z"); // 1
      addParm("Coordinate","Coordinate","Longitudinal", QStringList() << "Longitudinal" << "Radial" << "Circumferential"); // 1
    }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      Stack *s1 = currentStack();
      return run(s1, mesh, parm("Central Axis"), parm("Coordinate"), mesh->labelHeat());
    }

    bool run(const Stack *s1, Mesh* mesh, QString axis, QString coord, IntFloatAttr& heatMap);
  };

  class mgxBase_EXPORT MeasureVariabilityRadius : public Process
  {
  public:
    MeasureVariabilityRadius(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/ToBeDeleted/Measures/Shape/Variability Radius");
      setDesc("Computes variability of radius of 2 similar cells on the mesh");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    void findCommonNeighbors(vvGraph& S, std::map<VertexPr, Set> &NhbrElem);

    void calculateVariabilityRadius(vvGraph& S, IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureCommonNhbrs : public Process
  {
  public:
    MeasureCommonNhbrs(const Process& process) : Process(process)
    {
	  setName("Mesh/Heat Map/ToBeDeleted/Measures/Shape/Common Neighbors");
      setDesc("Computes Common neighbors of 2 similar cells on the mesh");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    void calculateCommonNhbrs(vvGraph& S, IntFloatAttr& heatMap);

    void calculateClosestNhbr(vvGraph& S, std::set<VertexPr> &NeighbourMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };


  class mgxBase_EXPORT MeasureStomataArea : public Process
  {
  public:
    MeasureStomataArea(const Process& process) : Process(process)
    {
	  setName("Mesh/Heat Map/ToBeDeleted/Measures/Shape/Stomata Area");
      setDesc("Computes Common neighbors of 2 similar cells on the mesh");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    void calculateStomataArea(vvGraph& S, IntFloatAttr &heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr &heatMap);

  };

  class mgxBase_EXPORT MeasureNeighborhoodArea : public Process
  {
  public:
    MeasureNeighborhoodArea(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/ToBeDeleted/Measures/Neighborhood/Area");
      setDesc("Computes average area of neighborhood cells on the mesh");
	    setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr &heatMap);

  };

  class mgxBase_EXPORT MeasureNeighborhoodPerimeter : public Process
  {
  public:
    MeasureNeighborhoodPerimeter(const Process& process) : Process(process)
    {
	    setName("Mesh/Heat Map/ToBeDeleted/Measures/Neighborhood/Perimeter");
      setDesc("Computes average perimeter of neighborhood cells on the mesh");
	    setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr &heatMap);

  };

  class mgxBase_EXPORT MeasureNeighborhoodAspectRatio : public Process
  {
  public:
    MeasureNeighborhoodAspectRatio(const Process& process) : Process(process)
    {
	    setName("Mesh/Heat Map/ToBeDeleted/Measures/Neighborhood/Aspect Ratio");
      setDesc("Computes LenBr of cells on the mesh");
	    setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run(IntFloatAttr& heatMap);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureNeighborhoodNeighbors : public Process
  {
  public:
    MeasureNeighborhoodNeighbors(const Process& process) : Process(process)
    {
      setName("Mesh/Heat Map/ToBeDeleted/Measures/Neighborhood/Neighbors");
      setDesc("Computes neighbors of cells on the mesh");
	    setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureNeighborhoodVariabilityRadius : public Process
  {
  public:
    MeasureNeighborhoodVariabilityRadius(const Process& process) : Process(process)
    {
	    setName("Mesh/Heat Map/ToBeDeleted/Measures/Neighborhood/Variability Radius");
      setDesc("Computes variability of radius of 2 similar cells on the mesh");
	    setIcon(QIcon(":/images/MakeHeatMap.png"));
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, mesh->labelHeat());
    }

    bool run(Mesh* mesh, IntFloatAttr& heatMap);

  };

  class mgxBase_EXPORT MeasureCellDistance : public Process
  {
  public:
    MeasureCellDistance(const Process& process) : Process(process)
    {
	    setName("Mesh/Heat Map/Measures/Location/Cell Distance");
      setDesc("Computes the shortest path between selected cells and the remaining cells");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Wall Weights","Wall Weights","Euclidean", QStringList() << "1 / Wall Length" << "1" << "Euclidean");	// 0
      addParm("Restrict connectivity to same cell type", "Restrict connectivity to same cell type", "No", booleanChoice());
	  }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, parm("Wall Weights"), stringToBool(parm("Restrict connectivity to same cell type")), mesh->labelHeat());
    }

    bool run(Mesh* mesh, QString weight, bool cellTypes, IntFloatAttr &heatmap);

  };

  class mgxBase_EXPORT MeasureCellCoord : public Process
  {
  public:
    MeasureCellCoord(const Process& process) : Process(process)
    {
    setName("Mesh/Heat Map/Measures/Location/Cell Coordinate");
      setDesc("Computes the shortest path between selected cells and the remaining cells");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Dimension","Dimension","X", QStringList() << "X" << "Y" << "Z" << "Distance Origin"); // 0
    }

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      Stack* s = currentStack();
      return run(s, mesh, parm("Dimension"), mesh->labelHeat());
    }

    bool run(Stack* s, Mesh* mesh, QString dim, IntFloatAttr &heatmap);
  };



 /**
   * \class JunctionDistance
   *
   * JunctionDistance
   * 
   */
  class mgxBase_EXPORT JunctionDistance : public Process
  {
  public:
    JunctionDistance(const Process& process) : Process(process)
    {
	  	setName("Mesh/Heat Map/Measures/Geometry/Junction Distance");
      setDesc("Calculates the distance between junctions of a cell.");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Mode","Min or Max","Min", QStringList() << "Min" << "Max");
      addParm("Direct Junctions Only", 
          "Consider Only Direct Cell Junctions. If No then neighboring cell junctions will also be considered.", "No", booleanChoice());
      addParm("Ignore Border Cells","Heat values for border cells should be ignored for this Measure", "Yes", booleanChoice());
	  }

    bool run()
    {
      Mesh *m = currentMesh();
      return run(m, parm("Mode"), stringToBool(parm("Direct Junctions Only")), stringToBool(parm("Ignore Border Cells")), m->labelHeat());
    }

    bool run(Mesh *m, QString mode, bool onlyDirect, bool ignoreBorderCells, IntFloatAttr& heatMap);
  };
}

#endif
