#ifndef DIVISION_ANALYSIS_HPP
#define DIVISION_ANALYSIS_HPP

#include <Process.hpp>
#include <DivisionAnalysisData.hpp>
#include <CellDivision.hpp>

#include <DivisionAnalysisProcesses.hpp>

namespace mgx {


struct RootDivData{

  int label1, label2;
  double coordLong, coordRad, coordCirc;
  CellDivision dirLong, dirRad, dirCirc, dirReal;

};


  typedef std::pair<vertex,vertex> VtxVtx;

  DivisionAnalysisData dat;

  struct DivisionParms{

    public:

    QString primary, secondary;
    QString primaryDir, secondaryDir;

    bool perpendicular, perpendicularNeighbor, perpendicularConstrained, cuttingNeighborWall;

    int stepsCenter;
    double stepSizeCenter;
    int planeNr;

    std::set<Point3d> perpNeighborPlanes;
    std::unordered_map<Point3d, std::vector<Point3d> > perpNeighborWalls;

  };

 /**
   * \class DisplayCellGraph DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DisplayCellGraph
   * TBD
   */
class DisplayCellGraph : public Process
  {
    public:
      DisplayCellGraph(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Cell Graph Display");
		setDesc("Creates the cell connectivity graph from the active MGX3D mesh and saves it into the non-active mesh.\n"
        "not really needed anymore since there is now the display option in Main/Mesh");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Min Shared Area","","0.001");
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, parm("Min Shared Area").toDouble());
      }
      bool run(Mesh *m, Mesh *m2, double minArea);

  };


 /**
   * \class DisplayCellGraph DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DisplayCellGraph
   * TBD
   */
class DisplayCellGraph2D : public Process
  {
    public:
      DisplayCellGraph2D(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Tools/Cell Graph Display 2D");
    setDesc("Creates the cell connectivity graph from the active MGX3D mesh and saves it into the non-active mesh.\n"
        "not really needed anymore since there is now the display option in Main/Mesh");
    setIcon(QIcon(":/images/CellDivide.png"));

    addParm("Min Shared Area","","0.001");
    }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, parm("Min Shared Area").toDouble());
      }
      bool run(Mesh *m, Mesh *m2, double minArea);

  };

 /**
   * \class DisplayCellGraph DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DisplayCellGraph
   * TBD
   */
