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

  Program:   Visualization Toolkit
  Module:    vtkImageCanvasSource2D.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   vtkImageCanvasSource2D
 * @brief   Paints on a canvas
 *
 * vtkImageCanvasSource2D is a source that starts as a blank image.
 * you may add to the image with two-dimensional drawing routines.
 * It can paint multi-spectral images.
 */

#ifndef vtkImageCanvasSource2D_h
#define vtkImageCanvasSource2D_h

#include "vtkImageAlgorithm.h"
#include "vtkImagingSourcesModule.h" // For export macro

class VTKIMAGINGSOURCES_EXPORT vtkImageCanvasSource2D : public vtkImageAlgorithm
{
public:
  /**
   * Construct an instance of vtkImageCanvasSource2D with no data.
   */
  static vtkImageCanvasSource2D* New();

  vtkTypeMacro(vtkImageCanvasSource2D, vtkImageAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  ///@{
  /**
   * Set/Get DrawColor.  This is the value that is used when filling data
   * or drawing lines. Default is (0,0,0,0)
   */
  vtkSetVector4Macro(DrawColor, double);
  vtkGetVector4Macro(DrawColor, double);
  ///@}

  /**
   * Set DrawColor to (a, 0, 0, 0)
   */
  void SetDrawColor(double a) { this->SetDrawColor(a, 0.0, 0.0, 0.0); }

  /**
   * Set DrawColor to (a, b, 0, 0)
   */
  void SetDrawColor(double a, double b) { this->SetDrawColor(a, b, 0.0, 0.0); }

  /**
   * Set DrawColor to (a, b, c, 0)
   */
  void SetDrawColor(double a, double b, double c) { this->SetDrawColor(a, b, c, 0.0); }

  /**
   * Initialize the canvas with a given volume
   */
  void InitializeCanvasVolume(vtkImageData* volume);

  ///@{
  /**
   * Set the pixels inside the box (min0, max0, min1, max1) to the current
   * DrawColor
   */
  void FillBox(int min0, int max0, int min1, int max1);
  void FillTube(int x0, int y0, int x1, int y1, double radius);
  void FillTriangle(int x0, int y0, int x1, int y1, int x2, int y2);
  void DrawCircle(int c0, int c1, double radius);
  void DrawPoint(int p0, int p1);
  void DrawSegment(int x0, int y0, int x1, int y1);
  void DrawSegment3D(double* p0, double* p1);
  void DrawSegment3D(double x1, double y1, double z1, double x2, double y2, double z2)
  {
    double p1[3], p2[3];
    p1[0] = x1;
    p1[1] = y1;
    p1[2] = z1;
    p2[0] = x2;
    p2[1] = y2;
    p2[2] = z2;
    this->DrawSegment3D(p1, p2);
  }
  ///@}

  /**
   * Draw subimage of the input image in the canvas at position x0 and
   * y0. The subimage is defined with sx, sy, width, and height.
   */
  void DrawImage(int x0, int y0, vtkImageData* i) { this->DrawImage(x0, y0, i, -1, -1, -1, -1); }
  void DrawImage(int x0, int y0, vtkImageData*, int sx, int sy, int width, int height);

  /**
   * Fill a colored area with another color. (like connectivity)
   * All pixels connected (and with the same value) to pixel (x, y)
   * get replaced by the current "DrawColor".
   */
  void FillPixel(int x, int y);

  ///@{
  /**
   * These methods set the WholeExtent of the output
   * It sets the size of the canvas.
   * Extent is a min max 3D box.  Minimums and maximums are inclusive.
   */
  void SetExtent(int* extent);
  void SetExtent(int x1, int x2, int y1, int y2, int z1, int z2);
  ///@}

  ///@{
  /**
   * The drawing operations can only draw into one 2D XY plane at a time.
   * If the canvas is a 3D volume, then this z value is used
   * as the default for 2D operations. The default is 0.
   */
  vtkSetMacro(DefaultZ, int);
  vtkGetMacro(DefaultZ, int);
  ///@}

  ///@{
  /**
   * Set/Get Ratio. This is the value that is used to pre-multiply each
   * (x, y, z) drawing coordinates (including DefaultZ). The default
   * is (1, 1, 1)
   */
  vtkSetVector3Macro(Ratio, double);
  vtkGetVector3Macro(Ratio, double);
  ///@}

  ///@{
  /**
   * Set the number of scalar components
   */
  virtual void SetNumberOfScalarComponents(int i);
  virtual int GetNumberOfScalarComponents() const;
  ///@}

  ///@{
  /**
   * Set/Get the data scalar type (i.e VTK_DOUBLE). Note that these methods
   * are setting and getting the pipeline scalar type. i.e. they are setting
   * the type that the image data will be once it has executed. Until the
   * REQUEST_DATA pass the actual scalars may be of some other type. This is
   * for backwards compatibility
   */
  void SetScalarTypeToFloat() { this->SetScalarType(VTK_FLOAT); }
  void SetScalarTypeToDouble() { this->SetScalarType(VTK_DOUBLE); }
  void SetScalarTypeToInt() { this->SetScalarType(VTK_INT); }
  void SetScalarTypeToUnsignedInt() { this->SetScalarType(VTK_UNSIGNED_INT); }
  void SetScalarTypeToLong() { this->SetScalarType(VTK_LONG); }
  void SetScalarTypeToUnsignedLong() { this->SetScalarType(VTK_UNSIGNED_LONG); }
  void SetScalarTypeToShort() { this->SetScalarType(VTK_SHORT); }
  void SetScalarTypeToUnsignedShort() { this->SetScalarType(VTK_UNSIGNED_SHORT); }
  void SetScalarTypeToUnsignedChar() { this->SetScalarType(VTK_UNSIGNED_CHAR); }
  void SetScalarTypeToChar() { this->SetScalarType(VTK_CHAR); }
  void SetScalarType(int);
  int GetScalarType() const;
  ///@}

protected:
  vtkImageCanvasSource2D();
  // Destructor: Deleting a vtkImageCanvasSource2D automatically deletes the
  // associated vtkImageData.  However, since the data is reference counted,
  // it may not actually be deleted.
  ~vtkImageCanvasSource2D() override;

  vtkImageData* ImageData;
  int WholeExtent[6];
  double DrawColor[4];
  int DefaultZ;
  double Ratio[3];

  int ClipSegment(int& a0, int& a1, int& b0, int& b1);

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

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

#endif
