///|
pub fn blank_fixture(width : Int, height : Int, value : Double) -> GrayImage {
  GrayImage::GrayImage(width~, height~, fill=value)
}

///|
pub fn rectangle_fixture(
  width : Int,
  height : Int,
  left : Int,
  top : Int,
  right : Int,
  bottom : Int,
  background : Double,
  foreground : Double,
) -> GrayImage {
  let image = blank_fixture(width, height, background)
  for y in top.max(0)..<(bottom + 1).min(height) {
    for x in left.max(0)..<(right + 1).min(width) {
      image.set(x, y, foreground)
    }
  }
  image
}

///|
pub fn bracket_fixture() -> GrayImage {
  let image = rectangle_fixture(160, 96, 32, 18, 126, 76, 0.05, 0.82)
  for y in 30..<64 {
    for x in 56..<104 {
      image.set(x, y, 0.05)
    }
  }
  for y in 18..<77 {
    image.set(32, y, 1.0)
    image.set(126, y, 1.0)
  }
  image
}

///|
pub fn slot_fixture(
  width : Int,
  height : Int,
  center : Point,
  slot_width : Double,
  slot_height : Double,
) -> GrayImage {
  let image = blank_fixture(width, height, 0.08)
  let left = (center.x - slot_width / 2.0).floor().to_int()
  let right = (center.x + slot_width / 2.0).ceil().to_int()
  let top = (center.y - slot_height / 2.0).floor().to_int()
  let bottom = (center.y + slot_height / 2.0).ceil().to_int()
  for y in top.max(0)..<(bottom + 1).min(height) {
    for x in left.max(0)..<(right + 1).min(width) {
      image.set(x, y, 0.9)
    }
  }
  image
}

///|
pub fn circle_fixture(
  width : Int,
  height : Int,
  center : Point,
  radius : Double,
  background : Double,
  foreground : Double,
) -> GrayImage {
  let image = blank_fixture(width, height, background)
  let radius_squared = radius * radius
  for y in 0.. GrayImage {
  let image = blank_fixture(width, height, 0.05)
  let inner_squared = inner_radius * inner_radius
  let outer_squared = outer_radius * outer_radius
  for y in 0..= inner_squared && squared <= outer_squared {
        image.set(x, y, 0.9)
      }
    }
  }
  image
}

///|
pub fn diagonal_edge_fixture(
  width : Int,
  height : Int,
  slope : Double,
  intercept : Double,
) -> GrayImage {
  let image = blank_fixture(width, height, 0.05)
  for y in 0..= boundary {
        image.set(x, y, 0.9)
      }
    }
  }
  image
}

///|
pub fn noisy_fixture(
  image : GrayImage,
  amplitude : Double,
  seed : Int,
) -> GrayImage {
  let result = image.copy()
  let mut state = seed.abs() + 1
  for i in 0.. GrayImage {
  let image = blank_fixture(width, height, 0.05)
  let inverse = AffineTransform::rotation(-angle)
  for y in 0.. GrayImage {
  let image = blank_fixture(width, height, 0.0)
  let safe_cell = cell.max(1)
  for y in 0.. GrayImage {
  let image = blank_fixture(width, height, 0.0)
  for y in 0.. GrayImage {
  let image = blank_fixture(192, 128, 0.04)
  let first = circle_fixture(
    192,
    128,
    Point::Point(x=48.0, y=64.0),
    24.0,
    0.04,
    0.92,
  )
  let second = rectangle_fixture(192, 128, 108, 36, 164, 92, 0.04, 0.78)
  for y in 0.. 0.5 || second.at(x, y) > 0.5 {
        image.set(x, y, first.at(x, y).max(second.at(x, y)))
      }
    }
  }
  image
}

///|
pub fn profile_fixture(
  length : Int,
  first_edge : Int,
  second_edge : Int,
  low : Double,
  high : Double,
) -> Array[ProfileSample] {
  let result : Array[ProfileSample] = []
  let safe_length = length.max(2)
  for i in 0.. Array[Point] {
  let result : Array[Point] = []
  for y in 0.. Measurement {
  let pixels = gauge_width(image, start, finish)
  let scale = calibration_from_reference(pixels, nominal)
  analyze_gap(
    "fixture-width",
    pixels,
    scale,
    Tolerance::Tolerance(nominal~, lower=nominal * 0.99, upper=nominal * 1.01),
  )
}

///|
pub fn fixture_checksum_suite() -> Array[Double] {
  [
    image_checksum(bracket_fixture()),
    image_checksum(
      circle_fixture(64, 64, Point::Point(x=32.0, y=32.0), 16.0, 0.0, 1.0),
    ),
    image_checksum(
      ring_fixture(64, 64, Point::Point(x=32.0, y=32.0), 12.0, 20.0),
    ),
    image_checksum(diagonal_edge_fixture(64, 64, 1.0, -10.0)),
  ]
}

///|
pub fn make_benchmark_image(width : Int, height : Int) -> GrayImage {
  noisy_fixture(multi_part_fixture(), 0.015, width + height)
}