use crate::patching::definition::FixtureDefinition;
use crate::patching::fixture::{LayoutPosition, UNITS_PER_METRE};
use emath::Rot2;
use emath::{Pos2, Vec2, pos2, vec2};
impl LayoutPosition {
pub fn scaled(&self, metres: [f32; 2]) -> Vec2 {
vec2(metres[0] * self.scale[0], metres[1] * self.scale[1]) * UNITS_PER_METRE
}
fn scene_offset(&self, offset_m: [f32; 3]) -> Vec2 {
Rot2::from_angle(self.angle) * self.scaled([offset_m[0], offset_m[1]])
}
}
impl FixtureDefinition {
pub fn pixel_scene_positions(&self, position: &LayoutPosition) -> Vec<Pos2> {
self.pixels
.iter()
.map(|pixel| position.pos + position.scene_offset(pixel.position_m))
.collect()
}
}
pub fn centroid(positions: &[Pos2]) -> Option<Pos2> {
if positions.is_empty() {
return None;
}
let sum = positions
.iter()
.fold(Vec2::ZERO, |acc, pos| acc + pos.to_vec2());
Some(pos2(
sum.x / positions.len() as f32,
sum.y / positions.len() as f32,
))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::rgb_bar as bar;
#[test]
fn a_one_metre_bar_spans_one_hundred_units() {
let definition = bar(2, 1.0);
let position = LayoutPosition::at(pos2(0.0, 0.0));
let positions = definition.pixel_scene_positions(&position);
assert_eq!(positions[0], pos2(-25.0, 0.0));
assert_eq!(positions[1], pos2(25.0, 0.0));
assert_eq!(positions[1].x - positions[0].x, 50.0);
}
#[test]
fn scale_stretches_per_axis() {
let definition = bar(2, 1.0);
let position = LayoutPosition::new(pos2(0.0, 0.0), 0.0, [2.0, 1.0]);
let positions = definition.pixel_scene_positions(&position);
assert_eq!(positions[0], pos2(-50.0, 0.0));
assert_eq!(positions[1], pos2(50.0, 0.0));
}
#[test]
fn angle_rotates_the_pixels_about_the_origin() {
let definition = bar(2, 1.0);
let position =
LayoutPosition::new(pos2(10.0, 10.0), std::f32::consts::FRAC_PI_2, [1.0, 1.0]);
let positions = definition.pixel_scene_positions(&position);
assert!((positions[0].x - 10.0).abs() < 1e-3);
assert!((positions[0].y - -15.0).abs() < 1e-3);
assert!((positions[1].y - 35.0).abs() < 1e-3);
}
#[test]
fn centroid_of_a_group_is_its_midpoint() {
let positions = [pos2(0.0, 0.0), pos2(10.0, 20.0)];
assert_eq!(centroid(&positions), Some(pos2(5.0, 10.0)));
assert_eq!(centroid(&[]), None);
}
}