//
// 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 FIBRIL_ORIENTATIONS_HPP
#define FIBRIL_ORIENTATIONS_HPP

#include <Process.hpp>

namespace mgx
{
  ///\addtogroup Process
  ///@{
  /**
   * \class FibrilOrientations <ProcessFibril.hpp>
   *
   * Compute principle orientations of lines in the mesh signal. Based on
   * Boudaoud et al., 'FibrilTool, an ImageJ plug-in to quantify fibrillar
   * structures in raw microscopy images', Nature Protocols 2014
   */
  class mgxBase_EXPORT FibrilOrientations : public Process {
  public:
    FibrilOrientations(const Process& process) : Process(process) 
    {	  
	  setName("Mesh/Cell Axis/Fibril Orientations/Compute Fibril Orientations");
	  setDesc("Compute principle orientations of lines in the mesh signal (vertex based version). \n"
	  "Based on Boudaoud et al., 'FibrilTool, an ImageJ plug-in to \n"
	  "quantify fibrillar structures in raw microscopy images', Nature Protocols 2014");
	  setIcon(QIcon(":/images/PrincipalOrientations.png"));	

	  addParm("Border Size","Width of cell border that is not taken into account for the computation.","1.0");
	  addParm("Min Area Ratio","Minimum ratio of inner area (whole cell - border) vs. total area needed for compuation.","0.25");
	  addParm("Blur Radius","Radius to blur the signal, 0 for none","0.5");
	  addParm("Background Radius","Radius to use for background substraction, 0 for none","0.0");
	}
  
    bool run()
    {
      if(!checkState().mesh(MESH_NON_EMPTY | MESH_SIGNAL))
        return false;
      Mesh* mesh = currentMesh();
      return run(mesh, parm("Border Size").toDouble(), parm("Min Area Ratio").toDouble(), 
                                                 parm("Blur Radius").toDouble(), parm("Background Radius").toDouble());
    }
  
    bool run(Mesh* mesh, double border, double minAreaRatio, double blurRadius, double backRadius);

  };
  
  /**
   * \class DisplayFibrilOrientations <ProcessFibril.hpp>
   *
   * Change the representation of the fibril orientation after it has been
   * computed.
   */
  class mgxBase_EXPORT DisplayFibrilOrientations : public Process 
  {
  public:
    DisplayFibrilOrientations(const Process& process) : Process(process) 
    {
	  setName("Mesh/Cell Axis/Fibril Orientations/Display Fibril Orientations");
	  setDesc("Display the orientations of fibrils on the image (vertex based version). \n"
	  "Only the maximal direction (main orientation) is displayed as a vector.");
	  setIcon(QIcon(":/images/PrincipalOrientations.png"));	

	  addParm("Heatmap","Display orientation strength (= MaxDirection/MinDirection - 1) as a colormap.","none", QStringList() << "none" << "Orientation");
	  addParm("Line Color","Line Color","red", QColor::colorNames());
	  addParm("Line Width","Line Width","1.0");
	  addParm("Line Scale","Length of the vectors = Scale * orientation strength.","1.0");
	  addParm("Line Offset","Draw the vector ends a bit tilted up for proper display on surfaces.","0.1");
	  addParm("Threshold","Minimal value of orientation strength required for drawing main direction.","0.0");						
	}
  
    bool run()
    {
      if(!checkState().mesh(MESH_NON_EMPTY))
        return false;
  
      return run(currentMesh(), parm("Heatmap"), QColor(parm("Line Color")), parm("Line Width").toFloat(), 
                            parm("Line Scale").toFloat(), parm("Line Offset").toFloat(), parm("Threshold").toFloat());
    }
  
    bool run(Mesh* mesh, const QString DisplayHeatMap, const QColor& ColorMax, 
        float AxisLineWidth, float ScaleAxisLength, float AxisOffset, float OrientationThreshold);

  };

