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

  Program:   Visualization Toolkit
  Module:    vtkYoungsMaterialInterface.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   vtkYoungsMaterialInterface
 * @brief   reconstructs material interfaces
 *
 *
 * Reconstructs material interfaces from a mesh containing mixed cells (where several materials are mixed)
 * this implementation is based on the youngs algorithm, generalized to arbitrary cell types and works
 * on both 2D and 3D meshes. the main advantage of the youngs algorithm is it guarantees the material volume correctness.
 * for 2D meshes, the AxisSymetric flag allows to switch between a pure 2D (planar) algorithm and an axis symmetric 2D algorithm
 * handling volumes of revolution.
 *
 * @par Thanks:
 * This file is part of the generalized Youngs material interface reconstruction algorithm contributed by <br>
 * CEA/DIF - Commissariat a l'Energie Atomique, Centre DAM Ile-De-France <br>
 * BP12, F-91297 Arpajon, France. <br>
 * Implementation by Thierry Carrard (thierry.carrard@cea.fr)
 * Modification by Philippe Pebay (philippe.pebay@kitware.com)
*/

#ifndef vtkYoungsMaterialInterface_h
#define vtkYoungsMaterialInterface_h

#include "vtkFiltersGeneralModule.h" // For export macro
#include "vtkMultiBlockDataSetAlgorithm.h"

#include "vtkSmartPointer.h" // For SP ivars

class vtkIntArray;
class vtkInformation;
class vtkInformationVector;
class vtkYoungsMaterialInterfaceInternals;

