import type Point from "../../Point.js";

/**
 * The Transformation class represents 2D transformations that can be applied to geometries using the [affineTransformOperator](https://developers.arcgis.com/javascript/latest/references/core/geometry/operators/affineTransformOperator/). All transformations are applied in the spatial reference units of the input geometries.
 *
 * @since 4.31
 */
export default class Transformation {
  constructor();
  /**
   * Calculates distance errors for a transformation on a given set of the input points to the output points.
   * This method is usually used to calculate errors for the transformation initialized by [initializeFromControlPoints()](https://developers.arcgis.com/javascript/latest/references/core/geometry/operators/support/Transformation/#initializeFromControlPoints).
   *
   * The length of the `input` and `output` arrays must be the same.
   *
   * @param input - The input points to transform from.
   * @param output - The output points to transform to.
   * @returns Returns an object representing the errors incurred during transformation.
   * @example
   * // Calculate the errors for a transformation
   * const errors = transformation.calculateErrors(inputPoints, outputPoints);
   * // Example returned object:
   * // { rms: 0.5, errorsOut: [0.1, 0.2, 0.3, 0.4, 0.5] }
   */
  calculateErrors(input: Point[], output: Point[]): ErrorResult;
  /**
   * Flips all the `x` coordinates of geometries on the vertical y-axis (right or left) that is centered between `x0` and `x1`.
   * For example, if `x0` is 0 and `x1` is 10, all the `x` coordinates of the geometries will be flipped, or mirrored, on the vertical axis centered at `x = 5`.
   *
   * ![FlipX transformation](https://developers.arcgis.com/javascript/latest/assets/references/core/operators/flipX.png "FlipX transformation")
   *
   * @param x0 - The x-coordinate of the first geometry.
   * @param x1 - The x-coordinate of the second geometry.
   * @example
   * // Flip the x-coordinates of a geometry on the vertical axis
   * const transform = new Transformation();
   * transform.flipX(0, 10);
   * const result = affineTransformOperator.execute(polygon, transform);
   *
   * // Flip the x-coordinates of a geometry on the vertical axis centered at the geometry's center
   * const centerX = polygon.extent.center.x;
   * transform.flipX(centerX, centerX);
   * const result = affineTransformOperator.execute(polygon, transform);
   */
  flipX(x0: number, x1: number): this;
  /**
   * Flips all the `y` coordinates of geometries on the horizontal x-axis (up or down) that is centered between `y0` and `y1`.
   * For example, if `y0` is 0 and `y1` is 10, all the `y` coordinates of the geometries will be flipped, or mirrored, on the horizontal axis centered at `y = 5`.
   *
   * ![FlipY transformation](https://developers.arcgis.com/javascript/latest/assets/references/core/operators/flipY.png "FlipY transformation")
   *
   * @param y0 - The y-coordinate of the first geometry.
   * @param y1 - The y-coordinate of the second geometry.
   * @example
   * // Flip the y-coordinates of a geometry on the vertical axis
   * transformation.flipY(0, 10);
   * const result = affineTransformOperator.execute(polygon, transform);
   *
   * // Flip the y-coordinates of a geometry on the horizontal axis centered at the geometry's center
   * const centerY = polygon.extent.center.y;
   * transform.flipY(centerY, centerY);
   * const result = affineTransformOperator.execute(polygon, transform);
   */
  flipY(y0: number, y1: number): this;
  /**
   * Initializes a new transformation from the input and output control points.
   * Uses least squares method to find the best fit transformation.
   * Adding control points allows you to snap lines and polygons to the input and output points on a map.
   *
   * The length of the `input` and `output` arrays must be the same.
   *
   * @param type - The type of transformation to initialize.
   *
   * Value | Description
   * ------|------------
   * "conformal" | Preserves the angles between curves.
   * "general" | Preserves lines and parallelisms. Does not preserve angles or lengths.
   * @param input - The input points to transform from.
   * @param output - The output points to transform to.
   * @param inverseOut - The transformation instance that is the inverse of the calculated transformation.
   * @example
   * // Initialize a transformation from control points
   * transformation.initializeFromControlPoints("conformal", inputPoints, outputPoints);
   */
  initializeFromControlPoints(type: "conformal" | "general", input: Point[], output: Point[], inverseOut?: Transformation): void;
  /**
   * Determines if the transformation is in its default state, which is an identity matrix.
   *
   * @returns Returns `true` if the transformation is the default and has not been changed.
   * There will be no change in the geometries when applying the transformation.
   * @see [setIdentity()](https://developers.arcgis.com/javascript/latest/references/core/geometry/operators/support/Transformation/#setIdentity)
   */
  isIdentity(): boolean;
  /**
   * Rotates the geometries by the specified angle in degrees around the point specified by the x and y coordinates.
   * The point can be the center of the geometries or any other point.
   *
   * ![Rotate transformation](https://developers.arcgis.com/javascript/latest/assets/references/core/operators/rotate.png "Rotate transformation")
   *
   * @param angleInDegrees - The angle to rotate the geometries in degrees.
   * @param rotationX - The x-coordinate of the point to rotate around.
   * @param rotationY - The y-coordinate of the point to rotate around.
   * @example
   * // Rotate a geometry
   * transformation.rotate(90, 0, 0);
   * const result = affineTransformOperator.execute(polygon, transform);
   */
  rotate(angleInDegrees: number, rotationX?: number, rotationY?: number): this;
  /**
   * Resizes the geometries by the specified scale factors defined by the x and y coordinates.
   * The coordinates define how much scaling is applied to the geometries in the x and y directions.
   *
   * ![Scale transformation](https://developers.arcgis.com/javascript/latest/assets/references/core/operators/scale.png "Scale transformation")
   *
   * @param x - The x-coordinate that defines the horizontal scale factor.
   * @param y - The y-coordinate that defines the vertical scale factor.
   * @example
   * // Scale a geometry
   * transformation.scale(2, 2);
   * const result = affineTransformOperator.execute(polygon, transform);
   */
  scale(x: number, y: number): this;
  /**
   * Use this method to reset the transformation to its default state, which is an identity matrix.
   * This method is useful when reusing the class instance for multiple transformations.
   *
   * @see [Wikipedia - Identity Matrix](https://en.wikipedia.org/wiki/Identity_matrix)
   */
  setIdentity(): void;
  /** Use this method to swap the x and y coordinate values in the transformation. An example usage is when slicing vertically with the [polgonSlicerOperator.findSlicesByArea()](https://developers.arcgis.com/javascript/latest/references/core/geometry/operators/polygonSlicerOperator/#findSlicesByArea) method. */
  setSwapCoordinates(): this;
  /**
   * Shifts a geometry's points by the specified proportion in parallel to the x and y directions,
   * except those points that are along the shear axis, which is a line defined by the x and y coordinates.
   * This transformation preserves lines and parallelisms, however it may distort angles and distances.
   * Applying this transformation will not change a geometry's area.
   *
   * ![Shear transformation](https://developers.arcgis.com/javascript/latest/assets/references/core/operators/shear.png "Shear transformation")
   *
   * @param proportionX - The proportion to shear the geometry in the x direction.
   * @param proportionY - The proportion to shear the geometry in the y direction.
   * @example
   * // Shear a geometry
   * transformation.shear(0.5, 0.5);
   * const result = affineTransformOperator.execute(polygon, transform);
   */
  shear(proportionX: number, proportionY: number): this;
  /**
   * Shifts all the coordinates of the geometries by the distance and direction between the specified `x` and `y` coordinates and their current location. This operation does not change the size or shape of the geometries.
   *
   * ![Shift transformation](https://developers.arcgis.com/javascript/latest/assets/references/core/operators/shift.png "Shift transformation")
   *
   * @param x - The x-coordinate to shift by.
   * @param y - The y-coordinate to shift by.
   * @example
   * // Shift the coordinates of a geometry
   * transformation.shift(5, 2);
   * const result = affineTransformOperator.execute(polygon, transform);
   */
  shift(x: number, y: number): this;
}

/** Object returned from the [calculateErrors()](https://developers.arcgis.com/javascript/latest/references/core/geometry/operators/support/Transformation/#calculateErrors) method. */
export interface ErrorResult {
  /** The root mean square (`rms`) of the 'average' distance error between the specified `output` points and the transformed `input` points. */
  rms: number;
  /** Contains the errors of the individual distance differences between specific pairs of points. */
  errorsOut: number[];
}