mirror of
https://github.com/storytold/cadcraft.git
synced 2026-11-09 20:10:12 -06:00
A DIMENSION moved by an older AutoCAD keeps its *D block contents where they were and the move in DXF group 12, and is drawn translated by the insertion point. Group 12 was never read into Dimension, so the block rendered at its pre-move position and the extents reached there too. Read group 12 into a new Dimension::insertion_point, draw the block translated by it, move its bounds with it in the extents, test the block's text where it draws, and write group 12 back whenever the block written is the one read from the file. Regenerated geometry (edits drop the block link) sits at its definition points, so no offset is kept or written for it. Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
132 lines
5.5 KiB
Rust
132 lines
5.5 KiB
Rust
//! Dimension text formatting (issue #373): DIMRND rounds the measurement only, tolerances use
|
|
//! DIMTZIN, alternate units DIMALTRND/DIMALTU/DIMALTZ, and DIMPOST is not added to angles.
|
|
|
|
use cadcraft_doc::{DimKind, DimStyle, Dimension};
|
|
use cadcraft_geom::Vec3;
|
|
use cadcraft_render::dimension_geometry;
|
|
|
|
fn linear(len: f64) -> Dimension {
|
|
Dimension {
|
|
kind: DimKind::Linear { rotation: 0.0 },
|
|
defpt: Vec3::new(0.0, 5.0, 0.0),
|
|
text_mid: Vec3::ZERO,
|
|
p13: Vec3::ZERO,
|
|
p14: Vec3::new(len, 0.0, 0.0),
|
|
p15: Vec3::ZERO,
|
|
p16: Vec3::ZERO,
|
|
text: String::new(),
|
|
style: "Standard".into(),
|
|
measurement: 0.0,
|
|
text_rotation: 0.0,
|
|
user_text_pos: false,
|
|
block: None,
|
|
overrides: Default::default(),
|
|
assoc: Vec::new(),
|
|
marks: Default::default(),
|
|
insertion_point: Vec3::ZERO,
|
|
}
|
|
}
|
|
|
|
fn text(d: &Dimension, vars: serde_json::Value) -> String {
|
|
let mut st = DimStyle::default();
|
|
let rejected = st.apply_fields(vars.as_object().unwrap());
|
|
assert!(rejected.is_empty(), "unknown variables {rejected:?}");
|
|
dimension_geometry(d, &st, 1.0).value
|
|
}
|
|
|
|
#[test]
|
|
fn dimrnd_rounds_neither_tolerances_nor_alternate_units() {
|
|
let d = linear(10.3);
|
|
let tol = serde_json::json!({"DIMRND": 0.5, "DIMDEC": 2, "DIMTOL": 1, "DIMTP": 0.1, "DIMTM": 0.1, "DIMTDEC": 2});
|
|
assert_eq!(text(&d, tol), "10.50±0.10");
|
|
let dev = serde_json::json!({"DIMRND": 0.5, "DIMDEC": 2, "DIMTOL": 1, "DIMTP": 0.1, "DIMTM": 0.2, "DIMTDEC": 2});
|
|
assert_eq!(text(&d, dev), "10.50+0.10/-0.20");
|
|
// Tolerance zeros follow DIMTZIN, not DIMZIN.
|
|
let tzin = serde_json::json!({"DIMZIN": 8, "DIMDEC": 2, "DIMTOL": 1, "DIMTP": 0.1, "DIMTM": 0.1, "DIMTDEC": 2});
|
|
assert_eq!(text(&d, tzin.clone()), "10.3±0.10");
|
|
let mut tzin8 = tzin;
|
|
tzin8["DIMTZIN"] = 8.into();
|
|
assert_eq!(text(&d, tzin8), "10.3±0.1");
|
|
|
|
// 10.3 in = 261.62 mm: DIMRND 0.5 rounds the primary value only.
|
|
assert_eq!(text(&d, serde_json::json!({"DIMRND": 0.5, "DIMDEC": 1, "DIMALT": 1})), "10.5 [261.62]");
|
|
// DIMALTRND rounds the alternate value.
|
|
assert_eq!(text(&d, serde_json::json!({"DIMDEC": 1, "DIMALT": 1, "DIMALTRND": 0.5})), "10.3 [261.50]");
|
|
// DIMALTZ, not DIMZIN, suppresses alternate zeros.
|
|
assert_eq!(text(&linear(10.0), serde_json::json!({"DIMZIN": 8, "DIMALT": 1})), "10 [254.00]");
|
|
assert_eq!(text(&linear(10.0), serde_json::json!({"DIMALT": 1, "DIMALTZ": 8})), "10.0000 [254]");
|
|
// DIMALTU: alternate units in their own format (7 = fractional, not stacked).
|
|
assert_eq!(text(&linear(2.0), serde_json::json!({"DIMALT": 1, "DIMALTF": 0.25, "DIMALTU": 7, "DIMALTD": 2})), "2.0000 [1/2]");
|
|
}
|
|
|
|
#[test]
|
|
fn dimpost_is_not_added_to_angular_dimensions() {
|
|
let mut a = linear(0.0);
|
|
a.kind = DimKind::Angular3P;
|
|
a.p15 = Vec3::ZERO;
|
|
a.p13 = Vec3::new(10.0, 0.0, 0.0);
|
|
a.p14 = Vec3::new(0.0, 10.0, 0.0);
|
|
a.defpt = Vec3::new(3.0, 3.0, 0.0);
|
|
assert_eq!(text(&a, serde_json::json!({"DIMPOST": "<>mm"})), "90°");
|
|
// Linear dimensions keep it, and an angular text override still wraps the angle.
|
|
assert_eq!(text(&linear(10.0), serde_json::json!({"DIMPOST": "<>mm", "DIMDEC": 1})), "10.0mm");
|
|
a.text = "<> TYP".into();
|
|
assert_eq!(text(&a, serde_json::json!({"DIMPOST": "<>mm"})), "90° TYP");
|
|
}
|
|
|
|
fn angular(radians: f64) -> Dimension {
|
|
let mut d = linear(0.0);
|
|
d.kind = DimKind::Angular3P;
|
|
d.p13 = Vec3::new(10.0, 0.0, 0.0);
|
|
d.p14 = Vec3::new(10.0 * radians.cos(), 10.0 * radians.sin(), 0.0);
|
|
d.defpt = Vec3::new(5.0 * (radians / 2.0).cos(), 5.0 * (radians / 2.0).sin(), 0.0);
|
|
d
|
|
}
|
|
|
|
#[test]
|
|
fn angular_dimensions_use_the_style_decimal_separator() {
|
|
for (unit, radians, decimals, dot, comma) in
|
|
[(0, 39.4_f64.to_radians(), 1, "39.4°", "39,4°"), (2, std::f64::consts::FRAC_PI_4, 1, "50.0g", "50,0g"), (3, 1.25, 2, "1.25r", "1,25r")]
|
|
{
|
|
let three_point = angular(radians);
|
|
let mut two_line = three_point.clone();
|
|
two_line.kind = DimKind::Angular;
|
|
two_line.p16 = three_point.defpt;
|
|
two_line.p15 = three_point.p14;
|
|
two_line.p14 = three_point.p13;
|
|
two_line.p13 = Vec3::ZERO;
|
|
two_line.defpt = Vec3::ZERO;
|
|
for d in [three_point, two_line] {
|
|
let vars = serde_json::json!({"DIMAUNIT": unit, "DIMADEC": decimals});
|
|
assert_eq!(text(&d, vars.clone()), dot);
|
|
let mut vars = vars;
|
|
vars["DIMDSEP"] = serde_json::json!(",");
|
|
assert_eq!(text(&d, vars), comma);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn angular_decimal_separator_respects_overrides_and_literal_text() {
|
|
let mut d = angular(39.4_f64.to_radians());
|
|
d.text = "<> at 1.5".into();
|
|
d.overrides.insert("DIMDSEP".into(), serde_json::json!(","));
|
|
assert_eq!(text(&d, serde_json::json!({"DIMADEC": 1, "DIMDSEP": "."})), "39,4° at 1.5");
|
|
d.overrides.insert("DIMDSEP".into(), serde_json::json!("."));
|
|
assert_eq!(text(&d, serde_json::json!({"DIMADEC": 1, "DIMDSEP": ","})), "39.4° at 1.5");
|
|
}
|
|
|
|
#[test]
|
|
fn angular_zero_suppression_works_with_a_decimal_comma() {
|
|
let d = angular(0.5_f64.to_radians());
|
|
for (zin, expected) in [(0, "0,500°"), (1, ",500°"), (2, "0,5°"), (3, ",5°")] {
|
|
assert_eq!(text(&d, serde_json::json!({"DIMADEC": 3, "DIMAZIN": zin, "DIMDSEP": ","})), expected);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn angular_decimal_separator_keeps_dms_notation() {
|
|
let d = angular(45.5125_f64.to_radians());
|
|
assert_eq!(text(&d, serde_json::json!({"DIMAUNIT": 1, "DIMADEC": 3, "DIMDSEP": ","})), "45°30'45\"");
|
|
}
|