/**
   * Transforms the view such that the entire original image is visible after lens distortion has
   * been removed. The appropriate {@link PointTransform_F32} is returned and a new set of intrinsic
   * camera parameters for the "virtual" camera that is associated with the returned transformed.
   *
   * <p>The original image coordinate system is maintained even if the intrinsic parameter flipY is
   * true.
   *
   * @param param Intrinsic camera parameters.
   * @param paramAdj If not null, the new camera parameters are stored here.
   * @return New transform that adjusts the view and removes lens distortion..
   */
  public static PointTransform_F32 fullView(
      IntrinsicParameters param, IntrinsicParameters paramAdj) {

    RemoveRadialPtoP_F32 removeDistort = new RemoveRadialPtoP_F32();
    AddRadialPtoP_F32 addDistort = new AddRadialPtoP_F32();
    removeDistort.set(param.fx, param.fy, param.skew, param.cx, param.cy, param.radial);
    addDistort.set(param.fx, param.fy, param.skew, param.cx, param.cy, param.radial);

    Rectangle2D_F32 bound =
        DistortImageOps.boundBox_F32(
            param.width, param.height, new PointToPixelTransform_F32(removeDistort));

    double scaleX = bound.width / param.width;
    double scaleY = bound.height / param.height;

    double scale = Math.max(scaleX, scaleY);

    // translation
    double deltaX = bound.tl_x;
    double deltaY = bound.tl_y;

    // adjustment matrix
    DenseMatrix64F A = new DenseMatrix64F(3, 3, true, scale, 0, deltaX, 0, scale, deltaY, 0, 0, 1);

    PointTransform_F32 tranAdj =
        PerspectiveOps.adjustIntrinsic_F32(addDistort, false, param, A, paramAdj);

    if (param.flipY) {
      PointTransform_F32 flip = new FlipVertical_F32(param.height);
      return new SequencePointTransform_F32(flip, tranAdj, flip);
    } else return tranAdj;
  }
  /**
   * Adjusts the view such that each pixel has a correspondence to the original image while
   * maximizing the view area. In other words no black regions which can cause problems for some
   * image processing algorithms.
   *
   * <p>The original image coordinate system is maintained even if the intrinsic parameter flipY is
   * true.
   *
   * @param param Intrinsic camera parameters.
   * @param paramAdj If not null, the new camera parameters are stored here.
   * @return New transform that adjusts the view and removes lens distortion..
   */
  public static PointTransform_F32 allInside(
      IntrinsicParameters param, IntrinsicParameters paramAdj) {
    RemoveRadialPtoP_F32 removeDistort = new RemoveRadialPtoP_F32();
    AddRadialPtoP_F32 addDistort = new AddRadialPtoP_F32();
    removeDistort.set(param.fx, param.fy, param.skew, param.cx, param.cy, param.radial);
    addDistort.set(param.fx, param.fy, param.skew, param.cx, param.cy, param.radial);

    Rectangle2D_F32 bound =
        LensDistortionOps.boundBoxInside(
            param.width, param.height, new PointToPixelTransform_F32(removeDistort));

    // ensure there are no strips of black
    LensDistortionOps.roundInside(bound);

    double scaleX = bound.width / param.width;
    double scaleY = bound.height / param.height;

    double scale = Math.min(scaleX, scaleY);

    // translation and shift over so that the small axis is in the middle
    double deltaX = bound.tl_x + (scaleX - scale) * param.width / 2.0;
    double deltaY = bound.tl_y + (scaleY - scale) * param.height / 2.0;

    // adjustment matrix
    DenseMatrix64F A = new DenseMatrix64F(3, 3, true, scale, 0, deltaX, 0, scale, deltaY, 0, 0, 1);

    PointTransform_F32 tranAdj =
        PerspectiveOps.adjustIntrinsic_F32(addDistort, false, param, A, paramAdj);

    if (param.flipY) {
      PointTransform_F32 flip = new FlipVertical_F32(param.height);
      return new SequencePointTransform_F32(flip, tranAdj, flip);
    } else return tranAdj;
  }
  /**
   * Transform from undistorted pixel coordinates to distorted with radial pixel coordinates
   *
   * <p>NOTE: The original image coordinate system is maintained even if the intrinsic parameter
   * flipY is true.
   *
   * @param param Intrinsic camera parameters
   * @return Transform from undistorted to distorted image.
   */
  public static PointTransform_F32 transformPixelToRadial_F32(IntrinsicParameters param) {
    AddRadialPtoP_F32 radialDistort = new AddRadialPtoP_F32();
    radialDistort.set(param.fx, param.fy, param.skew, param.cx, param.cy, param.radial);

    if (param.flipY) {
      PointTransform_F32 flip = new FlipVertical_F32(param.height);
      return new SequencePointTransform_F32(flip, radialDistort, flip);
    } else {
      return radialDistort;
    }
  }