///|
pub(all) struct Point {
  x : Double
  y : Double
} derive(Debug)

///|
pub fn Point::Point(x~ : Double, y~ : Double) -> Point {
  { x, y }
}

///|
pub(all) struct Line {
  a : Double
  b : Double
  c : Double
} derive(Debug)

///|
pub fn Line::Line(a~ : Double, b~ : Double, c~ : Double) -> Line {
  let norm = (a * a + b * b).sqrt()
  if norm <= 0.0 {
    { a: 0.0, b: 1.0, c: 0.0 }
  } else {
    { a: a / norm, b: b / norm, c: c / norm }
  }
}

///|
pub(all) struct Circle {
  center : Point
  radius : Double
  rms_error : Double
} derive(Debug)

///|
pub fn Circle::Circle(
  center~ : Point,
  radius~ : Double,
  rms_error~ : Double,
) -> Circle {
  { center, radius, rms_error }
}

///|
pub(all) enum EdgeMode {
  Rising
  Falling
  Both
} derive(Debug, Eq)

///|
pub(all) struct EdgePoint {
  point : Point
  strength : Double
  polarity : Int
} derive(Debug)

///|
pub(all) struct ProfileSample {
  point : Point
  value : Double
  gradient : Double
} derive(Debug)

///|
pub(all) struct Tolerance {
  nominal : Double
  lower : Double
  upper : Double
  unit : String
} derive(Debug)

///|
pub(all) enum MeasurementDecision {
  Pass
  Warn
  Fail
} derive(Debug, Eq)

///|
pub(all) struct Measurement {
  name : String
  value : Double
  unit : String
  decision : MeasurementDecision
  deviation : Double
} derive(Debug)

///|
pub(all) struct MeasurementReport {
  part_id : String
  measurements : Array[Measurement]
  notes : Array[String]
} derive(Debug)

///|
pub(all) struct Bounds {
  min_x : Int
  min_y : Int
  max_x : Int
  max_y : Int
} derive(Debug, Eq)

///|
pub(all) struct DoubleBounds {
  min : Double
  max : Double
} derive(Debug)

///|
pub(all) struct StatsSummary {
  count : Int
  sum : Double
  mean : Double
  variance : Double
  standard_deviation : Double
  minimum : Double
  maximum : Double
  median : Double
  ordered : Array[Double]
} derive(Debug)

///|
pub fn StatsSummary::percentile(summary : StatsSummary, _q : Double) -> Double {
  if summary.ordered.is_empty() {
    0.0
  } else {
    let q = _q.clamp(min=0.0, max=1.0)
    let position = q * Double::from_int(summary.ordered.length() - 1)
    let lower = position.floor().to_int()
    let upper = position.ceil().to_int()
    if lower == upper {
      summary.ordered[lower]
    } else {
      let fraction = position - Double::from_int(lower)
      summary.ordered[lower] * (1.0 - fraction) +
      summary.ordered[upper] * fraction
    }
  }
}

///|
pub(all) struct BinaryMask {
  width : Int
  height : Int
  values : Array[Bool]
} derive(Debug)

///|
pub(all) struct Component {
  label : Int
  area : Int
  bounds : Bounds
  centroid : Point
  perimeter : Double
  circularity : Double
} derive(Debug)

///|
pub(all) struct AffineTransform {
  a : Double
  b : Double
  c : Double
  d : Double
  tx : Double
  ty : Double
} derive(Debug)

///|
pub(all) struct CalibrationFit {
  transform : AffineTransform
  residuals : Array[Double]
  rms_error : Double
  max_error : Double
} derive(Debug)

///|
pub(all) struct MeasurementSummary {
  total : Int
  pass : Int
  warn : Int
  fail : Int
  acceptance_rate : Double
  values : StatsSummary
} derive(Debug)

///|
pub(all) struct BatchRun {
  id : String
  records : Array[Measurement]
} derive(Debug)

