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

  Program:   Visualization Toolkit
  Module:    vtkTickPlacer3D.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 vtkTickPlacer3D
 * @brief Places non-overlapping tick labels along a 3D axis.
 *
 * This assumes that the labels will be rendered using vtkTextActor2D,
 * vtkTextMapper, or vtkBillboardTextActor3D. Specifically, it assumes pixel
 * aligned text rendering.
 */

#ifndef vtkTickPlacer3D_h
#define vtkTickPlacer3D_h

#include "vtkRenderingAnnotationModule.h" // For export macro
#include "vtkNew.h" // For vtkNew
#include "vtkObject.h"
#include "vtkRect.h" // For vtkRect
#include "vtkVector.h" // For vtkVector

class vtkBitArray;
class vtkCoordinate;
class vtkDoubleArray;
class vtkIntArray;
class vtkRenderer;
class vtkStringArray;
class vtkTextProperty;

class VTKRENDERINGANNOTATION_EXPORT vtkTickPlacer3D: public vtkObject
{
public:
  static vtkTickPlacer3D* New();
  vtkTypeMacro(vtkTickPlacer3D, vtkObject)
  void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE;

  // Keep in sync with vtkAxis:
  enum NotationType
  {
    Standard = 0, ///< Standard iostream formatting
    Scientific,   ///< Scientific iostream formatting
    Fixed,        ///< Fixed iostream formatting
    Printf        ///< Custom printf format string.
  };

  /**
   * Set the NotationType for formatting the scalar values.
   * @{
   */
  vtkSetMacro(Notation, NotationType)
  vtkGetMacro(Notation, NotationType)
  /**@}*/

  /**
   * Set the precision for Scientific and Fixed notation formats,
   * @{
   */
  vtkSetMacro(Precision, int)
  vtkGetMacro(Precision, int)
  /**@}*/

  /**
   * Set the printf-style format string for Printf notation.
   * @{
   */
  vtkGetStringMacro(Format)
  vtkSetStringMacro(Format)
  /**@}*/

  /**
   * The start/end of the axis in world coordinates. Start must correspond to
   * GetRange()[0], and End must correspond to GetRange()[1].
   * @{
   */
  vtkGetMacro(StartPoint, vtkVector3d)
  vtkSetMacro(StartPoint, vtkVector3d)
  vtkGetMacro(EndPoint, vtkVector3d)
  vtkSetMacro(EndPoint, vtkVector3d)
  /**@}*/

  /**
   * The range for values to use for the tick labels. Range[0] must correspond
   * to StartPoint, and Range[1] must correspond to EndPoint.
   * @{
   */
  vtkGetVector2Macro(Range, double)
  vtkSetVector2Macro(Range, double)
  /**@}*/

  /**
   * The maximum number of intermediate tick marks. 0 is unlimited, and the
   * labels marking the start/end of the range are not included.
   * @{
   */
  vtkGetMacro(MaximumNumberOfTicks, vtkIdType)
  vtkSetMacro(MaximumNumberOfTicks, vtkIdType)
  /**@}*/

  /**
   * An array explicitly specifying the values to place tick marks at. If a
   * value is not bounded by the specified Range, it is ignored. Set to NULL
   * for autogenerated ticks.
   * @{
   */
  virtual void SetCustomTickValues(vtkDoubleArray *ticks);
  vtkGetObjectMacro(CustomTickValues, vtkDoubleArray)
  /**@}*/

  /**
   * The text property to use when computing label size.
   * @{
   */
  virtual void SetTextProperty(vtkTextProperty *tprop);
  vtkGetObjectMacro(TextProperty, vtkTextProperty)
  /**@}*/

  /**
   * The renderer used for coordinate conversion to detect label overlap in
   * display space.
   * @{
   */
  virtual void SetRenderer(vtkRenderer *ren);
  vtkGetObjectMacro(Renderer, vtkRenderer)
  /**@}*/

