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

  Program:   Visualization Toolkit
  Module:    vtkImageActorPointPlacer.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   vtkImageActorPointPlacer
 * @brief   Converts 2D display positions to world positions such that they lie on an ImageActor
 *
 * This PointPlacer is used to constrain the placement of points on the
 * supplied image actor. Additionally, you may set bounds to restrict the
 * placement of the points. The placement of points will then be constrained
 * to lie not only on the ImageActor but also within the bounds specified.
 * If no bounds are specified, they may lie anywhere on the supplied ImageActor.
 */

#ifndef vtkImageActorPointPlacer_h
#define vtkImageActorPointPlacer_h

#include "vtkInteractionWidgetsModule.h" // For export macro
#include "vtkPointPlacer.h"

class vtkBoundedPlanePointPlacer;
class vtkImageActor;
class vtkRenderer;

class VTKINTERACTIONWIDGETS_EXPORT vtkImageActorPointPlacer : public vtkPointPlacer
{
public:
  /**
   * Instantiate this class.
   */
  static vtkImageActorPointPlacer* New();

  //@{
  /**
   * Standard methods for instances of this class.
   */
  vtkTypeMacro(vtkImageActorPointPlacer, vtkPointPlacer);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  //@}

  /**
   * Given and renderer and a display position in pixels,
   * find a world position and orientation. In this class
   * an internal vtkBoundedPlanePointPlacer is used to compute
   * the world position and orientation. The internal placer
   * is set to use the plane of the image actor and the bounds
   * of the image actor as the constraints for placing points.
   */
  int ComputeWorldPosition(
    vtkRenderer* ren, double displayPos[2], double worldPos[3], double worldOrient[9]) override;

  /**
   * This method is identical to the one above since the
   * reference position is ignored by the bounded plane
   * point placer.
   */
  int ComputeWorldPosition(vtkRenderer* ren, double displayPos[2], double refWorldPos[2],
    double worldPos[3], double worldOrient[9]) override;

  /**
   * This method validates a world position by checking to see
   * if the world position is valid according to the constraints
   * of the internal placer (essentially - is this world position
   * on the image?)
   */
  int ValidateWorldPosition(double worldPos[3]) override;

  /**
   * This method is identical to the one above since the bounded
   * plane point placer ignores orientation
   */
  int ValidateWorldPosition(double worldPos[3], double worldOrient[9]) override;

  /**
   * Update the world position and orientation according the
   * the current constraints of the placer. Will be called
   * by the representation when it notices that this placer
   * has been modified.
   */
  int UpdateWorldPosition(vtkRenderer* ren, double worldPos[3], double worldOrient[9]) override;

  /**
   * A method for configuring the internal placer according
   * to the constraints of the image actor.
   * Called by the representation to give the placer a chance
   * to update itself, which may cause the MTime to change,
   * which would then cause the representation to update
   * all of its points
   */
  int UpdateInternalState() override;

  //@{
  /**
   * Set / get the reference vtkImageActor used to place the points.
   * An image actor must be set for this placer to work. An internal
   * bounded plane point placer is created and set to match the bounds
   * of the displayed image.
   */
  void SetImageActor(vtkImageActor*);
  vtkGetObjectMacro(ImageActor, vtkImageActor);
  //@}

  //@{
  /**
   * Optionally, you may set bounds to restrict the placement of the points.
   * The placement of points will then be constrained to lie not only on
   * the ImageActor but also within the bounds specified. If no bounds are
   * specified, they may lie anywhere on the supplied ImageActor.
   */
  vtkSetVector6Macro(Bounds, double);
  vtkGetVector6Macro(Bounds, double);
  //@}

  /**
   * Set the world tolerance. This propagates it to the internal
   * BoundedPlanePointPlacer.
   */
  void SetWorldTolerance(double s) override;

protected:
  vtkImageActorPointPlacer();
  ~vtkImageActorPointPlacer() override;

  // The reference image actor. Must be configured before this placer
  // is used.
  vtkImageActor* ImageActor;

  // The internal placer.
  vtkBoundedPlanePointPlacer* Placer;

  // Used to keep track of whether the bounds of the
  // input image have changed
  double SavedBounds[6];

  // See the SetBounds method
  double Bounds[6];

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

#endif
