mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-14 14:26:45 -04:00
AUNITS: degrees/minutes/seconds angles round at the displayed precision (#672)
Squash of PR #672 by @webdevtodayjason. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
6ca8cec97d
commit
bc6dc997ef
1 file changed
+48
-4
@@ -65,10 +65,24 @@ pub fn format_angle(a: f64, aunits: i64, auprec: i64) -> String {
|
||||
let deg = cadcraft_geom::norm_angle(a).to_degrees();
|
||||
match aunits {
|
||||
1 => {
|
||||
let d = deg.floor();
|
||||
let m = ((deg - d) * 60.0).floor();
|
||||
let s = (deg - d - m / 60.0) * 3600.0;
|
||||
format!("{}d{}'{:.*}\"", d as i64, m as i64, prec.saturating_sub(4), s)
|
||||
// Round at the displayed precision before splitting, carrying through a full turn.
|
||||
let scale = 10i64.pow(prec.saturating_sub(4) as u32);
|
||||
let seconds_per_unit = match prec {
|
||||
0 => 3600,
|
||||
1 | 2 => 60,
|
||||
_ => 1,
|
||||
};
|
||||
let units = (deg * (3600 / seconds_per_unit * scale) as f64).round() as i64;
|
||||
let total = units * seconds_per_unit % (360 * 3600 * scale);
|
||||
let (d, m) = (total / (3600 * scale), (total / (60 * scale)) % 60);
|
||||
match prec {
|
||||
0 => format!("{d}d"),
|
||||
1 | 2 => format!("{d}d{m}'"),
|
||||
_ => {
|
||||
let s = (total % (60 * scale)) as f64 / scale as f64;
|
||||
format!("{d}d{m}'{:.*}\"", prec.saturating_sub(4), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
2 => format!("{:.*}g", prec, deg / 0.9),
|
||||
3 => format!("{:.*}r", prec, cadcraft_geom::norm_angle(a)),
|
||||
@@ -280,6 +294,36 @@ mod tests {
|
||||
assert_eq!(format_distance(30.0, 3, 2), "2'-6.00\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dms_display_precision() {
|
||||
let angle = (12.0 + 34.0 / 60.0 + 56.78912 / 3600.0_f64).to_radians();
|
||||
let expected = ["13d", "12d35'", "12d35'", "12d34'57\"", "12d34'57\"", "12d34'56.8\"", "12d34'56.79\"", "12d34'56.789\"", "12d34'56.7891\""];
|
||||
for (prec, expected) in expected.into_iter().enumerate() {
|
||||
assert_eq!(format_angle(angle, 1, prec as i64), expected, "AUPREC {prec}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dms_rounding_carries() {
|
||||
let dms = |d: f64, m: f64, s: f64| (d + m / 60.0 + s / 3600.0).to_radians();
|
||||
let negative = (-0.0001_f64).to_radians();
|
||||
let cases = [
|
||||
(dms(29.0, 59.0, 59.6), 0, "30d"),
|
||||
(dms(29.0, 59.0, 59.6), 2, "30d0'"),
|
||||
(dms(29.0, 59.0, 59.6), 4, "30d0'0\""),
|
||||
(dms(29.0, 0.0, 59.99996), 2, "29d1'"),
|
||||
(dms(29.0, 0.0, 59.99996), 4, "29d1'0\""),
|
||||
(dms(29.0, 59.0, 59.99996), 5, "30d0'0.0\""),
|
||||
(dms(29.0, 59.0, 59.99996), 8, "30d0'0.0000\""),
|
||||
(negative, 0, "0d"),
|
||||
(negative, 4, "0d0'0\""),
|
||||
(negative, 5, "359d59'59.6\""),
|
||||
];
|
||||
for (angle, prec, expected) in cases {
|
||||
assert_eq!(format_angle(angle, 1, prec), expected, "AUPREC {prec}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_distances() {
|
||||
assert_eq!(parse_distance("12.5"), Some(12.5));
|
||||
|
||||
Reference in new issue
Block a user