#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct GeoPoint {
pub position: [f32; 3],
pub normal: [f32; 3],
pub scale: f32,
pub rotation_deg: f32,
pub label: u32,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct GeoPointExport {
pub points: Vec<GeoPoint>,
}
#[allow(dead_code)]
pub fn new_geo_point_export() -> GeoPointExport {
GeoPointExport { points: Vec::new() }
}
#[allow(dead_code)]
pub fn add_geo_point(export: &mut GeoPointExport, point: GeoPoint) {
export.points.push(point);
}
#[allow(dead_code)]
pub fn geo_point_count(export: &GeoPointExport) -> usize {
export.points.len()
}
#[allow(dead_code)]
pub fn geo_point_bounds(export: &GeoPointExport) -> Option<([f32; 3], [f32; 3])> {
if export.points.is_empty() {
return None;
}
let mut mn = export.points[0].position;
let mut mx = export.points[0].position;
for p in &export.points {
for k in 0..3 {
if p.position[k] < mn[k] {
mn[k] = p.position[k];
}
if p.position[k] > mx[k] {
mx[k] = p.position[k];
}
}
}
Some((mn, mx))
}
#[allow(dead_code)]
pub fn avg_geo_point_scale(export: &GeoPointExport) -> f32 {
let n = export.points.len();
if n == 0 {
return 0.0;
}
export.points.iter().map(|p| p.scale).sum::<f32>() / n as f32
}
#[allow(dead_code)]
pub fn points_with_label_gp(export: &GeoPointExport, label: u32) -> usize {
export.points.iter().filter(|p| p.label == label).count()
}
#[allow(dead_code)]
pub fn validate_geo_points(export: &GeoPointExport) -> bool {
export.points.iter().all(|p| p.scale > 0.0)
}
#[allow(dead_code)]
pub fn geo_point_to_json(export: &GeoPointExport) -> String {
format!("{{\"point_count\":{}}}", export.points.len())
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_point(x: f32) -> GeoPoint {
GeoPoint {
position: [x, 0.0, 0.0],
normal: [0.0, 1.0, 0.0],
scale: 1.0,
rotation_deg: 0.0,
label: 0,
}
}
#[test]
fn test_add_and_count() {
let mut e = new_geo_point_export();
add_geo_point(&mut e, sample_point(0.0));
assert_eq!(geo_point_count(&e), 1);
}
#[test]
fn test_bounds_none_empty() {
let e = new_geo_point_export();
assert!(geo_point_bounds(&e).is_none());
}
#[test]
fn test_bounds_some() {
let mut e = new_geo_point_export();
add_geo_point(&mut e, sample_point(0.0));
add_geo_point(&mut e, sample_point(5.0));
let (mn, mx) = geo_point_bounds(&e).expect("should succeed");
assert!(mn[0].abs() < 1e-5);
assert!((mx[0] - 5.0).abs() < 1e-5);
}
#[test]
fn test_avg_scale() {
let mut e = new_geo_point_export();
add_geo_point(&mut e, sample_point(0.0));
add_geo_point(&mut e, sample_point(1.0));
assert!((avg_geo_point_scale(&e) - 1.0).abs() < 1e-5);
}
#[test]
fn test_points_with_label() {
let mut e = new_geo_point_export();
add_geo_point(&mut e, sample_point(0.0));
assert_eq!(points_with_label_gp(&e, 0), 1);
assert_eq!(points_with_label_gp(&e, 1), 0);
}
#[test]
fn test_validate_valid() {
let mut e = new_geo_point_export();
add_geo_point(&mut e, sample_point(0.0));
assert!(validate_geo_points(&e));
}
#[test]
fn test_validate_invalid_zero_scale() {
let mut e = new_geo_point_export();
e.points.push(GeoPoint {
position: [0.0; 3],
normal: [0.0, 1.0, 0.0],
scale: 0.0,
rotation_deg: 0.0,
label: 0,
});
assert!(!validate_geo_points(&e));
}
#[test]
fn test_geo_point_to_json() {
let e = new_geo_point_export();
let j = geo_point_to_json(&e);
assert!(j.contains("point_count"));
}
#[test]
fn test_avg_scale_empty() {
let e = new_geo_point_export();
assert!(avg_geo_point_scale(&e).abs() < 1e-6);
}
#[test]
fn test_validate_empty() {
let e = new_geo_point_export();
assert!(validate_geo_points(&e));
}
}