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

  Program:   Visualization Toolkit
  Module:    vtkModifiedBSPTree.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.

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

/*=========================================================================
  This code is derived from an earlier work and is distributed
  with permission from, and thanks to

  ------------------------------------------
  Copyright (C) 1997-2000 John Biddiscombe
  Rutherford Appleton Laboratory,
  Chilton, Oxon, England
  ------------------------------------------
  Copyright (C) 2000-2004 John Biddiscombe
  Skipping Mouse Software Ltd,
  Blewbury, England
  ------------------------------------------
  Copyright (C) 2004-2009 John Biddiscombe
  CSCS - Swiss National Supercomputing Centre
  Galleria 2 - Via Cantonale
  CH-6928 Manno, Switzerland
  ------------------------------------
=========================================================================*/
/**
 * @class   vtkModifiedBSPTree
 * @brief   Generate axis aligned BBox tree for raycasting and other Locator based searches
 *
 *
 * vtkModifiedBSPTree creates an evenly balanced BSP tree using a top down
 * implementation. Axis aligned split planes are found which evenly divide
 * cells into two buckets. Generally a split plane will intersect some cells
 * and these are usually stored in both child nodes of the current parent.
 * (Or split into separate cells which we cannot consider in this case).
 * Storing cells in multiple buckets creates problems associated with multiple
 * tests against rays and increases the required storage as complex meshes
 * will have many cells straddling a split plane (and further splits may
 * cause multiple copies of these).
 *
 * During a discussion with Arno Formella in 1998 he suggested using
 * a third child node to store objects which straddle split planes. I've not
 * seen this published (Yes! - see below), but thought it worth trying. This
 * implementation of the BSP tree creates a third child node for storing cells
 * laying across split planes, the third cell may overlap the other two, but the
 * two 'proper' nodes otherwise conform to usual BSP rules.
 *
 * The advantage of this implementation is cells only ever lie in one node
 * and mailbox testing is avoided. All BBoxes are axis aligned and a ray cast
 * uses an efficient search strategy based on near/far nodes and rejects
 * all BBoxes using simple tests.
 *
 * For fast raytracing, 6 copies of cell lists are stored in each leaf node
 * each list is in axis sorted order +/- x,y,z and cells are always tested
 * in the direction of the ray dominant axis. Once an intersection is found
 * any cell or BBox with a closest point further than the I-point can be
 * instantly rejected and raytracing stops as soon as no nodes can be closer
 * than the current best intersection point.
 *
 * The addition of the 'middle' node upsets the optimal balance of the tree,
 * but is a minor overhead during the raytrace. Each child node is contracted
 * such that it tightly fits all cells inside it, enabling further ray/box
 * rejections.
 *
 * This class is intended for persons requiring many ray tests and is optimized
 * for this purpose. As no cell ever lies in more than one leaf node, and parent
 * nodes do not maintain cell lists, the memory overhead of the sorted cell
 * lists is 6*num_cells*4 for 6 lists of ints, each num_cells in length.
 * The memory requirement of the nodes themselves is usually of minor
 * significance.
 *
 * Subdividision is controlled by MaxCellsPerNode - any node with more than
 * this number will be subdivided providing a good split plane can be found and
 * the max depth is not exceeded.
 *
 * The average cells per leaf will usually be around half the MaxCellsPerNode,
 * though the middle node is usually sparsely populated and lowers the average
 * slightly. The middle node will not be created when not needed.
 * Subdividing down to very small cells per node is not generally suggested
 * as then the 6 stored cell lists are effectively redundant.
 *
 * Values of MaxcellsPerNode of around 16->128 depending on dataset size will
 * usually give good results.
 *
 * Cells are only sorted into 6 lists once - before tree creation, each node
 * segments the lists and passes them down to the new child nodes whilst
 * maintaining sorted order. This makes for an efficient subdivision strategy.
 *
 * NB. The following reference has been sent to me
 *   @Article{formella-1995-ray,
 *     author =     "Arno Formella and Christian Gill",
 *     title =      "{Ray Tracing: A Quantitative Analysis and a New
 *                   Practical Algorithm}",
 *     journal =    "{The Visual Computer}",
 *     year =       "{1995}",
 *     month =       dec,
 *     pages =      "{465--476}",
 *     volume =     "{11}",
 *     number =     "{9}",
 *     publisher =  "{Springer}",
 *     keywords =   "{ray tracing, space subdivision, plane traversal,
 *                    octree, clustering, benchmark scenes}",
 *     annote =     "{We present a new method to accelerate the process of
 *                    finding nearest ray--object intersections in ray
 *                    tracing. The algorithm consumes an amount of memory
 *                    more or less linear in the number of objects. The basic
 *                    ideas can be characterized with a modified BSP--tree
 *                    and plane traversal. Plane traversal is a fast linear
 *                    time algorithm to find the closest intersection point
 *                    in a list of bounding volumes hit by a ray. We use
 *                    plane traversal at every node of the high outdegree
 *                    BSP--tree. Our implementation is competitive to fast
 *                    ray tracing programs. We present a benchmark suite
 *                    which allows for an extensive comparison of ray tracing
 *                    algorithms.}",
 *   }
 *
 * @par Thanks:
 *  John Biddiscombe for developing and contributing this class
 *
 * @todo
 * -------------
 * Implement intersection heap for testing rays against transparent objects
 *
 * @par Style:
 * --------------
 * This class is currently maintained by J. Biddiscombe who has specially
 * requested that the code style not be modified to the kitware standard.
 * Please respect the contribution of this class by keeping the style
 * as close as possible to the author's original.
 *
 */