class DisplayCellGraph3D : public Process
  {
    public:
      DisplayCellGraph3D(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Tools/Cell Graph Display 3D");
    setDesc("Creates the cell connectivity graph from the active MGX3D mesh and saves it into the non-active mesh.\n"
        "not really needed anymore since there is now the display option in Main/Mesh");
    setIcon(QIcon(":/images/CellDivide.png"));

    addParm("Min Shared Area","","0.001");
    }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, parm("Min Shared Area").toDouble());
      }
      bool run(Mesh *m, Mesh *m2, double minArea);

  };

   /**
   * \class DivideCell3DMGX3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DivideCell3DMGX3D
   * TODO: Implement MGXM version!
   * Divide a cell along a specified direction through the cell center
   */
  class DivideCell3DMGX3D : public Process
  {
    public:
      DivideCell3DMGX3D(const Process& process) : Process(process)
      {

		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Divide Cell MGX3D");
		setDesc("Divide a cell along a specified direction through the cell center.\n"
        " WARNING: not 100 percent bug-free. sometimes chrashes or results in a broken mesh");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Label","Label","1");
		addParm("Division Alg","","predefined direction", QStringList() << "shortest wall" << "random direction" << "predefined direction");
		addParm("Custom X","Custom X","1.0");
		addParm("Custom Y","Custom Y","0.0");
		addParm("Custom Z","Custom Z","0.0");
		addParm("Center Displacement" ,"Center Displacement","0.0");
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, parm("Label").toInt(), parm("Division Alg"), parm("Custom X").toDouble(), parm("Custom Y").toDouble(), parm("Custom Z").toDouble(),
          parm("Center Displacement").toDouble()/*, stringToBool(parms[6])*//*, parms[7]*/);
      }
      bool run(Mesh *m, int label, QString division, double x, double y, double z,
        double displacement/*, bool newM*//*, QString fragmentHandling*/);

  };

 /**
   * \class TestDivisionPlanes DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * TestDivisionPlanes
   * Central division analysis process that simulate cell divisions
   */
     class TestDivisionPlanes : public Process
  {
    public:
      TestDivisionPlanes(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/B Cell Division Analysis");
		setDesc("Central division analysis process that simulate cell divisions using multiple division \n"
		"planes on a cell before the division has ocurred or on two neighobring cells after the division. \n"
		"Calculates properties of possible divisions such as division plane area and volume of the daughter cells");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Label Cell 1","Label of cell to be tested","1");	// 0
		addParm("Label Cell 2 (optional)","Label of neighbor cell to be tested (after the actual division has occurred)","0");	// 1
		addParm("Test Division Planes","Approximate number of division planes that will be tested","1000");	// 2
		addParm("Perpendicular To Surface","Perpendicular To Surface","No",booleanChoice());	// 3
		addParm("Perpendicular To Low Degree Neighbor Wall","Enforce that the wall is perpendicular to a neighbor cell with the lowest number of neighbors. constrained/cutting wall means that the division plane has to cut this wall.","No", QStringList() << "Yes (constrained)" << "Yes" << "No" << "No (but cutting wall)");	// 4
		addParm("Steps Center Variance","Steps Center Variance","0");	// 5
		addParm("Stepsize Center Variance","Stepsize Center Variance","1.0");	// 6
		addParm("Display Result","Display Result","Yes",booleanChoice());	// 7
		addParm("Save Result To File","Save Result To File","");	// 8
		addParm("Weights Cell Graph","Weights Cell Graph","no weights", QStringList() << "no weights" << "no weights (dijkstra)" << "1/wallArea");	// 9
		addParm("GPU","GPU","0");	// 10
		addParm("Calc Betw","Calc Betw","No",booleanChoice());	// 11
		addParm("Division Point","Division Point","Centroid",QStringList() << "Centroid" << "Center of Actual" << "Manual");	// 12
	  }

      DivisionAnalysisData datTest;

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);

        bool constWeight = parm("Weights Cell Graph") == "1/wallArea" ? false : true;
        bool dijk = parm("Weights Cell Graph") == "no weights" ? false : true;

        bool perpendicularNeighbor =  (parm("Perpendicular To Low Degree Neighbor Wall") == "No" or parm("Perpendicular To Low Degree Neighbor Wall") == "No (but cutting wall)") ? false : true;
        bool perpendicularConstrained =  parm("Perpendicular To Low Degree Neighbor Wall") == "Yes (constrained)" ? true : false;
        bool cuttingNeighborWall = parm("Perpendicular To Low Degree Neighbor Wall") == "No (but cutting wall)" ? true : false;

        DivisionParms p;

        p.perpendicularNeighbor = perpendicularNeighbor;
        p.perpendicularConstrained = perpendicularConstrained;
        p.cuttingNeighborWall = cuttingNeighborWall;
        p.perpendicular = stringToBool(parm("Test Division Planes"));


        p.stepsCenter = parm("Steps Center Variance").toInt();
        p.stepSizeCenter = parm("Stepsize Center Variance").toDouble();

        p.planeNr = parm("Test Division Planes").toInt();

        return run(m, m2, p, parm("Label Cell 1").toInt(), parm("Label Cell 2 (optional)").toInt(),
          stringToBool(parm("Display Result")), parm("Save Result To File"), constWeight, dijk, parm("GPU").toInt(),
          stringToBool(parm("Calc Betw")), parm("Division Point"));

      }
      bool run(Mesh *m, Mesh *m2, int label1, int label2, int divPlanes, bool perpendicular, bool perpendicularNeighbor, int cellCenterVarSteps,
        double cellCenterVarStepSize, bool displayResult, QString filename, bool constWeight, bool dijk, int percGPU, bool calcBetw,
        QString cellCenterSelVertex, bool perpendicularConstrained, bool cuttingNeighborWall);

      bool run(Mesh *m, Mesh *m2, DivisionParms& par, int label1, int label2,
        bool displayResult, QString filename, bool constWeight, bool dijk, int percGPU, bool calcBetw, QString cellCenterSelVertex);


      //bool testDivisionPlanesFunc(Mesh *mesh, Mesh *mesh2, int label, int divPlanes, bool perpendicular, bool perpendicularNeighbor,
      //  int cellCenterVarSteps, double cellCenterVarStepSize, bool displayResult, QString filename, bool constWeight, bool dijk,
      //  int percGPU, bool calcBetw, bool overwrite, bool cellCenterSelVertex, bool perpendicularConstrained,
      //  bool cuttingNeighborWall, Point3d divisionPoint = Point3d(0,0,0), DivisionParms& par);

      bool testDivisionPlanesFunc(Mesh *mesh, Mesh *mesh2, int label, bool displayResult, QString filename, bool constWeight, bool dijk,
        int percGPU, bool calcBetw, bool overwrite, QString cellCenterSelVertex, DivisionParms& par, Point3d divisionPoint = Point3d(0,0,0));

  };
 /**
   * \class TestDivisionPlanesCellAtlas DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * TestDivisionPlanesCellAtlas
   * TBD
   */
     class TestDivisionPlanesCellAtlas : public Process
  {
    public:
      TestDivisionPlanesCellAtlas(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Processes Cell Atlas/Test Cell Atlas Division Planes");
		setDesc("TBD");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Label 1","Label of cell to be tested","1");	// 0
		addParm("Label 2","Label of cell to be tested","2");	// 1
		addParm("Display Result","Display Result","Yes",booleanChoice());	// 2

		  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);

        RootDivData result;

        return run(m, m2, parm("Label 1").toInt(), parm("Label 2").toInt(), stringToBool(parm("Display Result")), result, true);
      }

      bool run(Mesh *m, Mesh *m2, int label1, int label2, bool displayResult, RootDivData& result, bool copyToM2);

  };
 /**
   * \class RootDivisionAnalysis DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * RootDivisionAnalysis
   * TBD
   */
     class RootDivisionAnalysis : public Process
  {
    public:
      RootDivisionAnalysis(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Processes Cell Atlas/Root Division Analysis");
		setDesc("TBD");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Display Result","Display Result","Yes",booleanChoice());	// 0
		addParm("Output File", "Output File","");	// 1

		   }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);

        return run(m, m2, stringToBool(parm("Display Result")), parm("Output File"));
      }

      bool run(Mesh *m, Mesh *m2, bool displayResult, QString filename);

  };

 /**
   * \class DivisionAnalysisMulti3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DivisionAnalysisMulti3D
   * TBD
   */
     class DivisionAnalysisMulti3DOld : public Process
  {
    public:
      DivisionAnalysisMulti3DOld(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Division Analysis Multi");
		setDesc("TBD");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Test Single","Test Single","No",booleanChoice());	// 0
		addParm("Test Double","Test Double","Yes",booleanChoice());	// 1
    addParm("Use Stack","Use Stack","Yes",booleanChoice()); // 1
		addParm("Display Shortest","Display Shortest","Yes",booleanChoice());	// 2
		addParm("Display Actual","Display Actual","Yes",booleanChoice());	// 3
	  }

      bool run()
      {
        Stack* s1 = currentStack();
        Store* store1 = s1->currentStore();

        Mesh *m = currentMesh();
        Mesh *m2 = otherMesh();
        return run(s1, store1, m, m2,stringToBool(parm("Test Single")),stringToBool(parm("Test Double")),
          stringToBool(parm("Use Stack")), stringToBool(parm("Display Shortest")), stringToBool(parm("Display Actual")));
      }

      bool run(Stack* s1, Store* s, Mesh *m, Mesh *m2, bool singleCells, bool doubleCells, bool useStack, bool displayShortest, bool displayActual);

  };

 // /**
 //   * \class DivisionAnalysisMulti DivisionAnalysis.hpp <DivisionAnalysis.hpp>
 //   *
 //   * DivisionAnalysisMulti
 //   * TBD
 //   */
 //     class DivisionAnalysisMulti : public Process
 //  {
 //    public:
 //      DivisionAnalysisMulti(const Process& process) : Process(process)
 //      {
	// 	setName("Mesh/Division Analysis/Analysis 3D/Division Analysis Multi");
	// 	setDesc("TBD");
	// 	setIcon(QIcon(":/images/CellDivide.png"));

	// 	addParm("Test Single","Test Single","No",booleanChoice());	// 0
	// 	addParm("Test Double","Test Double","Yes",booleanChoice());	// 1
	// 	addParm("Display Shortest","Display Shortest","Yes",booleanChoice());	// 2
	// 	addParm("Display Actual","Display Actual","Yes",booleanChoice());	// 3
	// 	addParm("Output File","Output File","");	// 4
	//   }

 //      bool run()
 //      {
 //        Mesh *m = currentMesh();
 //        Mesh *m2;
 //        if(currentMesh() == mesh(0))
 //          m2 = mesh(1);
 //        else
 //          m2 = mesh(0);

 //        return run(m, m2, stringToBool(parm("Test Single")), stringToBool(parm("Test Double")), stringToBool(parm("Display Shortest")), parm("Display Actual"));
 //      }

 //      bool run(Mesh *m, Mesh *m2, bool runPre, bool runPost, bool displayResult, QString filename);

 //  };

 /**
   * \class FlatDivisionPlane DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * FlatDivisionPlane
   * Display a planar approximation plane of a wall between two cells
   */
   class FlatDivisionPlane : public Process
  {
    public:
      FlatDivisionPlane(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Division Plane Approximation");
		setDesc("Display a planar approximation plane of a wall between two cells");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Label 1","Label 1","1");	// 0
		addParm("Label 2","Label 2","2");	// 1
		addParm("Display","Overwrite the non-active mesh and display the plane","No",booleanChoice());	// 2
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        CellDivisionAttr cda;
        return run(m, m2, parm("Label 1").toInt(), parm("Label 2").toInt(), stringToBool(parm("Display")), dat, cda);
      }

      bool run(Mesh *m, Mesh *m2, int label1, int label2, bool display, DivisionAnalysisData &dat, CellDivisionAttr &cdaExp);

  };


 /**
   * \class ActualPlaneStack DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * ActualPlaneStack
   * ***DESCRIPTION NEEDED***
   */
   class ActualPlaneStack : public Process
  {
    public:
      ActualPlaneStack(const Process& process) : Process(process)
      {
      setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Division Plane Actual Stack");
      setDesc("Display a planar approximation plane of a wall between two cells");
      setIcon(QIcon(":/images/CellDivide.png"));

      addParm("Label 1","Label 1","1"); // 0
      addParm("Label 2","Label 2","2"); // 1
      addParm("Display","Overwrite the non-active mesh and display the plane","No",booleanChoice());  // 2
      }

    bool run()
      {
        Stack* s1 = currentStack();
        Store* store1 = s1->currentStore();

        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        CellDivisionAttr cda;
        return run(s1, store1, m, m2, parm("Label 1").toInt(), parm("Label 2").toInt(),
                   stringToBool(parm("Display")), dat, cda);
      }
      bool run(Stack* s1, Store* s, Mesh *m, Mesh *m2, int label1, int label2, bool display, DivisionAnalysisData &dat, CellDivisionAttr &cdaExp);
  };



 /**
   * \class AnalyzeSurface DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * AnalyzeSurface
   * Pre Analysis of the mesh to calculate optional data such as direction to surface, nearest surface pont and betweenness measures
   */
  class AnalyzeSurface : public Process
  {
    public:
      AnalyzeSurface(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/A Pre Analysis");
		setDesc("Requires a MGX3D mesh in the active mesh and a surface mesh in the non-active mesh \n"
		"Also can calculate the betweenness measure (visualize with Tools/Cell Data Heatmap)");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Calc Betweenness Centrality","Calc Betweenness Centrality","No", QStringList() << "No" << "Yes - no weights" << "Yes - 1/wallArea");	// 0
		addParm("Calc Current Flow Betweenness","Calc Current Flow Betweenness","No", QStringList() << "No" << "Yes - no weights" << "Yes - 1/wallArea" << "Yes - no weights (GPU)" << "Yes - 1/wallArea (GPU)");
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
/*
        bool betw = parms[0] == "No" ? false : true;
        bool weights = parms[0] == "Yes - 1/wallArea" ? true : false;

        bool currentFlow = parms[1] == "No" ? false : true;
        bool weightsCur = parms[1] == "Yes - 1/wallArea" or parms[1] == "Yes - 1/wallArea (GPU)" ? true : false;

        bool useGPU = parms[1] == "Yes - no weights (GPU)" or parms[1] == "Yes - 1/wallArea (GPU)" ? true : false;
*/
        return run(m, m2, dat);
      }

      bool run(Mesh *m, Mesh *m2, DivisionAnalysisData &dat);

  };

 // /**
 //   * \class DisplayHeatMaps DivisionAnalysis.hpp <DivisionAnalysis.hpp>
 //   *
 //   * DisplayHeatMaps
 //   * Displays measures of the Pre Analysis
 //   */
 //   class DisplayHeatMaps : public Process
 //  {
 //    public:
 //      DisplayHeatMaps(const Process& process) : Process(process) { }

 //      bool run(const QStringList& parms){
 //        return run(parms[0]);
 //      }
 //      bool run(QString choice);

 //      QStringList parmNames() const { return QStringList() << "Data"; }

 //      QStringList parmDefaults() const { return QStringList() << "Betweenness Centrality"; }

 //      ParmChoiceMap parmChoice() const
 //      {
 //        ParmChoiceMap map;
 //        map[0] = QStringList() << "Betweenness Centrality" << "Current Flow Betweenness";
 //        return map;
 //      }

 //      QString name() const { return "Mesh/Division Analysis/Tools/Cell Data Heatmap"; }
 //      QString description() const { return "Displays cell properties as a heatmap.\n"
 //        "\n"
 //        "Requires analyzed or loaded data in the memory (Pre Analysis Process)."; }

 //      QIcon icon() const { return QIcon(":/images/CellAtlas.png"); }

 //  };





 /**
   * \class SetDivisionPoint DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * SetDivisionPoint
   * 2D process
   */
  class SetDivisionPoint : public Process
  {
    public:
      SetDivisionPoint(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Set Division Point");
		setDesc("Set a custom division point (select exactly one vertex)");
		setIcon(QIcon(":/images/CellDivide.png"));
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);

  };

 /**
   * \class DisplayOptimalPlanes DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DisplayOptimalPlanes
   * Displays planes of the Division analysis processes
   */
  class DisplayOptimalPlanes : public Process
  {
    public:
      DisplayOptimalPlanes(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Display Optimal Planes Advanced");
		setDesc("Displays planes of the Division analysis processes");
	    setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Custom","Custom","No",booleanChoice());	// 0
		addParm("Primary Criteria","Primary Optimization Criteria","Wall Area", QStringList() << "Wall Area" << "Volume Ratio" << "Betweenness Centrality" << "Random Walk Betweenness" << "Neighbor Count");	// 1
		addParm("Direction Primary Criteria","Direction Primary Criteria","Min", QStringList() << "Min" << "Max");	// 2
		addParm("Secondary Criteria","Secondary Optimization Criteria","Volume Ratio", QStringList() << "None" << "Wall Area" << "Volume Ratio" << "Betweenness Centrality" << "Random Walk Betweenness" << "Neighbor Count");	// 3
		addParm("Direction Secondary Criteria","Direction Secondary Criteria","Min", QStringList() << "Min" << "Max" << "Random");	// 4
		addParm("Tolerance","Tolerance","0.01");	// 5
		addParm("Max Planes","Max Planes","100");	// 6
		addParm("Reset Mesh","Reset Mesh","Yes",booleanChoice());	// 7
		addParm("Max Plane Similarity","Max Plane Similarity","100.0");	// 8
		addParm("Plane Size","Plane Size","10.0");	// 9
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, stringToBool(parm("Custom")), parm("Primary Criteria"), parm("Secondary Criteria"), parm("Direction Primary Criteria"), parm("Direction Secondary Criteria"), dat, parm("Tolerance").toDouble(), parm("Max Planes").toInt(), stringToBool(parm("Reset Mesh")), parm("Max Plane Similarity").toDouble(), parm("Plane Size").toDouble());
      }

      bool run(Mesh *m, Mesh *m2, bool custom, QString primary, QString secondary, QString primaryDir, QString secondaryDir,
        DivisionAnalysisData &dat, double tolerance, int maxPlanes, bool resetM2, double locMinSens, double planeSize);

  };


 /**
   * \class DisplayOptimalPlanesSimple DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DisplayOptimalPlanesSimple
   * Easy-to-use process to get the best planes dasiplyed accoring to the specified division rule
   */
  class DisplayOptimalPlanesSimple : public Process
  {
    public:
      DisplayOptimalPlanesSimple(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Display Optimal Planes");
		setDesc("Displays planes of the Division analysis processes");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Division Rule","Division Rule","Shortest Wall", QStringList() << "Shortest Wall" << "Best Volume Ratio" << "Longest Wall");	// 0
		addParm("Max Distance to Optimum","Max Distance to Optimum","0.1");	// 1
		addParm("Max Number of Planes","Max Number of Planes","10");	// 2
		addParm("Max Plane Similarity","Highest allowed similarity between two showed planes. Is the norm of the scalar product of their normals (if plane position is identical)","0.99");	// 3
		addParm("Plane Size","Plane Size","10.0");	// 4
		addParm("Reset Planes","Reset Planes","Yes",booleanChoice());	// 5
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, parm("Division Rule"), parm("Max Distance to Optimum").toDouble(), parm("Max Number of Planes").toInt(), parm("Max Plane Similarity").toDouble(), parm("Plane Size").toDouble(), stringToBool(parm("Reset Planes")));
      }

      bool run(Mesh *m, Mesh *m2, QString divRule, double maxDis, int maxPlanes, double planeSim, double planeSize, bool resetMesh);

  };


 /**
   * \class DisplayAllPlanes DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * DisplayAllPlanes
   * Displays all analyzed planes (Debug purposes)
   */
  class DisplayAllPlanes : public Process
  {
    public:
      DisplayAllPlanes(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/To Revise/Display All Planes");
		setDesc("TBD");
		setIcon(QIcon(":/images/CellDivide.png"));
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2);
      }

      bool run(Mesh *m, Mesh *m2);

  };

 /**
   * \class AnalysisDivPlanes DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * AnalysisDivPlanes
   * Displays planes
   */
  class AnalysisDivPlanes : public Process
  {
    public:
      AnalysisDivPlanes(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Draw Division Planes");
		setDesc("TBD");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Flat Plane","Flat Plane","Yes",booleanChoice());	// 0
		addParm("Shortest","Shortest","Yes",booleanChoice());	// 1
		addParm("Shortest Best","Shortest Best","Yes",booleanChoice());	// 2
		addParm("Shortest Wall","Shortest Wall","Yes",booleanChoice());	// 3
		addParm("Shortest Best Betw Centr","Shortest Best Betw Centr","No",booleanChoice());	// 4
		addParm("Shortest Best Rand Walk Betw","Shortest Best Rand Walk Betw","No",booleanChoice());	// 5
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, stringToBool(parm("Flat Plane")), stringToBool(parm("Shortest")), stringToBool(parm("Shortest Best")), dat);
      }

      bool run(Mesh *m, Mesh *m2, bool flat, bool shortest, bool shortestBest, DivisionAnalysisData &dat);

  };

 /**
   * \class SaveCellGraph DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * SaveCellGraph
   * Save the cell graph to a file
   */
  // class SaveCellGraph : public Process
  // {
  //   public:
  //     SaveCellGraph(const Process& process) : Process(process)
  //     {
		// setName("Mesh/Division Analysis/Tools/Cell Graph Save MGX3D");
		// setDesc("Save the cell (neighborhood) graph to a file in the format cell1 cell2 sharedWallArea");
		// setIcon(QIcon(":/images/CellDivide.png"));

		// addParm("filename","Name of file to be saved","");	// 0
		// addParm("Min Shared Area","Min shared wall area to be considered a neighbor","0.001");	// 1
	 //  }

  //     bool initialize(QWidget* parent);

  //     bool run()
  //     {
  //       Mesh *m = currentMesh();
  //       //Mesh *m2 = mesh(0);
  //       //if(currentMesh() == mesh(0))
  //       //  m2 = mesh(1);
  //       return run(m, parm("filename"), parm("Min Shared Area").toDouble());
  //     }

  //     bool run(Mesh *m, QString filename, double minArea);

  // };

 /**
   * \class JoinCellsMGX3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * JoinCellsMGX3D
   * Join 2 neighboring 3D cells
   */
  class JoinCellsMGX3D : public Process
  {
    public:
      JoinCellsMGX3D(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Mesh/Tools 3D/Merge Cells MGX3D");
		setDesc("Join specified cells of a MGX3D mesh \n"
		"Common triangles will be deleted.");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Cell 1","Label of cell 1","1");	// 0
		addParm("Cell 2","Label of cell 2","2");	// 1

		  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, parm("Cell 1").toInt(), parm("Cell 2").toInt());
      }

      bool run(Mesh *m, int label1, int label2);

  };


 /**
   * \class JoinCellsMGX3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * JoinCellsMGX3D
   * Join 2 neighboring 3D cells
   */
  class MergeCellsMGXM3D : public Process
  {
    public:
      MergeCellsMGXM3D(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Mesh/Tools 3D/Merge 3D Cells");
		setDesc("Join specified cells of a standard 3D mesh \n"
		"Common triangles will be deleted. \n"
		"Cells can be specified by parameter or selection (if parameters are -1) \n"
		"Note that depending on the mesh structure errors like holes or missing triangles might occur.");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Cell 1","Label of cell 1","-1");	// 0
		addParm("Cell 2","Label of cell 2","-1");	// 1
		addParm("Force Merge","If No: Abort merge if unexpected errors occur.","No",booleanChoice());	// 2
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, parm("Cell 1").toInt(), parm("Cell 2").toInt(), stringToBool(parm("Force Merge")));
      }

      bool run(Mesh *m, int label1, int label2, bool forceMerge);

  };


