///|
/// A single calibration frame containing 3D object points and corresponding 2D detected image corners.
pub(all) struct CalibrationFrame {
  object_points : Array[Point3D]
  image_points : Array[Point2D]
} derive(Debug, Eq)

///|
/// Creates a new CalibrationFrame.
pub fn CalibrationFrame::new(
  object_points : Array[Point3D],
  image_points : Array[Point2D],
) -> CalibrationFrame {
  { object_points, image_points }
}

///|
/// Result of camera calibration procedure.
pub(all) struct CalibrationResult {
  camera_intrinsics : CameraIntrinsics
  extrinsic_poses : Array[Pose3D]
  per_view_errors : Array[Double]
  overall_rmse : Double
} derive(Debug, Eq)

///|
/// Container for collecting multi-view calibration data from ChArUco / Chessboard frames.
pub(all) struct CameraCalibrator {
  image_size : Size2D
  frames : Array[CalibrationFrame]
} derive(Debug, Eq)

///|
/// Creates a new CameraCalibrator.
pub fn CameraCalibrator::new(image_size : Size2D) -> CameraCalibrator {
  { image_size, frames: [] }
}

///|
/// Adds a calibration frame with detected point correspondences.
pub fn CameraCalibrator::add_frame(
  self : CameraCalibrator,
  object_points : Array[Point3D],
  image_points : Array[Point2D],
) -> Unit {
  if object_points.length() >= 4 &&
    object_points.length() == image_points.length() {
    self.frames.push(CalibrationFrame::new(object_points, image_points))
  }
}