///|
pub(all) struct EdgePolicy {
  low_threshold : Double
  high_threshold : Double
  mode : EdgeMode
  min_strength : Double
} derive(Debug)

///|
pub(all) struct PipelineDiagnostic {
  stage : String
  message : String
  severity : MeasurementDecision
} derive(Debug)

///|
pub(all) struct FeatureMeasurement {
  name : String
  value : Double
  unit : String
  confidence : Double
  decision : MeasurementDecision
} derive(Debug)

///|
pub(all) struct Vector2 {
  x : Double
  y : Double
} derive(Debug)

///|
pub fn Vector2::Vector2(x~ : Double, y~ : Double) -> Vector2 {
  { x, y }
}

///|
pub(all) struct Matrix2 {
  m00 : Double
  m01 : Double
  m10 : Double
  m11 : Double
} derive(Debug)

///|
pub(all) struct Histogram {
  minimum : Double
  maximum : Double
  bins : Array[Int]
} derive(Debug)

///|
pub(all) enum BorderPolicy {
  Constant(value~ : Double)
  Clamp
  Reflect
} derive(Debug, Eq)

///|
pub(all) enum PixelThreshold {
  Below(value~ : Double)
  Above(value~ : Double)
  Between(lower~ : Double, upper~ : Double)
} derive(Debug, Eq)

///|
pub(all) struct PolygonMetrics {
  area : Double
  perimeter : Double
  centroid : Point
  circularity : Double
  rectangularity : Double
} derive(Debug)

///|
pub(all) struct BatchStatistics {
  id : String
  total : Int
  accepted : Int
  rejected : Int
  mean : Double
  standard_deviation : Double
  minimum : Double
  maximum : Double
} derive(Debug)

///|
pub(all) struct CaliperConfig {
  start : Point
  finish : Point
  threshold : Double
  mode : EdgeMode
  expected_edges : Int
  unit : String
} derive(Debug)

///|
pub(all) struct ProfileSummary {
  samples : Array[ProfileSample]
  edges : Array[EdgePoint]
  strongest_edge : EdgePoint?
  mean_gradient : Double
  noise : Double
  signal_to_noise : Double
} derive(Debug)

///|
pub(all) struct PipelineResult {
  measurements : Array[Measurement]
  diagnostics : Array[PipelineDiagnostic]
  accepted : Bool
  confidence : Double
} derive(Debug)

///|
pub(all) struct QualitySummary {
  signal_to_noise : Double
  edge_count : Int
  confidence : Double
  stable : Bool
  notes : Array[String]
} derive(Debug)

///|
pub(all) struct Ellipse {
  center : Point
  major_radius : Double
  minor_radius : Double
  angle : Double
  rms_error : Double
} derive(Debug)

///|
pub(all) struct PyramidLevel {
  scale : Double
  image : GrayImage
} derive(Debug)

///|
pub(all) struct MatchResult {
  found : Bool
  location : Point
  score : Double
  candidates : Array[Point]
} derive(Debug)

///|
pub(all) struct DiagnosticEvent {
  code : String
  stage : String
  detail : String
  value : Double
} derive(Debug)

///|
pub(all) struct Roi {
  id : String
  bounds : Bounds
  mask : BinaryMask
} derive(Debug)

///|
pub(all) struct UncertaintyEstimate {
  standard : Double
  expanded : Double
  coverage : Double
  source : String
} derive(Debug)

///|
pub(all) struct EdgeMapSummary {
  edges : BinaryMask
  count : Int
  density : Double
  mean_strength : Double
} derive(Debug)

///|
pub(all) struct MeasurementTable {
  columns : Array[String]
  rows : Array[Array[String]]
} derive(Debug)

///|
pub fn distance(a : Point, b : Point) -> Double {
  let dx = a.x - b.x
  let dy = a.y - b.y
  (dx * dx + dy * dy).sqrt()
}

///|
pub fn Line::distance_to(line : Line, p : Point) -> Double {
  (line.a * p.x + line.b * p.y + line.c).abs()
}