redid it library style
This commit is contained in:
101
src/normalize.rs
Normal file
101
src/normalize.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
/// Normalizes a gesture by removing translation and scale
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `points` - Slice of Point structs representing the gesture
|
||||
///
|
||||
/// # Returns
|
||||
/// Vector of normalized points centered at origin with unit scale
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use redoal::point::Point;
|
||||
/// use redoal::normalize;
|
||||
///
|
||||
/// let points = vec![
|
||||
/// Point::new(1.0, 2.0),
|
||||
/// Point::new(3.0, 4.0),
|
||||
/// Point::new(5.0, 6.0),
|
||||
/// ];
|
||||
/// let normalized = normalize(&points);
|
||||
/// ```
|
||||
use crate::Point;
|
||||
|
||||
pub fn normalize(points: &[Point]) -> Vec<Point> {
|
||||
let n = points.len() as f64;
|
||||
|
||||
// Calculate centroid
|
||||
let cx = points.iter().map(|p| p.x).sum::<f64>() / n;
|
||||
let cy = points.iter().map(|p| p.y).sum::<f64>() / n;
|
||||
|
||||
// Center points at origin
|
||||
let mut out: Vec<Point> = points.iter().map(|p| {
|
||||
Point {
|
||||
x: p.x - cx,
|
||||
y: p.y - cy,
|
||||
}
|
||||
}).collect();
|
||||
|
||||
// Find maximum radius
|
||||
let mut max_r = 0.0;
|
||||
for p in &out {
|
||||
let r = (p.x * p.x + p.y * p.y).sqrt();
|
||||
if r > max_r {
|
||||
max_r = r;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale to unit size
|
||||
if max_r > 0.0 {
|
||||
for p in &mut out {
|
||||
p.x /= max_r;
|
||||
p.y /= max_r;
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::point::Point;
|
||||
|
||||
#[test]
|
||||
fn test_normalize_centers_points() {
|
||||
let points = vec![
|
||||
Point::new(1.0, 1.0),
|
||||
Point::new(2.0, 2.0),
|
||||
Point::new(3.0, 3.0),
|
||||
];
|
||||
|
||||
let normalized = normalize(&points);
|
||||
let sum_x: f64 = normalized.iter().map(|p| p.x).sum();
|
||||
let sum_y: f64 = normalized.iter().map(|p| p.y).sum();
|
||||
|
||||
// Centroid should be at origin
|
||||
assert!( (sum_x.abs() < 1e-10) );
|
||||
assert!( (sum_y.abs() < 1e-10) );
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize_scales_points() {
|
||||
let points = vec![
|
||||
Point::new(0.0, 0.0),
|
||||
Point::new(10.0, 0.0),
|
||||
Point::new(5.0, 5.0),
|
||||
];
|
||||
|
||||
let normalized = normalize(&points);
|
||||
let max_r = normalized.iter().map(|p| (p.x * p.x + p.y * p.y).sqrt()).fold(0.0, |a: f64, b| a.max(b));
|
||||
|
||||
// All points should be within unit circle
|
||||
assert!( (max_r - 1.0).abs() < 1e-10 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize_empty() {
|
||||
let points: Vec<Point> = vec![];
|
||||
let normalized = normalize(&points);
|
||||
assert_eq!(normalized.len(), 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user