class VTKFILTERSGENERAL_EXPORT vtkYoungsMaterialInterface : public vtkMultiBlockDataSetAlgorithm
{
public:
  static vtkYoungsMaterialInterface* New();
  vtkTypeMacro(vtkYoungsMaterialInterface,vtkMultiBlockDataSetAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  //@{
  /**
   * Set/Get whether the normal vector has to be flipped.
   */
  vtkSetMacro(InverseNormal,vtkTypeBool);
  vtkGetMacro(InverseNormal,vtkTypeBool);
  vtkBooleanMacro(InverseNormal,vtkTypeBool);
  //@}

  //@{
  /**
   * If this flag is on, material order in reversed.
   * Otherwise, materials are sorted in ascending order depending on the given ordering array.
   */
  vtkSetMacro(ReverseMaterialOrder,vtkTypeBool);
  vtkGetMacro(ReverseMaterialOrder,vtkTypeBool);
  vtkBooleanMacro(ReverseMaterialOrder,vtkTypeBool);
  //@}

  //@{
  /**
   * Set/Get OnionPeel flag. if this flag is on, the normal vector of the first
   * material (which depends on material ordering) is used for all materials.
   */
  vtkSetMacro(OnionPeel,vtkTypeBool);
  vtkGetMacro(OnionPeel,vtkTypeBool);
  vtkBooleanMacro(OnionPeel,vtkTypeBool);
  //@}

  //@{
  /**
   * Turns on/off AxisSymetric computation of 2D interfaces.
   * in axis symmetric mode, 2D meshes are understood as volumes of revolution.
   */
  vtkSetMacro(AxisSymetric,vtkTypeBool);
  vtkGetMacro(AxisSymetric,vtkTypeBool);
  vtkBooleanMacro(AxisSymetric,vtkTypeBool);
  //@}

  //@{
  /**
   * when UseFractionAsDistance is true, the volume fraction is interpreted as the distance
   * of the cutting plane from the origin.
   * in axis symmetric mode, 2D meshes are understood as volumes of revolution.
   */
  vtkSetMacro(UseFractionAsDistance,vtkTypeBool);
  vtkGetMacro(UseFractionAsDistance,vtkTypeBool);
  vtkBooleanMacro(UseFractionAsDistance,vtkTypeBool);
  //@}

  //@{
  /**
   * When FillMaterial is set to 1, the volume containing material is output and not only the interface surface.
   */
  vtkSetMacro(FillMaterial,vtkTypeBool);
  vtkGetMacro(FillMaterial,vtkTypeBool);
  vtkBooleanMacro(FillMaterial,vtkTypeBool);
  //@}

  //@{
  /**
   * Set/Get minimum and maximum volume fraction value. if a material fills a volume above the minimum value, the material is considered to be void. if a material fills a volume fraction beyond the maximum value it is considered as filling the whole volume.
   */
  vtkSetVector2Macro(VolumeFractionRange,double);
  vtkGetVectorMacro(VolumeFractionRange,double,2);
  //@}

  //@{
  /**
   * Sets/Gets the number of materials.
   */
  virtual void SetNumberOfMaterials(int n);
  virtual int GetNumberOfMaterials();
  //@}

  //@{
  /**
   * Set/Get whether all material blocks should be used, irrespective of the material block mapping.
   */
  vtkSetMacro(UseAllBlocks,bool);
  vtkGetMacro(UseAllBlocks,bool);
  vtkBooleanMacro(UseAllBlocks,bool);
  //@}

  //@{
  /**
   * Only meaningful for LOVE software. returns the maximum number of blocks containing the same material
   */
  vtkGetMacro(NumberOfDomains,int);
  //@}

  //@{
  /**
   * Set ith Material arrays to be used as volume fraction, interface normal and material ordering. Each parameter name a cell array.
   */
  virtual void SetMaterialArrays( int i, const char* volume, const char* normalX, const char* normalY, const char* normalZ, const char* ordering );
  virtual void SetMaterialArrays( int i, const char* volume, const char* normal, const char* ordering );
  virtual void SetMaterialVolumeFractionArray( int i, const char* volume );
  virtual void SetMaterialNormalArray( int i, const char* normal );
  virtual void SetMaterialOrderingArray( int i, const char* ordering );
  //@}

  /**
   * Removes all materials previously added.
   */
  virtual void RemoveAllMaterials();

  //@{
  /**
   * Alternative API for associating Normal and Ordering arrays to materials
   * identified by its volume-fraction array.
   * Note that these mappings are cleared by a call to RemoveAllMaterials() but
   * not by SetNumberOfMaterials().
   * If one uses the SetMaterial*Array(int, ...) API to set the normal or
   * ordering arrays, then that supersedes the values set using this API.
   */
  virtual void SetMaterialNormalArray(const char* volume, const char* normal);
  virtual void SetMaterialOrderingArray(const char* volume, const char* ordering);
  //@}

  //@{
  /**
   * select blocks to be processed for each described material.
   */
  virtual void RemoveAllMaterialBlockMappings();
  virtual void AddMaterialBlockMapping(int b);
  //@}

  enum
  {
    MAX_CELL_POINTS=256
  };

protected:
  vtkYoungsMaterialInterface ();
  ~vtkYoungsMaterialInterface () override;

  int FillInputPortInformation(int port, vtkInformation *info) override;
  int RequestData(vtkInformation *request,
             vtkInformationVector **inputVector,
             vtkInformationVector *outputVector) override;

  /**
   * Serial implementation of the material aggregation.
   */
  virtual void Aggregate ( int, int* );

  void UpdateBlockMapping();

  int CellProduceInterface( int dim, int np, double fraction, double minFrac, double maxFrac );

  //@{
  /**
   * Read-Write Properties
   */
  vtkTypeBool FillMaterial;
  vtkTypeBool InverseNormal;
  vtkTypeBool AxisSymetric;
  vtkTypeBool OnionPeel;
  vtkTypeBool ReverseMaterialOrder;
  vtkTypeBool UseFractionAsDistance;
  double VolumeFractionRange[2];
  //@}

  vtkSmartPointer<vtkIntArray> MaterialBlockMapping;

  bool UseAllBlocks;

  /**
   * Read only properties
   */
  int NumberOfDomains;

  // Description:
  // Internal data structures
  vtkYoungsMaterialInterfaceInternals* Internals;

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

#endif /* VTK_YOUNGS_MATERIAL_INTERFACE_H */