 /**
   * \class FibrilOrientations <ProcessFibril.hpp>
   *
   * Compute principle orientations of lines in the mesh signal. Based on
   * Boudaoud et al., 'FibrilTool, an ImageJ plug-in to quantify fibrillar
   * structures in raw microscopy images', Nature Protocols 2014
   */
  class mgxBase_EXPORT FibrilOrientationsVertex : public Process {
  public:
    FibrilOrientationsVertex(const Process& process) : Process(process) 
    {	  
	  setName("Mesh/Cell Axis/Fibril Orientations/Vertex Compute Orientations");
	  setDesc("Compute principle orientations of lines in the mesh signal (vertex based version). \n"
	  "Based on Boudaoud et al., 'FibrilTool, an ImageJ plug-in to \n"
	  "quantify fibrillar structures in raw microscopy images', Nature Protocols 2014");
	  setIcon(QIcon(":/images/PrincipalOrientations.png"));	

	  addParm("Border Size","Width of cell border that is not taken into account for the computation.","1.0");
	  addParm("Minimum inner area ratio","Minimum ratio of inner area (whole cell - border) vs. total area needed for compuation.","0.25");
	  addParm("Radius","Radius to use for orientation","2.0");
	  addParm("Blur Radius","Radius to blur the signal","1.0");
	
	}
  
    bool run()
    {
      if(!checkState().mesh(MESH_NON_EMPTY | MESH_SIGNAL))
        return false;
      Mesh* m = currentMesh();
      Mesh *m2;
      if(currentMesh() == mesh(0))
        m2 = mesh(1);
      else
        m2 = mesh(0);
      return run(m, m2, parm("Border Size").toFloat(), parm("Minimum inner area ratio").toFloat(), parm("Radius").toFloat(), parm("Blur Radius").toFloat());
    }
  
    bool run(Mesh* m, Mesh* m2, float border, float minAreaRatio, float radius, float blurRadius);
  
  };


  /**
   * \class DisplayFibrilOrientations <ProcessFibril.hpp>
   *
   * Change the representation of the fibril orientation after it has been
   * computed.
   */
  class mgxBase_EXPORT DisplayFibrilOrientationsVertex : public Process 
  {
  public:
    DisplayFibrilOrientationsVertex(const Process& process) : Process(process) 
    {
	  setName("Mesh/Cell Axis/Fibril Orientations/Vertex Display Orientations");
	  setDesc("Display the orientations of fibrils on the image (vertex based version). \n"
	  "Only the maximal direction (main orientation) is displayed as a vector.");
	  setIcon(QIcon(":/images/PrincipalOrientations.png"));	

	  addParm("Heatmap","Display orientation strength (= MaxDirection/MinDirection - 1) as a colormap.","none", QStringList() << "none" << "Orientation");
	  addParm("Line Color","Line Color","red", QColor::colorNames());
	  addParm("Line Width","Line Width","1.0");
	  addParm("Line Scale","Length of the vectors = Scale * orientation strength.","1.0");
	  addParm("Line Offset","Draw the vector ends a bit tilted up for proper display on surfaces.","0.1");
	  addParm("Threshold","Minimal value of orientation strength required for drawing main direction.","0.0");
	
		
		}
  
    bool run()
    {
      if(!checkState().mesh(MESH_NON_EMPTY))
        return false;
  
      return run(currentMesh(), parm("Heatmap"), QColor(parm("Line Color")), parm("Line Width").toFloat(), 
                            parm("Line Scale").toFloat(), parm("Line Offset").toFloat(), parm("Threshold").toFloat());
    }
  
    bool run(Mesh* mesh, const QString DisplayHeatMap, const QColor& ColorMax, 
        float AxisLineWidth, float ScaleAxisLength, float AxisOffset, float OrientationThreshold);
  
  };


 /**
   * \class FibrilOrientations <ProcessFibril.hpp>
   *
   * Compute principle orientations of lines in the mesh signal. Based on
   * Boudaoud et al., 'FibrilTool, an ImageJ plug-in to quantify fibrillar
   * structures in raw microscopy images', Nature Protocols 2014
   */
  class mgxBase_EXPORT SelectVerticesOfCell : public Process {
  public:
    SelectVerticesOfCell(const Process& process) : Process(process) 
    {
	  setName("Mesh/Cell Axis/Fibril Orientations/Vertices Select");
	  setDesc("Selects vertices of cells that are (roughly) equally spaced and distributed.");

	  addParm("Min Point Distance","Minimum distance between two points","2.0");	// 0
	  addParm("Min Border Distance","Minimum distance of a generated point and a border vertex of the cell","0.0");	// 1
          addParm("Only Cells With Parent Label","Only Cells With Parent Label","No",booleanChoice()); // 2
	}
  
    bool run()
    {
      Mesh* m = currentMesh();

      return run(m, parm("Min Point Distance").toDouble(), parm("Min Border Distance").toDouble(),
                 stringToBool(parm("Only Cells With Parent Label")));
    }
  
    bool run(Mesh* m, double minPointDis, double minBorderDis, bool ignoreNoParents);

  };


  ///@}
}

#endif
