use super::*;
use crate::RtcVerdict;
#[test]
fn test_bounds_creation() {
let bounds = ModelBounds::new();
assert!(!bounds.is_valid());
assert!(!bounds.has_large_coordinates(1.0));
}
#[test]
fn test_bounds_expand() {
let mut bounds = ModelBounds::new();
bounds.expand(100.0, 200.0, 50.0);
bounds.expand(150.0, 250.0, 75.0);
assert!(bounds.is_valid());
assert_eq!(bounds.min_x, 100.0);
assert_eq!(bounds.max_x, 150.0);
assert_eq!(bounds.min_y, 200.0);
assert_eq!(bounds.max_y, 250.0);
let centroid = bounds.centroid();
assert_eq!(centroid.0, 125.0);
assert_eq!(centroid.1, 225.0);
}
#[test]
fn test_large_coordinates_detection() {
let mut bounds = ModelBounds::new();
bounds.expand(2679012.0, 1247892.0, 432.0); bounds.expand(2679112.0, 1248092.0, 632.0);
assert!(bounds.has_large_coordinates(1.0));
assert_eq!(
bounds.rtc_offset(1.0),
Some(RtcVerdict::Large { anchor: (2679062.0, 1247992.0, 532.0) })
);
}
#[test]
fn test_small_coordinates_no_shift() {
let mut bounds = ModelBounds::new();
bounds.expand(0.0, 0.0, 0.0);
bounds.expand(100.0, 100.0, 10.0);
assert!(!bounds.has_large_coordinates(1.0));
let offset = bounds.rtc_offset(1.0).expect("bounds contain points").offset();
assert_eq!(offset.0, 0.0);
assert_eq!(offset.1, 0.0);
assert_eq!(offset.2, 0.0);
}
#[test]
fn test_extract_point_coordinates_3d() {
let text = "IFCCARTESIANPOINT((2679012.123,1247892.456,432.789))";
let coords = extract_point_coordinates(text).unwrap();
assert!((coords.0 - 2679012.123).abs() < 0.001);
assert!((coords.1 - 1247892.456).abs() < 0.001);
assert!((coords.2.unwrap() - 432.789).abs() < 0.001);
}
#[test]
fn test_extract_point_coordinates_2d() {
let text = "IFCCARTESIANPOINT((100.5,200.5))";
let coords = extract_point_coordinates(text).unwrap();
assert_eq!(coords.0, 100.5);
assert_eq!(coords.1, 200.5);
assert!(coords.2.is_none());
}
#[test]
fn test_scan_model_bounds() {
let ifc_content = r#"
ISO-10303-21;
HEADER;
FILE_DESCRIPTION((''),'2;1');
ENDSEC;
DATA;
#1=IFCCARTESIANPOINT((2679012.0,1247892.0,432.0));
#2=IFCCARTESIANPOINT((2679112.0,1247992.0,442.0));
#3=IFCWALL('guid',$,$,$,$,$,$,$);
ENDSEC;
END-ISO-10303-21;
"#;
let bounds = scan_model_bounds(ifc_content);
assert!(bounds.is_valid());
assert!(bounds.has_large_coordinates(1.0));
assert_eq!(bounds.sample_count, 2);
let centroid = bounds.centroid();
assert!((centroid.0 - 2679062.0).abs() < 0.001);
assert!((centroid.1 - 1247942.0).abs() < 0.001);
}
#[test]
fn test_scan_model_bounds_small_model() {
let ifc_content = r#"
ISO-10303-21;
DATA;
#1=IFCCARTESIANPOINT((0.0,0.0,0.0));
#2=IFCCARTESIANPOINT((10.0,10.0,5.0));
ENDSEC;
END-ISO-10303-21;
"#;
let bounds = scan_model_bounds(ifc_content);
assert!(bounds.is_valid());
assert!(!bounds.has_large_coordinates(1.0));
let offset = bounds.rtc_offset(1.0).expect("bounds contain points").offset();
assert_eq!(offset.0, 0.0); }
#[test]
fn test_precision_preserved_with_rtc() {
let x1 = 2679012.123456_f64; let x2 = 2679012.223456_f64; let expected_diff = 0.1;
let mut bounds = ModelBounds::new();
bounds.expand(x1, 1247892.0, 432.0);
bounds.expand(x2, 1247892.5, 432.5);
assert!(bounds.has_large_coordinates(1.0), "premise: large coords");
let diff_direct = ((x2 as f32) - (x1 as f32)) as f64;
let error_direct = (diff_direct - expected_diff).abs();
assert!(error_direct > 0.01, "premise: cast must lose 0.1 m");
let (offset_x, _, _) = bounds.rtc_offset(1.0).expect("bounds contain points").offset();
let diff_rtc = (((x2 - offset_x) as f32) - ((x1 - offset_x) as f32)) as f64;
let error_rtc = (diff_rtc - expected_diff).abs();
assert!(
error_rtc < 1.0e-6,
"RTC-shifted f32 must keep the 0.1 m separation (diff={diff_rtc}, err={error_rtc})"
);
assert!(error_rtc < error_direct * 0.1, "RTC must improve precision");
}
#[test]
fn large_coordinate_gate_scales_file_units_to_metres_before_deciding() {
let mut bounds = ModelBounds::new();
bounds.expand(500.0, 500.0, 0.0);
bounds.expand(500.1, 500.1, 0.01);
assert!(!bounds.has_large_coordinates(1.0));
assert_eq!(bounds.rtc_offset(1.0), Some(RtcVerdict::Small));
assert!(bounds.has_large_coordinates(1000.0));
let (x, y, z) = bounds.rtc_offset(1000.0).expect("bounds contain points").offset();
assert!((x - 500_050.0).abs() < 1e-6, "x offset in metres, got {x}");
assert!((y - 500_050.0).abs() < 1e-6, "y offset in metres, got {y}");
assert!((z - 5.0).abs() < 1e-6, "z offset in metres, got {z}");
}
#[test]
fn millimetre_model_inside_ten_metres_is_not_large() {
let mut bounds = ModelBounds::new();
bounds.expand(0.0, 0.0, 0.0);
bounds.expand(25_000.0, 25_000.0, 3_000.0);
assert!(bounds.has_large_coordinates(1.0), "premise: raw values read as 25 km");
assert!(!bounds.has_large_coordinates(0.001));
assert_eq!(bounds.rtc_offset(0.001), Some(RtcVerdict::Small));
}
#[test]
fn bounds_scans_match_keyword_case_insensitively() {
let upper = "\
ISO-10303-21;
DATA;
#1=IFCCARTESIANPOINT((2679012.0,1247892.0,432.0));
#2=IFCAXIS2PLACEMENT3D(#1,$,$);
#3=IFCCARTESIANPOINT((1.0,2.0,3.0));
ENDSEC;
END-ISO-10303-21;
";
let mixed = upper
.replace("IFCCARTESIANPOINT", "IfcCartesianPoint")
.replace("IFCAXIS2PLACEMENT3D", "ifcaxis2placement3d");
assert_ne!(upper, mixed, "premise: the spelling actually changed");
let (u, m) = (scan_model_bounds(upper), scan_model_bounds(&mixed));
assert_eq!(u.sample_count, 2, "control: uppercase scan sees both points");
assert_eq!(m.sample_count, u.sample_count);
assert_eq!(m.centroid(), u.centroid());
let (u, m) = (scan_placement_bounds(upper), scan_placement_bounds(&mixed));
assert_eq!(u.sample_count, 1, "control: uppercase placement scan sees #1 only");
assert_eq!(m.sample_count, u.sample_count);
assert_eq!(m.centroid(), u.centroid());
}
#[test]
fn a_large_corner_with_an_in_threshold_centre_is_still_large() {
let mut bounds = ModelBounds::new();
bounds.expand(200.0, 0.0, 0.0);
bounds.expand(1_500.0, 0.0, 0.0);
assert_eq!(
bounds.rtc_offset(1.0),
Some(RtcVerdict::Large { anchor: (850.0, 0.0, 0.0) })
);
}
#[test]
fn issue_4934_survey_grid_band_gets_an_rtc_anchor() {
let mut bounds = ModelBounds::new();
bounds.expand(6_200.0, -3.36, -7_788.45);
bounds.expand(6_330.0, 27.68, -7_731.68);
assert!(bounds.has_large_coordinates(1.0));
let (x, y, z) = bounds.rtc_offset(1.0).expect("bounds contain points").offset();
assert!((x - 6_265.0).abs() < 1e-9, "x anchor, got {x}");
assert!((y - 12.16).abs() < 1e-9, "y anchor, got {y}");
assert!((z - -7_760.065).abs() < 1e-9, "z anchor, got {z}");
}
#[test]
fn issue_4934_mm_scale_model_still_small() {
let mut bounds = ModelBounds::new();
bounds.expand(0.0, 0.0, 0.0);
bounds.expand(25.0, 25.0, 10.0);
assert!(!bounds.has_large_coordinates(1.0));
assert_eq!(bounds.rtc_offset(1.0), Some(RtcVerdict::Small));
}