#ifndef vtkModifiedBSPTree_h
#define vtkModifiedBSPTree_h

#include "vtkAbstractCellLocator.h"
#include "vtkFiltersFlowPathsModule.h" // For export macro
#include "vtkSmartPointer.h"           // required because it is nice

class Sorted_cell_extents_Lists;
class BSPNode;
class vtkGenericCell;
class vtkIdList;
class vtkIdListCollection;

class VTKFILTERSFLOWPATHS_EXPORT vtkModifiedBSPTree : public vtkAbstractCellLocator
{
public:
  //@{
  /**
   * Standard Type-Macro
   */
  vtkTypeMacro(vtkModifiedBSPTree, vtkAbstractCellLocator);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  //@}

  /**
   * Construct with maximum 32 cells per node. (average 16->31)
   */
  static vtkModifiedBSPTree* New();

  // Re-use any superclass signatures that we don't override.
  using vtkAbstractCellLocator::FindCell;
  using vtkAbstractCellLocator::IntersectWithLine;

  /**
   * Free tree memory
   */
  void FreeSearchStructure() override;

  /**
   * Build Tree
   */
  void BuildLocator() override;

  /**
   * Generate BBox representation of Nth level
   */
  void GenerateRepresentation(int level, vtkPolyData* pd) override;

  /**
   * Generate BBox representation of all leaf nodes
   */
  virtual void GenerateRepresentationLeafs(vtkPolyData* pd);

  /**
   * Return intersection point (if any) AND the cell which was intersected by
   * the finite line. Uses fast tree-search BBox rejection tests.
   */
  int IntersectWithLine(const double p1[3], const double p2[3], double tol, double& t, double x[3],
    double pcoords[3], int& subId, vtkIdType& cellId) override;

  /**
   * Return intersection point (if any) AND the cell which was intersected by
   * the finite line. The cell is returned as a cell id and as a generic cell.
   */
  int IntersectWithLine(const double p1[3], const double p2[3], double tol, double& t, double x[3],
    double pcoords[3], int& subId, vtkIdType& cellId, vtkGenericCell* cell) override;

  /**
   * Take the passed line segment and intersect it with the data set.
   * The return value of the function is 0 if no intersections were found.
   * For each intersection found, the vtkPoints and CellIds objects
   * have the relevant information added in order of intersection increasing
   * from ray start to end. If either vtkPoints or CellIds are nullptr
   * pointers, then no information is generated for that list.
   */
  virtual int IntersectWithLine(const double p1[3], const double p2[3], const double tol,
    vtkPoints* points, vtkIdList* cellIds);