//  /**
//    * \class JoinCellsMGX2D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
//    *
//    * JoinCellsMGX2D
//    * Join the cells
//    */
// class JoinCellsMGX2D : public Process
//   {
//     public:
//       JoinCellsMGX2D(const Process& process) : Process(process) { }

//       bool run(const QStringList &parms)
//       {
//         Mesh *m = currentMesh();
//         return run(m, parms[0].toInt(), parms[1].toInt());
//       }
//       bool run(Mesh *m, int label1, int label2);

//       QStringList parmNames() const { return QStringList() << "Cell 1" << "Cell 2"; }
//       QStringList parmDefaults() const { return QStringList() << "1" << "2"; }
//       QStringList parmDescs() const { return QStringList() << "Label of cell 1" << "Label of cell 2"; }
//       QString name() const { return "Mesh/Division Analysis/Test/Join Cells MGX2D"; }
//       QString description() const { return "Join specified cells of a MGX2D mesh\n"
//         "\n"
//         "Common vertices will be deleted"; }

//       QIcon icon() const { return QIcon(":/images/CellDivide.png"); }

//       ParmChoiceMap parmChoice() const {
//         ParmChoiceMap map;
//         return map;
//       }

//   };


 /**
   * \class OutsideCellWall DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * OutsideCellWall
   * Creates a heat map of the ratio of the outside cell wall area to the total cell wall area
   */
  class OutsideCellWall : public Process
  {
    public:
      OutsideCellWall(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/To Test/Outside Cell Wall");
		setDesc("Creates a heat map of the ratio of the outside cell wall area to the total cell wall area");
		setIcon(QIcon(":/images/CellDivide.png"));
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);

  };

 /**
   * \class CreateJunctionGraph DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * CreateJunctionGraph
   * Creates a junction graph from a MGX3D mesh (junctions are nodes and cell walls are edges)
   */
  class CreateJunctionGraph : public Process
  {
    public:
      CreateJunctionGraph(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Junction Graph Stack Display");
		setDesc("Creates a junction graph from a stack (junctions are nodes and cell walls are edges)");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Save to file","Save to file","");	// 0
		addParm("Create graph in active mesh","Create graph in active mesh","Yes",booleanChoice());	// 1
		addParm("Create mesh in inactive mesh","Create mesh in inactive mesh","No",booleanChoice());	// 2
	  }

      bool initialize(QWidget* parent);

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(mesh(0) == currentMesh())
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, parm("Save to file"), stringToBool(parm("Create graph in active mesh")), stringToBool(parm("Create mesh in inactive mesh")));
      }

      bool run(Mesh *m, Mesh *m2, QString filename, bool createGraph, bool createMesh);

  };

 /**
   * \class CreateJunctionGraphStack DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * CreateJunctionGraphStack
   * Creates a junction graph from a stack (junctions are nodes and cell walls are edges)
   */
  class CreateJunctionGraphStack : public Process
  {
    public:
      CreateJunctionGraphStack(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Junction Graph Stack Display");
		setDesc("Creates a junction graph from a stack (junctions are nodes and cell walls are edges)");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Save to file","Save to file","");	// 0
		addParm("Create graph in active mesh","Create graph in active mesh","Yes",booleanChoice());	// 1
		addParm("Create mesh in inactive mesh","Create mesh in inactive mesh","No",booleanChoice());	// 2
	  }

      bool initialize(QWidget* parent);

      bool run()
      {

        const Stack* stack = currentStack();
        Mesh *m = currentMesh();
        Mesh *m2;
        if(mesh(0) == currentMesh())
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(stack, m, m2, parm("Save to file"), stringToBool(parm("Create graph in active mesh")), stringToBool(parm("Create mesh in inactive mesh")));
      }

      bool run(const Stack* s, Mesh *m, Mesh *m2, QString filename, bool createGraph, bool createMesh);

  };

 /**
   * \class OrganDivisionSimulation DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * OrganDivisionSimulation
   * Simulates a dividing tissue by performing a division plane testing and dividing according to the specified criteria of cells with a parent label > 0.
   */
  class OrganDivisionSimulation : public Process
  {
    public:
      OrganDivisionSimulation(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/MGX3D/Organ Division Simulation");
		setDesc("Simulates a dividing tissue by performing a division plane testing and dividing \n"
		"according to the specified criteria of cells with a parent label > 0.");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Division Order Criteria","Criteria determining the order the cells divide","Neighbor Count Max", QStringList() << "Neighbor Count Max" << "Parent Label Min");	// 0
		addParm("Primary Criteria","Primary Criteria","Wall Area", QStringList() << "Wall Area" << "Volume Ratio" << "Betweenness Centrality" << "Betweenness Centrality (weighted)" << "Random Walk Betweenness" << "Random Walk Betweenness (weighted)" << "Neighbor Count");	// 1
		addParm("Direction Primary Criteria","Direction Primary Criteria","Min", QStringList() << "Min" << "Max" << "Random");	// 2
		addParm("Secondary Criteria","Secondary Criteria","None", QStringList() << "None" << "Wall Area" << "Volume Ratio" << "Betweenness Centrality" << "Betweenness Centrality (weighted)" << "Random Walk Betweenness" << "Random Walk Betweenness (weighted)" << "Neighbor Count");	// 3
		addParm("Direction Secondary Criteria","Direction Secondary Criteria","Random", QStringList() << "Min" << "Max" << "Random");	// 4
		addParm("Tolerance","Tolerance","0.01");	// 5
		addParm("Div Planes","Div Planes","1000");	// 6
		addParm("Perpendicular To Surface","Perpendicular To Surface","No",booleanChoice());	// 7
		addParm("Perpendicular To Low Degree Neighbor Wall","Perpendicular To Low Degree Neighbor Wall","No", QStringList() << "Yes (constrained)" << "Yes" << "No" << "No (but cutting wall)");	// 8
		addParm("Steps Center","Steps Center","0");	// 9
		addParm("Stepsize Center","Stepsize Center","0.0");	// 10
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);

        //bool perpendicularNeighbor =
        //bool perpendicularConstrained =  parms[8] == "Yes (constrained)" ? true : false;
        //bool cuttingNeighborWall = parms[8] == "No (but cutting wall)" ? true : false;

        DivisionParms p;

        p.perpendicular = stringToBool(parm("Perpendicular To Surface"));

        p.perpendicularNeighbor = (parm("Perpendicular To Low Degree Neighbor Wall") == "No" or parm("Perpendicular To Low Degree Neighbor Wall") == "No (but cutting wall)") ? false : true;
        p.perpendicularConstrained = parm("Perpendicular To Low Degree Neighbor Wall") == "Yes (constrained)" ? true : false;
        p.cuttingNeighborWall = parm("Perpendicular To Low Degree Neighbor Wall") == "No (but cutting wall)" ? true : false;

        p.primary = parm("Primary Criteria");
        p.primaryDir = parm("Direction Primary Criteria");

        p.secondary = parm("Secondary Criteria");
        p.secondaryDir = parm("Direction Secondary Criteria");

        p.stepsCenter = parm("Steps Center").toInt();
        p.stepSizeCenter = parm("Stepsize Center").toDouble();

        p.planeNr = parm("Div Planes").toInt();

        //return run(m, m2, parms[0], parms[1], parms[3], parms[2], parms[4],
        //  parms[5].toDouble(), parms[6].toInt(), stringToBool(parms[7]), p.perpendicularNeighbor,
        //  parms[9].toInt(), parms[10].toDouble(), p.perpendicularConstrained, p.cuttingNeighborWall);
        return run(m, m2, parm("Division Order Criteria"), p, parm("Tolerance").toDouble());
      }
      //bool run(Mesh *m, Mesh *m2, QString order, QString primary, QString secondary, QString primaryDir, QString secondaryDir,
      //  double tolerance, int planeNr, bool perpendicular, bool perpendicularNeighbor, int stepsCenter, double stepSizeCenter,
      //  bool perpendicularConstrained, bool cuttingNeighborWall);

      bool run(Mesh *m, Mesh *m2, QString order, DivisionParms& p,
        double tolerance);

  };



 /**
   * \class PlanePropertiesOnConsole DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * PlanePropertiesOnConsole
   * Prints the properties of a selected plane onto the console
   */
  class DivisionPlaneHeat : public Process
  {
    public:
      DivisionPlaneHeat(const Process& process) : Process(process)
      {
		setName("Mesh/Division Analysis/Xtra/Previous/Set Div Plane Heat");
		setDesc("Displays planes of the Division analysis processes");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Heat Map","Heat Map","Area", QStringList() << "None" << "Area" << "Angle to Actual" << "Volume Ratio");	// 0
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, parm("Heat Map"));
      }

      bool run(Mesh *m, QString option);

  };

 /**
   * \class MeasureBetweenessCentrality DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * MeasureBetweenessCentrality
   * Generate heat map of the betweenness centrality of the cells weighted by a property
   */
  class MeasureBetweenessCentrality : public Process
  {
    public:
      MeasureBetweenessCentrality(const Process& process) : Process(process)
      {
		setName("Mesh/Heat Map/Measures/Network/Betweenness Centrality");
		setDesc("Generate heat map of the betweenness centrality of the cells weighted by a property.");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Weights","Weights on the edges between cells. None means all weights are 1. Wall Length ist the length of the shared wall. Euclidean is the distance between the cell centers.","1 / Wall Area", QStringList() << "None" << "Wall Area" << "1 / Wall Area");	// 0
	  }
      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, m->labelHeat(), parm("Weights"));
      }

      bool run(Mesh *m, IntFloatAttr& heatMap, QString weightType);

  };

 /**
   * \class MeasureBetweenessCentrality3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * MeasureBetweenessCentrality3D
   * Generate heat map of the betweenness centrality of the 3D cells weighted by a property.
   */
  class MeasureBetweenessCentrality3D : public Process
  {
    public:
      MeasureBetweenessCentrality3D(const Process& process) : Process(process)
      {
		setName("Mesh/Heat Map/Measures 3D/Network/Betweenness Centrality");
		setDesc("Generate heat map of the betweenness centrality of the 3D cells weighted by a property.");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Weights","Weights on the edges between cells. None means all weights are 1. Wall Length ist the length of the shared wall. Euclidean is the distance between the cell centers.","1 / Wall Area", QStringList() << "None" << "Wall Area" << "1 / Wall Area");	// 0
      }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, m->labelHeat(), parm("Weights"));
      }

      bool run(Mesh *m, IntFloatAttr& heatMap, QString weightType);

  };


 /**
   * \class MeasureBetweenessCurrentFlow DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * MeasureBetweenessCurrentFlow
   * Generate heat map of the current flow betweenness of the cells weighted by a property
   */
  class MeasureBetweenessCurrentFlow : public Process
  {
    public:
      MeasureBetweenessCurrentFlow(const Process& process) : Process(process)
      {
		setName("Mesh/Heat Map/Measures/Network/Betweenness Current Flow");
		setDesc("Generate heat map of the current flow betweenness of the cells weighted by a property");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Weights","Weights on the edges between cells. None means all weights are 1. Wall Length ist the length of the shared wall. Euclidean is the distance between the cell centers.","1 / Wall Area", QStringList() << "None" << "Wall Area" << "1 / Wall Area");	// 0
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, m->labelHeat(), parm("Weights"));
      }

      bool run(Mesh *m, IntFloatAttr& heatMap, QString weightType);


  };

 /**
   * \class MeasureBetweenessCurrentFlow3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * MeasureBetweenessCurrentFlow3D
   * Generate heat map of the current flow betweenness of the cells weighted by a property
   */
  class MeasureBetweenessCurrentFlow3D : public Process
  {
    public:
      MeasureBetweenessCurrentFlow3D(const Process& process) : Process(process)
      {
		setName("Mesh/Heat Map/Measures 3D/Network/Betweenness Current Flow");
		setDesc("Generate heat map of the current flow betweenness of the cells weighted by a property");
		setIcon(QIcon(":/images/CellDivide.png"));

		addParm("Weights","Weights on the edges between cells. None means all weights are 1. Wall Length ist the length of the shared wall. Euclidean is the distance between the cell centers.","1 / Wall Area", QStringList() << "None" << "Wall Area" << "1 / Wall Area");	// 0
	  }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, m->labelHeat(), parm("Weights"));
      }

      bool run(Mesh *m, IntFloatAttr& heatMap, QString weightType);

  };

 /**
   * \class PlanePropertiesOnConsole DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * PlanePropertiesOnConsole
   * Prints the properties of a selected plane onto the console
   */
  class CreatePlaneFromSelectedVtxs : public Process
  {
    public:
      CreatePlaneFromSelectedVtxs(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Xtra/To Revise/Create Plane From Selected Vtxs");
    setDesc("Create Plane From Selected Vtxs");
    setIcon(QIcon(":/images/CellDivide.png"));

    addParm("Plane Size","Plane Size","15.0"); // 0
    addParm("Overwrite Other Mesh","Overwrite Other Mesh","No", booleanChoice()); // 0
    }

      bool run()
      {
        Mesh *m = currentMesh();
        Mesh *m2 = otherMesh();
        return run(m, m2, parm("Plane Size").toDouble(), stringToBool(parm("Overwrite Other Mesh")));
      }

      bool run(Mesh *m, Mesh *m2, double size, bool overwrite);

  };

 /**
   * \class PlanePropertiesOnConsole DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * PlanePropertiesOnConsole
   * Prints the properties of a selected plane onto the console
   */
  class AngleTwoPlanes : public Process
  {
    public:
      AngleTwoPlanes(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Xtra/To Revise/Angle Two Selected Planes");
    setDesc("Angle Two Selected Planes");
    setIcon(QIcon(":/images/CellDivide.png"));

    }

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);

  };


 /**
   * \class ExportPlaneData DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * ExportPlaneData
   * Export Division Plane Data to a csv file
   */
  class ExportPlaneData : public Process
  {
    public:
      ExportPlaneData(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Export Plane Data");
    setDesc("Export Division Plane Data to a csv file");
    setIcon(QIcon(":/images/CellDivide.png"));

    addParm("Filename","Filename","");
    addParm("Export","Export","Actual Planes", QStringList() << "Actual Planes" << "Simulated Planes" << "Filtered Planes");
    }

    bool initialize(QWidget* parent);

      bool run()
      {
        Mesh *m = currentMesh();
        return run(m, parm("Filename"), parm("Export"));
      }

      bool run(Mesh *m, QString filename, QString mode);

  };

 /**
   * \class FlatDivisionPlane3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * FlatDivisionPlane3D
   * Display a planar approximation plane of a wall between two cells
   */
   class FlatDivisionPlane3D : public Process
  {
    public:
      FlatDivisionPlane3D(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Analysis 3D/Division Plane Approximation");
    setDesc("Display a planar approximation plane of a wall between two cells");
    setIcon(QIcon(":/images/CellDivide.png"));

    addParm("Display Plane","Overwrite the non-active mesh and display the plane","Yes",booleanChoice());
    addParm("Plane Size","Plane Size","10.0");
    addParm("Reset Mesh","Reset Mesh","No",booleanChoice());

     }

       bool run()
       {
         Mesh *m = currentMesh();
         Mesh *m2;
         if(currentMesh() == mesh(0))
           m2 = mesh(1);
         else
           m2 = mesh(0);
         return run(m, m2, stringToBool(parm("Display Plane")), parm("Plane Size").toDouble(), stringToBool(parm("Reset Mesh")));
       }
       bool run(Mesh *m, Mesh *m2, bool display, double planeSize, bool resetMesh, int label = 0);

  };


 /**
   * \class TestDivisionPlanes3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * TestDivisionPlanes3D
   * Division Testing for 3D cells
   */
  class TestDivisionPlanes3D : public Process
  {
    public:
      TestDivisionPlanes3D(const Process& process) : Process(process)
      {
    setName("Mesh/Division Analysis/Analysis 3D/Division Analysis");
    setDesc("Division Testing for 3D cells");
    setIcon(QIcon(":/images/CellDivide.png"));

    addParm("Nr of Planes","Approx number of planes to be tested","1000");
    addParm("Steps Center Displacement","Displacement steps from the cell center","0");
    addParm("Stepsize Center Displacement","Displacement step size from the cell center","0.0");
    addParm("Division Point","Division Point", "Centroid",QStringList() << "Centroid" << "Center Actual" << "Custom Vertex");
    //addParm("Draw Plane","Draw Plane","Yes",booleanChoice());

      }

      bool run()
      {
        std::cout << "Div analysis s1" << std::endl;
        Mesh *m = currentMesh();
        Mesh *m2;
        if(currentMesh() == mesh(0))
          m2 = mesh(1);
        else
          m2 = mesh(0);
        return run(m, m2, parm("Nr of Planes").toInt(), parm("Steps Center Displacement").toInt(), parm("Stepsize Center Displacement").toDouble(),
         parm("Division Point"), -1);
      }
      bool run(Mesh *m, Mesh *m2, int divPlanes, int centerDisplSteps, double centerDisplStepSize, QString divCenter, int parentLabel);

  };

  /**
    * \class DivisionAnalysisMulti3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
    *
    * DivisionAnalysisMulti3D
    * 2D process
    */
   class DivisionAnalysisMulti3D : public Process
   {
     public:
       DivisionAnalysisMulti3D(const Process& process) : Process(process)
       {
     setName("Mesh/Division Analysis/Analysis 3D/Division Analysis Multi");
     setDesc("Multi cell analysis of divisions in 3D meshes");
     setIcon(QIcon(":/images/CellDivide.png"));

     addParm("Test Single","Test Single","No",booleanChoice());
     addParm("Test Double","Test Double","Yes",booleanChoice());
     }

       bool run()
       {
        std::cout << "Div analysis Multi1" << std::endl;
         Mesh *m = currentMesh();
         Mesh *m2;
         if(currentMesh() == mesh(0))
           m2 = mesh(1);
         else
           m2 = mesh(0);

         return run(m, m2, stringToBool(parm("Test Single")), stringToBool(parm("Test Double")));
       }
       bool run(Mesh *m, Mesh *m2, bool singleCells, bool doubleCells);

   };

}

#endif
