forked from 1b-agent/opencadstudio-upstream
fix(dimension): render DIMAUNIT 4 as a surveyor's bearing
DIMAUNIT 4 is Surveyor's units, but format_angular_value matched only 0-3 and let 4 fall through the catch-all to decimal degrees. An angular dimension in a drawing authored with surveyor units therefore read as plain degrees, while AUNITS 4 in the same drawing writes a bearing for the coordinate readout — the two disagreed on one angle. Format the bearing from the dimension's own DMS path so it carries DIMADEC, DIMAZIN and DIMDSEP, quantise before picking the quadrant so a value just short of a cardinal does not quote a quarter turn, and offer the option in the dimension-style dialog.
This commit is contained in:
1 parent
3ad0423393
commit
074e589ce8
2 files changed
+80
-1
No files matched your search
@@ -6567,6 +6567,8 @@ fn format_angular_value(measurement_deg: f64, style: Option<&DimStyle>) -> Strin
|
||||
swap_decimal_sep(&apply_angular_zero_suppression(&raw, azin), decimal_separator)
|
||||
)
|
||||
}
|
||||
// 4 = Surveyor's units
|
||||
4 => format_surveyor(measurement_deg, adec, azin, decimal_separator),
|
||||
// 0 or unknown = Decimal Degrees
|
||||
_ => {
|
||||
let raw = format!("{:.*}", adec, measurement_deg);
|
||||
@@ -6578,6 +6580,48 @@ fn format_angular_value(measurement_deg: f64, style: Option<&DimStyle>) -> Strin
|
||||
}
|
||||
}
|
||||
|
||||
/// Surveyor's units (DIMAUNIT 4): a bearing away from north or south toward
|
||||
/// east or west, so the quoted angle never exceeds a quarter turn. Due north,
|
||||
/// south, east and west have no bearing to quote and are written as the single
|
||||
/// letter, which is also what keeps a quarter turn from reading as a
|
||||
/// contradictory `N 90d0'0" E`. The bearing is DMS, so it carries DIMADEC,
|
||||
/// DIMAZIN and DIMDSEP the same way the DMS format does.
|
||||
fn format_surveyor(deg: f64, sec_dec: usize, azin: i16, decimal_separator: i16) -> String {
|
||||
// Quantise before choosing a cardinal or a quadrant, so a value a hair
|
||||
// under a cardinal direction does not print a quarter-turn bearing.
|
||||
let scale = 3600.0 * 10f64.powi(sec_dec.min(8) as i32);
|
||||
let turn = 360.0 * scale;
|
||||
let ticks = (deg.rem_euclid(360.0) * scale).round().rem_euclid(turn);
|
||||
let at = |d: f64| (ticks - d * scale).abs() < 0.5;
|
||||
if at(0.0) {
|
||||
return "E".into();
|
||||
}
|
||||
if at(90.0) {
|
||||
return "N".into();
|
||||
}
|
||||
if at(180.0) {
|
||||
return "W".into();
|
||||
}
|
||||
if at(270.0) {
|
||||
return "S".into();
|
||||
}
|
||||
let d = ticks / scale;
|
||||
// Measured from the nearer pole, toward the side the angle falls on.
|
||||
let (pole, bearing, side) = if d < 90.0 {
|
||||
("N", 90.0 - d, "E")
|
||||
} else if d < 180.0 {
|
||||
("N", d - 90.0, "W")
|
||||
} else if d < 270.0 {
|
||||
("S", 270.0 - d, "W")
|
||||
} else {
|
||||
("S", d - 270.0, "E")
|
||||
};
|
||||
format!(
|
||||
"{pole} {} {side}",
|
||||
format_dms(bearing, sec_dec, azin, decimal_separator)
|
||||
)
|
||||
}
|
||||
|
||||
fn format_dms(deg: f64, sec_dec: usize, azin: i16, decimal_separator: i16) -> String {
|
||||
let sign = if deg < 0.0 { "-" } else { "" };
|
||||
let scale = 10_u64.pow(sec_dec.min(8) as u32) as f64;
|
||||
@@ -7270,6 +7314,41 @@ mod dimtad_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod angular_unit_tests {
|
||||
use super::format_angular_value;
|
||||
use acadrust::tables::DimStyle;
|
||||
|
||||
fn style(dimaunit: i16, dimadec: i16) -> DimStyle {
|
||||
let mut s = DimStyle::standard();
|
||||
s.dimaunit = dimaunit;
|
||||
s.dimadec = dimadec;
|
||||
s
|
||||
}
|
||||
|
||||
// DIMAUNIT 4 is Surveyor's units. It used to fall through to the decimal
|
||||
// branch, so an angular dimension in a drawing authored with surveyor
|
||||
// units read as plain degrees while AUNITS=4 elsewhere wrote a bearing.
|
||||
#[test]
|
||||
fn surveyor_units_write_a_bearing() {
|
||||
assert_eq!(format_angular_value(45.0, Some(&style(4, 0))), "N 45\u{b0}0'0\" E");
|
||||
assert_eq!(format_angular_value(135.0, Some(&style(4, 0))), "N 45\u{b0}0'0\" W");
|
||||
assert_eq!(format_angular_value(200.0, Some(&style(4, 0))), "S 70\u{b0}0'0\" W");
|
||||
assert_eq!(format_angular_value(300.0, Some(&style(4, 0))), "S 30\u{b0}0'0\" E");
|
||||
// A hair under a cardinal must not quote a quarter-turn bearing.
|
||||
assert_eq!(format_angular_value(89.99999, Some(&style(4, 0))), "N");
|
||||
assert_eq!(format_angular_value(90.0, Some(&style(4, 0))), "N");
|
||||
assert_eq!(format_angular_value(0.0, Some(&style(4, 0))), "E");
|
||||
}
|
||||
|
||||
// The other unit formats are untouched.
|
||||
#[test]
|
||||
fn other_angular_units_unchanged() {
|
||||
assert_eq!(format_angular_value(45.5, Some(&style(1, 0))), "45\u{b0}30'0\"");
|
||||
assert_eq!(format_angular_value(90.0, Some(&style(2, 1))), "100.0g");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod arch_format_tests {
|
||||
use super::{format_architectural, format_fractional};
|
||||
|
||||
@@ -956,7 +956,7 @@ pub fn view_window<'a>(
|
||||
t!("Unit format"),
|
||||
DsField::Dimaunit,
|
||||
vals.dimaunit,
|
||||
&[("0", "Decimal degrees"), ("1", "Degrees, minutes, seconds"), ("2", "Gradians"), ("3", "Radians")],
|
||||
&[("0", "Decimal degrees"), ("1", "Degrees, minutes, seconds"), ("2", "Gradians"), ("3", "Radians"), ("4", "Surveyor's units")],
|
||||
),
|
||||
row![lbl(t!("Precision")), mk_field(DsField::Dimadec, vals.dimadec)]
|
||||
.spacing(8).align_y(iced::Center),
|
||||
|
||||
Reference in new issue
Block a user