// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
 * @class   vtkAdaptiveSubdivisionFilter
 * @brief   subdivide triangles based on edge and/or area metrics
 *
 *
 * vtkAdaptiveSubdivisionFilter is a filter that subdivides triangles based
 * on maximum edge length and/or triangle area. It uses a simple case-based,
 * multi-pass approach to repeatedly subdivide the input triangle mesh to
 * meet the area and/or edge length criteria. New points may be inserted only
 * on edges; depending on the number of edges to be subdivided a different
 * number of triangles are inserted ranging from two (i.e., two triangles
 * replace the original one) to four.
 *
 * Triangle subdivision is controlled by specifying a maximum edge length
 * and/or triangle area that any given triangle may have. Subdivision
 * proceeds until their criteria are satisfied. Note that using excessively
 * small criteria values can produce enormous meshes with the possibility of
 * exhausting system memory. Also, if you want to ignore a particular
 * criterion value (e.g., triangle area) then simply set the criterion value
 * to a very large value (e.g., VTK_DOUBLE_MAX).
 *
 * An incremental point locator is used because as new points are created, a
 * search is made to ensure that a point has not already been created. This
 * ensures that the mesh remains compatible (watertight) as long as certain
 * criteria are not used (triangle area limit, and number of triangles limit).
 *
 * To prevent overly large triangle meshes from being created, it is possible
 * to set a limit on the number of triangles created. By default this number
 * is a very large number (i.e., no limit). Further, a limit on the number of
 * passes can also be set, this is mostly useful to generated animations of
 * the algorithm.
 *
 * Finally, the attribute data (point and cell data) is treated as follows.
 * The cell data from a parent triangle is assigned to its subdivided
 * children.  Point data is interpolated along edges as the edges are
 * subdivided.
 *
 * @warning
 * The subdivision is linear along edges. Thus do not expect smoothing or
 * blending effects to occur. If you need to smooth the resulting mesh use an
 * algorithm like vtkWindowedSincPolyDataFilter or vtkSmoothPolyDataFilter.
 *
 * The filter retains mesh compatibility (watertightness) if the mesh was
 * originally compatible; and the area, max triangles criteria are not used.
 *
 * @warning
 * The filter requires a triangle mesh. Use vtkTriangleFilter to tessellate
 * the mesh if necessary.
 *
 * @sa
 * vtkInterpolatingSubdivisionFilter vtkLinearSubdivisionFilter
 * vtkButterflySubdivisionFilter vtkTriangleFilter
 */

#ifndef vtkAdaptiveSubdivisionFilter_h
#define vtkAdaptiveSubdivisionFilter_h

#include "vtkFiltersModelingModule.h" // For export macro
#include "vtkPolyDataAlgorithm.h"

VTK_ABI_NAMESPACE_BEGIN
class vtkIncrementalPointLocator;

class VTKFILTERSMODELING_EXPORT vtkAdaptiveSubdivisionFilter : public vtkPolyDataAlgorithm
{
public:
  ///@{
  /**
   * Standard methods for instantiation, type info, and printing.
   */
  static vtkAdaptiveSubdivisionFilter* New();
  vtkTypeMacro(vtkAdaptiveSubdivisionFilter, vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  ///@}

  ///@{
  /**
   * Specify the maximum edge length that a triangle may have. Edges longer
   * than this value are split in half and the associated triangles are
   * modified accordingly.
   */
  vtkSetClampMacro(MaximumEdgeLength, double, 0.000001, VTK_DOUBLE_MAX);
  vtkGetMacro(MaximumEdgeLength, double);
  ///@}

  ///@{
  /**
   * Specify the maximum area that a triangle may have. Triangles larger
   * than this value are subdivided to meet this threshold. Note that if
   * this criterion is used it may produce non-watertight meshes as a
   * result.
   */
  vtkSetClampMacro(MaximumTriangleArea, double, 0.000001, VTK_DOUBLE_MAX);
  vtkGetMacro(MaximumTriangleArea, double);
  ///@}

  ///@{
  /**
   * Set a limit on the maximum number of triangles that can be created.  If
   * the limit is hit, it may result in premature termination of the
   * algorithm and the results may be less than satisfactory (for example
   * non-watertight meshes may be created). By default, the limit is set to a
   * very large number (i.e., no effective limit).
   */
  vtkSetClampMacro(MaximumNumberOfTriangles, vtkIdType, 1, VTK_ID_MAX);
  vtkGetMacro(MaximumNumberOfTriangles, vtkIdType);
  ///@}

  ///@{
  /**
   * Set a limit on the number of passes (i.e., levels of subdivision).  If
   * the limit is hit, then the subdivision process stops and additional
   * passes (needed to meet other criteria) are aborted. The default limit is
   * set to a very large number (i.e., no effective limit).
   */
  vtkSetClampMacro(MaximumNumberOfPasses, vtkIdType, 1, VTK_ID_MAX);
  vtkGetMacro(MaximumNumberOfPasses, vtkIdType);
  ///@}

  ///@{
  /**
   * Set / get a spatial locator for merging points. By default,
   * an instance of vtkMergePoints is used. This is used to merge
   * coincident points during subdivision.
   */
  void SetLocator(vtkIncrementalPointLocator* locator);
  vtkGetObjectMacro(Locator, vtkIncrementalPointLocator);
  ///@}

  ///@{
  /**
   * Set/get the desired precision for the output types. See the documentation
   * for the vtkAlgorithm::Precision enum for an explanation of the available
   * precision settings.
   */
  vtkSetMacro(OutputPointsPrecision, int);
  vtkGetMacro(OutputPointsPrecision, int);
  ///@}

  /**
   * Create a default locator. Used to create one when none is
   * specified.
   */
  void CreateDefaultLocator();

  /**
   * Modified GetMTime because of the dependence on the locator.
   */
  vtkMTimeType GetMTime() override;

protected:
  vtkAdaptiveSubdivisionFilter();
  ~vtkAdaptiveSubdivisionFilter() override;

  double MaximumEdgeLength;
  double MaximumTriangleArea;
  vtkIdType MaximumNumberOfTriangles;
  vtkIdType MaximumNumberOfPasses;
  vtkIncrementalPointLocator* Locator;
  int OutputPointsPrecision;

  int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;

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

VTK_ABI_NAMESPACE_END
#endif