  /**
   * Update the results arrays based on the current state.
   */
  void Update();

  /**
   * The locations of the tick marks, specified as fractions of the axis.
   */
  vtkGetNewMacro(TickPositions, vtkDoubleArray)

  /**
   * The scalar values corresponding to the tick marks.
   */
  vtkGetNewMacro(TickValues, vtkDoubleArray)

  /**
   * Formatted labels for each tick mark.
   */
  vtkGetNewMacro(TickLabels, vtkStringArray)

  /**
   * Mask indicating whether a ticks label should be shown or not. Disabled
   * labels are on low-priority ticks that overlap with other labels in display
   * space.
   */
  vtkGetNewMacro(TickLabelMask, vtkBitArray)

  /**
   * A 4 component int array containing the x, y, width, and height metadata
   * for each tick label.
   */
  vtkGetNewMacro(TickLabelBounds, vtkIntArray)

  /**
   * The total number of ticks.
   */
  vtkIdType GetNumberOfTicks();

protected:
  vtkTickPlacer3D();
  ~vtkTickPlacer3D();

  /**
   * Prepare the working state (get display coordinates, etc).
   */
  void Prepare();

  /**
   * Looks at range, computes a delta that will look nice, as well as the
   * first tick value inside of (not including) the range.
   */
  void GetTickSpecification();

  void ClearResults();

  /**
   * Compute and fill the result arrays.
   */
  void PopulateResults();

  /**
   * Add an entry to the result arrays for the specified scalar value and
   * world coordinate.
   */
  void AddTick(double scalarValue, const vtkVector3d &posWC);

  /**
   * Removes a tick's metadata from all result arrays.
   */
  void RemoveTick(vtkIdType idx);

  /**
   * Check all tick marks to see which overlap, removing those that do. Tries
   * to always keep the first and last labels.
   */
  void PruneOverlaps();

  /**
   * Remove all labels that overlap the designated 'keeper'.
   */
  void PruneOverlappingLabels(vtkIdType keeper, bool isEndpoint);

  /**
   * Convert a number to a string using the current format spec.
   */
  vtkStdString FormatScalar(double value) const;

  /**
   * Compute the bounding rect for the string rendered using the current
   * text properties / renderer DPI.
   */
  vtkRecti GetTextBoundingRect(const vtkStdString &str);

  vtkIdType MaximumNumberOfTicks;

  vtkVector3d StartPoint; // In world coordinates.
  vtkVector3d EndPoint;
  double Range[2]; // Scalar range
  NotationType Notation;
  int Precision;
  char *Format; // sprintf format
  vtkRenderer *Renderer; // Used for viewport conversions.
  vtkTextProperty *TextProperty; // Text formatting
  vtkDoubleArray *CustomTickValues; // For explicitly specified ticks

  // Result time
  vtkTimeStamp BuildTime;

  // Results:
  vtkNew<vtkDoubleArray> TickPositions; // 3D world coordinates
  vtkNew<vtkDoubleArray> TickValues; // Scalar values
  vtkNew<vtkStringArray> TickLabels; // Formatted strings
  vtkNew<vtkBitArray> TickLabelMask; // Whether label will render w/o overlap
  vtkNew<vtkIntArray> TickLabelBounds; // X, Y, width, height

  // Working ivars:
  vtkNew<vtkCoordinate> Converter;
  int DPI;
  vtkVector2d StartPixel;
  vtkVector2d EndPixel;
  vtkVector3d WCVector;
  vtkVector2d DCVector;

  double FirstTick; // First tick inside (Range[0], Range[1])
  double Delta; // May be zero/negative, meaning no ticks, just range markers

private:
  vtkTickPlacer3D(const vtkTickPlacer3D&) VTK_DELETE_FUNCTION;
  void operator=(const vtkTickPlacer3D&) VTK_DELETE_FUNCTION;
};

#endif // vtkTickPlacer3D_h
