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

  Program:   Visualization Toolkit
  Module:    vtkAxesTransformRepresentation.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   vtkAxesTransformRepresentation
 * @brief   represent the vtkAxesTransformWidget
 *
 * The vtkAxesTransformRepresentation is a representation for the
 * vtkAxesTransformWidget. This representation consists of a origin sphere
 * with three tubed axes with cones at the end of the axes. In addition an
 * optional label provides delta values of motion. Note that this particular
 * widget draws its representation in 3D space, so the widget can be
 * occluded.
 * @sa
 * vtkDistanceWidget vtkDistanceRepresentation vtkDistanceRepresentation2D
 */

#ifndef vtkAxesTransformRepresentation_h
#define vtkAxesTransformRepresentation_h

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

class vtkHandleRepresentation;
class vtkPoints;
class vtkPolyData;
class vtkPolyDataMapper;
class vtkActor;
class vtkVectorText;
class vtkFollower;
class vtkBox;
class vtkCylinderSource;
class vtkGlyph3D;
class vtkDoubleArray;
class vtkTransformPolyDataFilter;
class vtkProperty;

class VTKINTERACTIONWIDGETS_EXPORT vtkAxesTransformRepresentation : public vtkWidgetRepresentation
{
public:
  /**
   * Instantiate class.
   */
  static vtkAxesTransformRepresentation* New();

  //@{
  /**
   * Standard VTK methods.
   */
  vtkTypeMacro(vtkAxesTransformRepresentation, vtkWidgetRepresentation);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  //@}

  //@{
  /**
   * Set/Get the two handle representations used for the
   * vtkAxesTransformWidget. (Note: properties can be set by grabbing these
   * representations and setting the properties appropriately.)
   */
  vtkGetObjectMacro(OriginRepresentation, vtkHandleRepresentation);
  vtkGetObjectMacro(SelectionRepresentation, vtkHandleRepresentation);
  //@}

  //@{
  /**
   * Methods to Set/Get the coordinates of the two points defining
   * this representation. Note that methods are available for both
   * display and world coordinates.
   */
  double* GetOriginWorldPosition();
  void GetOriginWorldPosition(double pos[3]);
  void SetOriginWorldPosition(double pos[3]);
  void SetOriginDisplayPosition(double pos[3]);
  void GetOriginDisplayPosition(double pos[3]);
  //@}

  /**
   * Specify a scale to control the size of the widget. Large values make the
   * the widget larger.
   */

  //@{
  /**
   * The tolerance representing the distance to the widget (in pixels) in
   * which the cursor is considered near enough to the end points of
   * the widget to be active.
   */
  vtkSetClampMacro(Tolerance, int, 1, 100);
  vtkGetMacro(Tolerance, int);
  //@}

  //@{
  /**
   * Specify the format to use for labelling information during
   * transformation. Note that an empty string results in no label, or a
   * format string without a "%" character will not print numeric values.
   */
  vtkSetStringMacro(LabelFormat);
  vtkGetStringMacro(LabelFormat);
  //@}

  /**
   * Enum used to communicate interaction state.
   */
  enum
  {
    Outside = 0,
    OnOrigin,
    OnX,
    OnY,
    OnZ,
    OnXEnd,
    OnYEnd,
    OnZEnd
  };

  //@{
  /**
   * The interaction state may be set from a widget (e.g., vtkLineWidget2) or
   * other object. This controls how the interaction with the widget
   * proceeds. Normally this method is used as part of a handshaking
   * process with the widget: First ComputeInteractionState() is invoked that
   * returns a state based on geometric considerations (i.e., cursor near a
   * widget feature), then based on events, the widget may modify this
   * further.
   */
  vtkSetClampMacro(InteractionState, int, Outside, OnZEnd);
  //@}

  //@{
  /**
   * Method to satisfy superclasses' API.
   */
  void BuildRepresentation() override;
  int ComputeInteractionState(int X, int Y, int modify = 0) override;
  void StartWidgetInteraction(double e[2]) override;
  void WidgetInteraction(double e[2]) override;
  double* GetBounds() override;
  //@}

  //@{
  /**
   * Methods required by vtkProp superclass.
   */
  void ReleaseGraphicsResources(vtkWindow* w) override;
  int RenderOpaqueGeometry(vtkViewport* viewport) override;
  int RenderTranslucentPolygonalGeometry(vtkViewport* viewport) override;
  //@}

  //@{
  /**
   * Scale text (font size along each dimension). This helps control
   * the appearance of the 3D text.
   */
  void SetLabelScale(double x, double y, double z)
  {
    double scale[3];
    scale[0] = x;
    scale[1] = y;
    scale[2] = z;
    this->SetLabelScale(scale);
  }
  virtual void SetLabelScale(double scale[3]);
  virtual double* GetLabelScale();
  //@}

  /**
   * Get the distance annotation property
   */
  virtual vtkProperty* GetLabelProperty();

protected:
  vtkAxesTransformRepresentation();
  ~vtkAxesTransformRepresentation() override;

  // The handle and the rep used to close the handles
  vtkHandleRepresentation* OriginRepresentation;
  vtkHandleRepresentation* SelectionRepresentation;

  // Selection tolerance for the handles
  int Tolerance;

  // Format for printing the distance
  char* LabelFormat;

  // The line
  vtkPoints* LinePoints;
  vtkPolyData* LinePolyData;
  vtkPolyDataMapper* LineMapper;
  vtkActor* LineActor;

  // The distance label
  vtkVectorText* LabelText;
  vtkPolyDataMapper* LabelMapper;
  vtkFollower* LabelActor;

  // The 3D disk tick marks
  vtkPoints* GlyphPoints;
  vtkDoubleArray* GlyphVectors;
  vtkPolyData* GlyphPolyData;
  vtkCylinderSource* GlyphCylinder;
  vtkTransformPolyDataFilter* GlyphXForm;
  vtkGlyph3D* Glyph3D;
  vtkPolyDataMapper* GlyphMapper;
  vtkActor* GlyphActor;

  // Support GetBounds() method
  vtkBox* BoundingBox;

  double LastEventPosition[3];

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

#endif
