/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkHyperTreeGridAxisClip.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/**
 * @class   vtkHyperTreeGridAxisClip
 * @brief   Axis aligned hyper tree grid clip
 *
 *
 * Clip an hyper tree grid along an axis aligned plane or box and output
 * a hyper tree grid with same dimensionality.
 * This filter also allows for reversal of the direction of what is inside
 * versus what is outside by setting the InsideOut instance variable.
 *
 * @sa
 * vtkHyperTreeGrid vtkHyperTreeGridAlgorithm
 *
 * @par Thanks:
 * This class was written by Philippe Pebay on a idea of Guenole Harel and Jacques-Bernard Lekien, 2016
 * This class was modified by Jacques-Bernard Lekien, 2018
 * This work was supported by Commissariat a l'Energie Atomique
 * CEA, DAM, DIF, F-91297 Arpajon, France.
*/

#ifndef vtkHyperTreeGridAxisClip_h
#define vtkHyperTreeGridAxisClip_h

#include "vtkFiltersHyperTreeModule.h" // For export macro
#include "vtkHyperTreeGridAlgorithm.h"

class vtkBitArray;
class vtkHyperTreeGrid;
class vtkQuadric;
class vtkHyperTreeGridNonOrientedCursor;
class vtkHyperTreeGridNonOrientedGeometryCursor;

class VTKFILTERSHYPERTREE_EXPORT vtkHyperTreeGridAxisClip : public vtkHyperTreeGridAlgorithm
{
public:
  static vtkHyperTreeGridAxisClip* New();
  vtkTypeMacro( vtkHyperTreeGridAxisClip, vtkHyperTreeGridAlgorithm );
  void PrintSelf( ostream&, vtkIndent ) override;

  /**
   * Methods by which the hyper tree grid input may be clipped:
   * PLANE: Clip with an axis-aligned plane defined by normal and intercept.
   * BOX: Clip with an axis-aligned rectangular prism defined by its extremal coordinates.
   * QUADRIC: Clip with an axis-aligned quadric defined by its coefficients.
   */
  enum ClipType
  {
    PLANE = 0,
    BOX,
    QUADRIC,
  };

  //@{
  /**
   * Set/get type of clip.
   * Default value is 0 (plane clip).
   */
  vtkSetClampMacro(ClipType, int, 0, 2);
  vtkGetMacro(ClipType, int);
  void SetClipTypeToPlane() { this->SetClipType( vtkHyperTreeGridAxisClip::PLANE); }
  void SetClipTypeToBox() { this->SetClipType( vtkHyperTreeGridAxisClip::BOX); }
  void SetClipTypeToQuadric() { this->SetClipType( vtkHyperTreeGridAxisClip::QUADRIC); }
  //@}

  //@{
  /**
   * Set/get normal axis of clipping plane: 0=X, 1=Y, 2=Z.
   * Default value is 0 (X-axis normal).
   */
  vtkSetClampMacro(PlaneNormalAxis, int, 0, 2);
  vtkGetMacro(PlaneNormalAxis, int);
  //@}

  //@{
  /**
   * Set/get position of clipping plane: intercept along normal axis.
   * Default value is 0.0.
   */
  vtkSetMacro(PlanePosition, double);
  vtkGetMacro(PlanePosition, double);
  //@}

  //@{
  /**
   * Set/get bounds of clipping box.
   */
  vtkSetVector6Macro(Bounds,double);
  vtkGetVectorMacro(Bounds,double,6);
  void GetMinimumBounds( double[3] );
  void GetMaximumBounds( double[3] );
  //@}

  //@{
  /**
   * Set/Get the InsideOut flag, in the case of clip by hyperplane.
   * When off, a cell is clipped out when its origin is above said plane
   * intercept along the considered direction, inside otherwise.
   * When on, a cell is clipped out when its origin + size is below said
   * said plane intercept along the considered direction.
   */
  vtkSetMacro(InsideOut,int);
  vtkGetMacro(InsideOut,int);
  vtkBooleanMacro(InsideOut,int);
  //@}

  //@{
  /**
   * Set/Get the clipping quadric function.
   */
  virtual void SetQuadric( vtkQuadric* );
  vtkGetObjectMacro(Quadric, vtkQuadric);
  //@}

  //@{
  /**
   * Helpers to set/get the 10 coefficients of the quadric function
   */
  void SetQuadricCoefficients(double a, double b, double c, double d, double e,
                              double f, double g, double h, double i, double j)
  {
    double array[10] = { a, b, c, d, e, f, g, h, i, j };
    this->SetQuadricCoefficients(array);
  }
  void SetQuadricCoefficients( double[10] );
  void GetQuadricCoefficients( double[10] );
  double* GetQuadricCoefficients();
  //@}

  /**
   * Override GetMTime because we delegate to a vtkQuadric.
   */
  vtkMTimeType GetMTime() override;

protected:
  vtkHyperTreeGridAxisClip();
  ~vtkHyperTreeGridAxisClip() override;

  // For this algorithm the output is a vtkHyperTreeGrid instance
  int FillOutputPortInformation( int, vtkInformation* ) override;

  /**
   * Decide whether the cell is clipped out
   */
  bool IsClipped( vtkHyperTreeGridNonOrientedGeometryCursor* );

  /**
   * Main routine to generate hyper tree grid clip
   */
  int ProcessTrees( vtkHyperTreeGrid*, vtkDataObject* ) override;

  /**
   * Recursively descend into tree down to leaves
   */
  void RecursivelyProcessTree( vtkHyperTreeGridNonOrientedGeometryCursor* inCursor,
                               vtkHyperTreeGridNonOrientedCursor* outCursor );

  /**
   * Type of clip to be performed
   */
  int ClipType;

  /**
   * Direction of clipping plane normal
   */
  int PlaneNormalAxis;

  /**
   * Intercept of clipping plane along normal
   */
  double PlanePosition;
  double PlanePositionRealUse;

  /**
   * Bounds of axis-aligned clipping box
   */
  double Bounds[6];

  /**
   * Coefficients of axis-aligned quadric
   */
  vtkQuadric* Quadric;

  /**
   * Decide what is inside versus what is out
   */
  int InsideOut;

  /**
   * Output material mask constructed by this filter
   */
  vtkBitArray* InMask;
  vtkBitArray* OutMask;

  /**
   * Keep track of current index in output hyper tree grid
   */
  vtkIdType CurrentId;

private:
  vtkHyperTreeGridAxisClip(const vtkHyperTreeGridAxisClip&) = delete;
  void operator=(const vtkHyperTreeGridAxisClip&) = delete;
};

#endif // vtkHyperTreeGridAxisClip_h