  /**
   * Test a point to find if it is inside a cell. Returns the cellId if inside
   * or -1 if not.
   */
  vtkIdType FindCell(
    double x[3], double tol2, vtkGenericCell* GenCell, double pcoords[3], double* weights) override;

  bool InsideCellBounds(double x[3], vtkIdType cell_ID) override;

  /**
   * After subdivision has completed, one may wish to query the tree to find
   * which cells are in which leaf nodes. This function returns a list
   * which holds a cell Id list for each leaf node.
   */
  vtkIdListCollection* GetLeafNodeCellInformation();

protected:
  vtkModifiedBSPTree();
  ~vtkModifiedBSPTree() override;
  //
  BSPNode* mRoot; // bounding box root node
  int npn;
  int nln;
  int tot_depth;

  //
  // The main subdivision routine
  void Subdivide(BSPNode* node, Sorted_cell_extents_Lists* lists, vtkDataSet* dataSet,
    vtkIdType nCells, int depth, int maxlevel, vtkIdType maxCells, int& MaxDepth);

  // We provide a function which does the cell/ray test so that
  // it can be overridden by subclasses to perform special treatment
  // (Example : Particles stored in tree, have no dimension, so we must
  // override the cell test to return a value based on some particle size
  virtual int IntersectCellInternal(vtkIdType cell_ID, const double p1[3], const double p2[3],
    const double tol, double& t, double ipt[3], double pcoords[3], int& subId);

  void BuildLocatorIfNeeded();
  void ForceBuildLocator();
  void BuildLocatorInternal();

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

///////////////////////////////////////////////////////////////////////////////
// BSP Node
// A BSP Node is a BBox - axis aligned etc etc
///////////////////////////////////////////////////////////////////////////////
#ifndef DOXYGEN_SHOULD_SKIP_THIS

class BSPNode
{
public:
  // Constructor
  BSPNode(void)
  {
    mChild[0] = mChild[1] = mChild[2] = nullptr;
    for (int i = 0; i < 6; i++)
      sorted_cell_lists[i] = nullptr;
    for (int i = 0; i < 3; i++)
    {
      this->Bounds[i * 2] = VTK_FLOAT_MAX;
      this->Bounds[i * 2 + 1] = -VTK_FLOAT_MAX;
    }
  }
  // Destructor
  ~BSPNode(void)
  {
    for (int i = 0; i < 3; i++)
      delete mChild[i];
    for (int i = 0; i < 6; i++)
      delete[] sorted_cell_lists[i];
  }
  // Set min box limits
  void setMin(double minx, double miny, double minz)
  {
    this->Bounds[0] = minx;
    this->Bounds[2] = miny;
    this->Bounds[4] = minz;
  }
  // Set max box limits
  void setMax(double maxx, double maxy, double maxz)
  {
    this->Bounds[1] = maxx;
    this->Bounds[3] = maxy;
    this->Bounds[5] = maxz;
  }
  //
  bool Inside(double point[3]) const;
  // BBox
  double Bounds[6];

protected:
  // The child nodes of this one (if present - nullptr otherwise)
  BSPNode* mChild[3];
  // The axis we subdivide this voxel along
  int mAxis;
  // Just for reference
  int depth;
  // the number of cells in this node
  int num_cells;
  // 6 lists, sorted after the 6 dominant axes
  vtkIdType* sorted_cell_lists[6];
  // Order nodes as near/mid far relative to ray
  void Classify(const double origin[3], const double dir[3], double& rDist, BSPNode*& Near,
    BSPNode*& Mid, BSPNode*& Far) const;
  // Test ray against node BBox : clip t values to extremes
  bool RayMinMaxT(const double origin[3], const double dir[3], double& rTmin, double& rTmax) const;
  //
  friend class vtkModifiedBSPTree;
  friend class vtkParticleBoxTree;

public:
  static bool VTKFILTERSFLOWPATHS_EXPORT RayMinMaxT(const double bounds[6], const double origin[3],
    const double dir[3], double& rTmin, double& rTmax);
  static int VTKFILTERSFLOWPATHS_EXPORT getDominantAxis(const double dir[3]);
};

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

#endif
