forked from 1b-agent/opencadstudio-upstream
fix(dimension): DIMLIM replaces the nominal with a limits stack
Dimensions with DIMLIM on were regenerated as the nominal value plus a separate stacked pair, and the pair was built from the unscaled measurement. AutoCAD prints only the upper limit over the lower one, with the offsets applied to the DIMLFAC-scaled, DIMRND-rounded value, and keeps both halves at the same number of decimals under DIMTZIN. Drawings with a limits-only style looked right on load, from their saved picture blocks, and gained an extra number as soon as an associative refresh dropped the picture. Fit and fill estimates now count visible cells, so a stack is as wide as its wider half at DIMTFAC, and the text-to-line offset uses the stacked height.
This commit is contained in:
1 parent
144abc96fe
commit
86f63f5fd1
1 file changed
+312
-59
+312
-59
@@ -4359,8 +4359,9 @@ fn text_fill_rect(
|
||||
let dimgap = style.map(|s| s.dimgap.abs()).unwrap_or(0.0) * dim_scale;
|
||||
// ~0.6 × text_height per character; matches average glyph aspect for
|
||||
// the bundled stick fonts. Inflate by 1 DIMGAP on each side.
|
||||
let approx_w = value.chars().count() as f64 * text_height * 0.6 + dimgap * 2.0;
|
||||
let approx_h = text_height + dimgap * 2.0;
|
||||
let stack_scale = style.map(dimtfac_or_one).unwrap_or(1.0);
|
||||
let approx_w = text_cells(&value, stack_scale) * text_height * 0.6 + dimgap * 2.0;
|
||||
let approx_h = dimension_text_block_height(style, text_height) + dimgap * 2.0;
|
||||
let rot = if dim.base().text_rotation.abs() > 1e-9 {
|
||||
dim.base().text_rotation
|
||||
} else {
|
||||
@@ -4402,7 +4403,8 @@ fn arc_length_symbol_points(
|
||||
let position = dimension_text_pos_f64(dim, style, text_height, dim_scale);
|
||||
let rotation = dimension_text_rotation(dim, style);
|
||||
let (sin_rotation, cos_rotation) = rotation.sin_cos();
|
||||
let text_width = value.chars().count() as f64 * text_height * 0.6;
|
||||
let stack_scale = style.map(dimtfac_or_one).unwrap_or(1.0);
|
||||
let text_width = text_cells(&value, stack_scale) * text_height * 0.6;
|
||||
let symbol_width = text_height * 0.62;
|
||||
let symbol_height = text_height * 0.20;
|
||||
let (center_x, center_y) = if symbol_position == 1 {
|
||||
@@ -4467,8 +4469,8 @@ fn dimension_text_layout(
|
||||
let gap = style
|
||||
.map(|style| (style.dimgap.abs() * dim_scale) as f32)
|
||||
.unwrap_or(0.09);
|
||||
let width = dimension_text_value(dimension, style)
|
||||
.map(|text| text.chars().count() as f32 * text_height as f32 * 0.6 + gap * 2.0)
|
||||
let width = dimension_text_cells(dimension, style)
|
||||
.map(|cells| cells as f32 * text_height as f32 * 0.6 + gap * 2.0)
|
||||
.unwrap_or(0.0);
|
||||
let position = vec3_local(dimension_text_pos_f64(
|
||||
dimension,
|
||||
@@ -5830,13 +5832,18 @@ fn dimension_text_entity(
|
||||
document: &CadDocument,
|
||||
dim_scale: f64,
|
||||
) -> Option<EntityType> {
|
||||
// Tolerances are emitted by `dimension_tolerance_entity` at their own
|
||||
// Deviations are emitted by `dimension_tolerance_entity` at their own
|
||||
// height and alignment; keep the primary entity free of duplicate text.
|
||||
let (value, _) = dimension_text_parts(dim, style)?;
|
||||
// Use f64 position directly to avoid f32 round-trip precision loss at large
|
||||
// coordinates (e.g. Turkish UTM ~4,000,000 m). tessellate() will apply
|
||||
// world_offset when rendering this synthetic entity.
|
||||
let pos_f64 = dimension_text_pos_f64(dim, style, text_height, dim_scale);
|
||||
// A limits stack draws each half at DIMTFAC × DIMTXT, like AutoCAD.
|
||||
let text_height = match style {
|
||||
Some(s) if s.dimlim => text_height * dimtfac_or_one(s),
|
||||
_ => text_height,
|
||||
};
|
||||
let base = dim.base();
|
||||
|
||||
let rotation = dimension_text_rotation(dim, style);
|
||||
@@ -5987,8 +5994,8 @@ fn dimension_text_is_outside(dim: &Dimension, style: Option<&DimStyle>) -> bool
|
||||
let scale = if style.dimscale > 1e-9 { style.dimscale } else { 1.0 };
|
||||
let height = style.dimtxt * scale;
|
||||
let gap = style.dimgap.abs() * scale;
|
||||
let text_width = dimension_text_value(dim, Some(style))
|
||||
.map(|value| value.chars().count() as f64 * height * 0.6 + gap * 2.0)
|
||||
let text_width = dimension_text_cells(dim, Some(style))
|
||||
.map(|cells| cells * height * 0.6 + gap * 2.0)
|
||||
.unwrap_or(0.0);
|
||||
let arrow = style.dimasz * scale;
|
||||
let span = radius as f64 * (end - start).abs() as f64;
|
||||
@@ -6019,8 +6026,8 @@ fn dimension_text_is_outside(dim: &Dimension, style: Option<&DimStyle>) -> bool
|
||||
};
|
||||
let height = style.dimtxt * scale;
|
||||
let gap = style.dimgap.abs() * scale;
|
||||
let text_width = dimension_text_value(dim, Some(style))
|
||||
.map(|value| value.chars().count() as f64 * height * 0.6 + gap * 2.0)
|
||||
let text_width = dimension_text_cells(dim, Some(style))
|
||||
.map(|cells| cells * height * 0.6 + gap * 2.0)
|
||||
.unwrap_or(0.0);
|
||||
let arrow = style.dimasz * scale;
|
||||
let insufficient = text_width + arrow > available;
|
||||
@@ -6047,8 +6054,8 @@ fn dimension_text_is_outside(dim: &Dimension, style: Option<&DimStyle>) -> bool
|
||||
let scale = if style.dimscale > 1e-9 { style.dimscale } else { 1.0 };
|
||||
let height = style.dimtxt * scale;
|
||||
let gap = style.dimgap.abs() * scale;
|
||||
let text_width = dimension_text_value(dim, Some(style))
|
||||
.map(|value| value.chars().count() as f64 * height * 0.6 + gap * 2.0)
|
||||
let text_width = dimension_text_cells(dim, Some(style))
|
||||
.map(|cells| cells * height * 0.6 + gap * 2.0)
|
||||
.unwrap_or(0.0);
|
||||
let arrow = style.dimasz * scale;
|
||||
let insufficient = text_width + arrow > available;
|
||||
@@ -6092,8 +6099,8 @@ fn dimension_text_is_outside(dim: &Dimension, style: Option<&DimStyle>) -> bool
|
||||
let scale = if style.dimscale > 1e-9 { style.dimscale } else { 1.0 };
|
||||
let height = style.dimtxt * scale;
|
||||
let gap = style.dimgap.abs() * scale;
|
||||
let text_width = dimension_text_value(dim, Some(style))
|
||||
.map(|value| value.chars().count() as f64 * height * 0.6 + gap * 2.0)
|
||||
let text_width = dimension_text_cells(dim, Some(style))
|
||||
.map(|cells| cells * height * 0.6 + gap * 2.0)
|
||||
.unwrap_or(0.0);
|
||||
let arrow = style.dimasz * scale;
|
||||
let span = hi - lo;
|
||||
@@ -6167,20 +6174,22 @@ fn dimension_text_parts(
|
||||
let is_angular = matches!(dim, Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_));
|
||||
|
||||
// Auto-generated body used when the user did not override it. Built first
|
||||
// so user_text "<>" substitution can re-use it.
|
||||
let primary_raw = if is_angular {
|
||||
format_angular_value(dim.measurement(), style)
|
||||
} else {
|
||||
let v = format_linear_value(dim.measurement(), style);
|
||||
match dim {
|
||||
Dimension::Radius(_) | Dimension::LargeRadial(_) => format!("R{}", v),
|
||||
Dimension::Diameter(_) => format!("Ø{}", v),
|
||||
_ => v,
|
||||
}
|
||||
// so user_text "<>" substitution can re-use it. With DIMLIM the limits
|
||||
// stack is the value itself: AutoCAD prints the upper limit over the
|
||||
// lower one and no nominal, so the tolerance slot stays empty.
|
||||
let value = match limits_text(dim, style, is_angular) {
|
||||
Some(limits) => limits,
|
||||
None if is_angular => format_angular_value(dim.measurement(), style),
|
||||
None => format_linear_value(dim.measurement(), style),
|
||||
};
|
||||
let primary_raw = match dim {
|
||||
Dimension::Radius(_) | Dimension::LargeRadial(_) => format!("R{}", value),
|
||||
Dimension::Diameter(_) => format!("Ø{}", value),
|
||||
_ => value,
|
||||
};
|
||||
|
||||
// Build tolerance / limits suffix separately so the caller can render
|
||||
// it as its own Text entity at DIMTFAC × DIMTXT height.
|
||||
// Build the deviation suffix separately so the caller can render it as
|
||||
// its own Text entity at DIMTFAC × DIMTXT height.
|
||||
let tolerance_suffix = build_tolerance_suffix(dim, style, is_angular);
|
||||
let primary = apply_dimpost(&primary_raw, style);
|
||||
|
||||
@@ -6208,24 +6217,75 @@ fn dimension_text_parts(
|
||||
Some((primary, tolerance_suffix))
|
||||
}
|
||||
|
||||
/// DIMLIM: the upper limit stacked over the lower one, replacing the nominal.
|
||||
/// The offsets apply to the displayed number, so DIMLFAC and DIMRND come first.
|
||||
fn limits_text(dim: &Dimension, style: Option<&DimStyle>, is_angular: bool) -> Option<String> {
|
||||
let s = style.filter(|s| s.dimlim)?;
|
||||
let measurement = dim.measurement();
|
||||
if is_angular {
|
||||
return Some(format!(
|
||||
"\\S{}^{};",
|
||||
format_angular_value(measurement + s.dimtp, style),
|
||||
format_angular_value(measurement - s.dimtm, style)
|
||||
));
|
||||
}
|
||||
let mut nominal = measurement * effective_dimlfac(style);
|
||||
if s.dimrnd > 1e-12 {
|
||||
nominal = (nominal / s.dimrnd).round() * s.dimrnd;
|
||||
}
|
||||
let (high, low) = limit_pair(nominal + s.dimtp, nominal - s.dimtm, s);
|
||||
Some(format!("\\S{}^{};", high, low))
|
||||
}
|
||||
|
||||
/// The two limits keep the same number of decimals so the stack lines up:
|
||||
/// DIMTZIN drops trailing zeros only as far as both values allow. AutoCAD
|
||||
/// writes `13.950` over `13.926` with DIMTZIN 8, not `13.95` over `13.926`.
|
||||
fn limit_pair(high: f64, low: f64, s: &DimStyle) -> (String, String) {
|
||||
let dimtdec = s.dimtdec.max(0) as usize;
|
||||
let mut high = format!("{:.*}", dimtdec, high);
|
||||
let mut low = format!("{:.*}", dimtdec, low);
|
||||
if s.dimtzin & 8 != 0 {
|
||||
let droppable = |value: &str| match value.find('.') {
|
||||
Some(_) => value.len() - value.trim_end_matches('0').len(),
|
||||
None => 0,
|
||||
};
|
||||
let drop = droppable(&high).min(droppable(&low));
|
||||
for value in [&mut high, &mut low] {
|
||||
value.truncate(value.len() - drop);
|
||||
if value.ends_with('.') {
|
||||
value.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
let finish = |value: &str| {
|
||||
let value = if s.dimtzin & 4 != 0 {
|
||||
strip_leading_zero(value)
|
||||
} else {
|
||||
value.to_string()
|
||||
};
|
||||
swap_decimal_sep(&value, s.dimdsep)
|
||||
};
|
||||
(finish(&high), finish(&low))
|
||||
}
|
||||
|
||||
/// Formats a tolerance number with DIMTDEC, DIMTZIN and DIMDSEP.
|
||||
fn tolerance_formatter(s: &DimStyle) -> impl Fn(f64) -> String + '_ {
|
||||
let dimtdec = s.dimtdec.max(0) as usize;
|
||||
move |v: f64| {
|
||||
let raw = format!("{:.*}", dimtdec, v);
|
||||
swap_decimal_sep(&apply_linear_zero_suppression(&raw, s.dimtzin), s.dimdsep)
|
||||
}
|
||||
}
|
||||
|
||||
/// DIMTOL deviation suffix drawn beside the nominal. DIMLIM wins over DIMTOL,
|
||||
/// as in AutoCAD, and is handled by `limits_text`.
|
||||
fn build_tolerance_suffix(
|
||||
dim: &Dimension,
|
||||
style: Option<&DimStyle>,
|
||||
is_angular: bool,
|
||||
) -> Option<String> {
|
||||
let s = style?;
|
||||
let measurement = dim.measurement();
|
||||
let dimtdec = s.dimtdec.max(0) as usize;
|
||||
let dimtzin = s.dimtzin;
|
||||
let fmt = |v: f64| -> String {
|
||||
let raw = format!("{:.*}", dimtdec, v);
|
||||
swap_decimal_sep(&apply_linear_zero_suppression(&raw, dimtzin), s.dimdsep)
|
||||
};
|
||||
if s.dimlim {
|
||||
let high = measurement + s.dimtp;
|
||||
let low = measurement - s.dimtm;
|
||||
return Some(format!("\\S{}^{};", fmt(high), fmt(low)));
|
||||
}
|
||||
let s = style.filter(|s| !s.dimlim)?;
|
||||
let fmt = tolerance_formatter(s);
|
||||
if s.dimtol {
|
||||
let unit = if is_angular { "°" } else { "" };
|
||||
if (s.dimtp - s.dimtm).abs() < 1e-12 && s.dimtp.abs() > 1e-12 {
|
||||
@@ -6358,12 +6418,7 @@ fn dimension_tolerance_entity(
|
||||
let s = style?;
|
||||
let is_angular = matches!(dim, Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_));
|
||||
let tol = build_tolerance_suffix(dim, style, is_angular)?;
|
||||
let dimtfac = if s.dimtfac.abs() < 1e-12 {
|
||||
1.0
|
||||
} else {
|
||||
s.dimtfac
|
||||
};
|
||||
let tol_height = primary_height * dimtfac;
|
||||
let tol_height = primary_height * dimtfac_or_one(s);
|
||||
|
||||
// Pull the geometry we need from the synthetic primary entity (Text or
|
||||
// MText — `dimension_text_entity` routes to MText when the dim value
|
||||
@@ -6443,14 +6498,73 @@ fn apply_dimpost(value: &str, style: Option<&DimStyle>) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// `resolved_dimension_style` has already applied the DXF sign convention,
|
||||
/// so a negative value here means the caller passed an unresolved style;
|
||||
/// fall back to 1.0 rather than reporting a negative length.
|
||||
fn effective_dimlfac(style: Option<&DimStyle>) -> f64 {
|
||||
let lfac = style.map(|s| s.dimlfac).unwrap_or(1.0);
|
||||
if lfac.abs() < 1e-12 || lfac < 0.0 {
|
||||
1.0
|
||||
} else {
|
||||
lfac
|
||||
}
|
||||
}
|
||||
|
||||
/// DIMTFAC with the unset value 0 read as 1.
|
||||
fn dimtfac_or_one(s: &DimStyle) -> f64 {
|
||||
if s.dimtfac.abs() < 1e-12 {
|
||||
1.0
|
||||
} else {
|
||||
s.dimtfac
|
||||
}
|
||||
}
|
||||
|
||||
/// Vertical extent of the rendered value: one line, or a DIMLIM stack whose
|
||||
/// halves each sit at DIMTFAC × DIMTXT.
|
||||
fn dimension_text_block_height(style: Option<&DimStyle>, text_height: f64) -> f64 {
|
||||
match style {
|
||||
Some(s) if s.dimlim => {
|
||||
text_height
|
||||
* dimtfac_or_one(s)
|
||||
* 2.0
|
||||
* f64::from(crate::entities::text_support::STACK_HALF_SCALE)
|
||||
}
|
||||
_ => text_height,
|
||||
}
|
||||
}
|
||||
|
||||
/// Approximate width of the rendered value in character cells of the nominal
|
||||
/// text height. A `\S` stack is as wide as its wider half, drawn at DIMTFAC.
|
||||
pub(crate) fn dimension_text_cells(dim: &Dimension, style: Option<&DimStyle>) -> Option<f64> {
|
||||
let value = dimension_text_value(dim, style)?;
|
||||
Some(text_cells(&value, style.map(dimtfac_or_one).unwrap_or(1.0)))
|
||||
}
|
||||
|
||||
fn text_cells(value: &str, stack_scale: f64) -> f64 {
|
||||
let mut cells = 0.0;
|
||||
let mut rest = value;
|
||||
while let Some(start) = rest.find("\\S") {
|
||||
cells += rest[..start].chars().count() as f64;
|
||||
let body = &rest[start + 2..];
|
||||
let end = body.find(';').unwrap_or(body.len());
|
||||
let widest = body[..end]
|
||||
.split(['^', '/', '#'])
|
||||
.map(|half| half.chars().count())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
cells += widest as f64 * stack_scale;
|
||||
rest = &body[(end + 1).min(body.len())..];
|
||||
}
|
||||
cells + rest.chars().count() as f64
|
||||
}
|
||||
|
||||
/// Format a linear measurement honouring DIMLFAC, DIMRND, DIMDEC, DIMZIN, DIMDSEP, DIMLUNIT.
|
||||
fn format_linear_value(measurement: f64, style: Option<&DimStyle>) -> String {
|
||||
let (dec, zin, lfac, rnd, dsep, lunit, frac, sub_factor, sub_suffix) = style
|
||||
let (dec, zin, rnd, dsep, lunit, frac, sub_factor, sub_suffix) = style
|
||||
.map(|s| {
|
||||
(
|
||||
s.dimdec,
|
||||
s.dimzin,
|
||||
s.dimlfac,
|
||||
s.dimrnd,
|
||||
s.dimdsep,
|
||||
s.dimlunit,
|
||||
@@ -6459,16 +6573,9 @@ fn format_linear_value(measurement: f64, style: Option<&DimStyle>) -> String {
|
||||
s.dimmzs.as_str(),
|
||||
)
|
||||
})
|
||||
.unwrap_or((4, 8, 1.0, 0.0, 46, 2, 0, 1.0, ""));
|
||||
.unwrap_or((4, 8, 0.0, 46, 2, 0, 1.0, ""));
|
||||
|
||||
// `resolved_dimension_style` has already applied the DXF sign convention,
|
||||
// so a negative value here means the caller passed an unresolved style;
|
||||
// fall back to 1.0 rather than reporting a negative length.
|
||||
let lfac = if lfac.abs() < 1e-12 || lfac < 0.0 {
|
||||
1.0
|
||||
} else {
|
||||
lfac
|
||||
};
|
||||
let lfac = effective_dimlfac(style);
|
||||
let scaled = measurement * lfac;
|
||||
let use_sub_units = zin & 4 != 0 && scaled.abs() < 1.0 && sub_factor.abs() > 1e-12;
|
||||
// For values below one unit, DIMMZF replaces DIMLFAC; applying it after
|
||||
@@ -6955,11 +7062,11 @@ fn dimension_text_pos_f64(
|
||||
let perp_off = if dimtad == 0 {
|
||||
dimtvp * text_height
|
||||
} else {
|
||||
text_height * 0.5 + dimgap
|
||||
dimension_text_block_height(style, text_height) * 0.5 + dimgap
|
||||
};
|
||||
// Rough text width + arrow allowance, used to decide text-outside fit.
|
||||
let text_w = dimension_text_value(dim, style)
|
||||
.map(|t| t.chars().count() as f64 * text_height * 0.6 + 2.0 * dimgap)
|
||||
let text_w = dimension_text_cells(dim, style)
|
||||
.map(|cells| cells * text_height * 0.6 + 2.0 * dimgap)
|
||||
.unwrap_or(0.0);
|
||||
let arrow = if matches!(dim, Dimension::LargeRadial(_)) {
|
||||
style
|
||||
@@ -7892,3 +7999,149 @@ mod linear_transform_tests {
|
||||
assert_draws_turned_with_its_plane(Dimension::Aligned(d));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod limits_format_tests {
|
||||
use super::*;
|
||||
use acadrust::entities::DimensionLinear;
|
||||
|
||||
/// A horizontal linear dimension measuring 10 units along X.
|
||||
fn horizontal() -> Dimension {
|
||||
let mut d =
|
||||
DimensionLinear::horizontal(Vector3::new(0.0, 0.0, 0.0), Vector3::new(10.0, 0.0, 0.0));
|
||||
d.definition_point = Vector3::new(0.0, 5.0, 0.0);
|
||||
Dimension::Linear(d)
|
||||
}
|
||||
|
||||
fn style() -> DimStyle {
|
||||
let mut s = DimStyle::standard();
|
||||
s.dimdec = 3;
|
||||
s.dimtdec = 3;
|
||||
// Keep trailing zeros so the expectations read like the drawing.
|
||||
s.dimzin = 0;
|
||||
s.dimtzin = 0;
|
||||
s.dimtp = 0.02;
|
||||
s.dimtm = 0.05;
|
||||
s
|
||||
}
|
||||
|
||||
// AutoCAD's DIMLIM shows the upper limit over the lower one and nothing
|
||||
// else. The renderer used to keep the nominal and hang the stack beside
|
||||
// it, so a drawing with limits-only styles grew an extra number on every
|
||||
// regenerated dimension.
|
||||
#[test]
|
||||
fn limits_replace_the_nominal() {
|
||||
let mut s = style();
|
||||
s.dimlim = true;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some((r"\S10.020^9.950;".to_string(), None))
|
||||
);
|
||||
}
|
||||
|
||||
// Stacked limits keep a common number of decimals: with DIMTZIN 8 the
|
||||
// zero in 10.020 stays because 9.965 has nothing to drop, while a pair
|
||||
// that both end in zero shortens together.
|
||||
#[test]
|
||||
fn limits_drop_trailing_zeros_only_together() {
|
||||
let mut s = style();
|
||||
s.dimlim = true;
|
||||
s.dimtzin = 8;
|
||||
s.dimtm = 0.035;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some((r"\S10.020^9.965;".to_string(), None))
|
||||
);
|
||||
s.dimtm = 0.08;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some((r"\S10.02^9.92;".to_string(), None))
|
||||
);
|
||||
s.dimtp = 0.0;
|
||||
s.dimtm = 0.0;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some((r"\S10^10;".to_string(), None))
|
||||
);
|
||||
}
|
||||
|
||||
// The offsets apply to the number the reader sees, which for a paper
|
||||
// space dimension is the DIMLFAC-scaled distance (and DIMRND-rounded).
|
||||
#[test]
|
||||
fn limits_are_offsets_from_the_scaled_measurement() {
|
||||
let mut s = style();
|
||||
s.dimlim = true;
|
||||
s.dimlfac = 7.5;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some((r"\S75.020^74.950;".to_string(), None))
|
||||
);
|
||||
s.dimrnd = 0.5;
|
||||
s.dimtp = 0.0;
|
||||
s.dimtm = 0.0;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some((r"\S75.000^75.000;".to_string(), None))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn limits_take_precedence_over_deviation() {
|
||||
let mut s = style();
|
||||
s.dimlim = true;
|
||||
s.dimtol = true;
|
||||
let (_, suffix) = dimension_text_parts(&horizontal(), Some(&s)).unwrap();
|
||||
assert_eq!(suffix, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deviation_keeps_the_nominal_and_a_separate_suffix() {
|
||||
let mut s = style();
|
||||
s.dimtol = true;
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some(("10.000".to_string(), Some(r"\S+0.020^-0.050;".to_string())))
|
||||
);
|
||||
}
|
||||
|
||||
// A per-entity DSTYLE override turning limits off (group 72 = 0) is how
|
||||
// the reference callouts in a limits-style drawing show a plain value.
|
||||
#[test]
|
||||
fn limits_off_shows_the_plain_value() {
|
||||
let s = style();
|
||||
assert_eq!(
|
||||
dimension_text_parts(&horizontal(), Some(&s)),
|
||||
Some(("10.000".to_string(), None))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_text_substitutes_the_stack_for_the_measurement() {
|
||||
let mut s = style();
|
||||
s.dimlim = true;
|
||||
let mut dim = horizontal();
|
||||
dim.base_mut().text = "<> REF".to_string();
|
||||
let (value, _) = dimension_text_parts(&dim, Some(&s)).unwrap();
|
||||
assert_eq!(value, r"\S10.020^9.950; REF");
|
||||
}
|
||||
|
||||
// Fit decisions size the text by its visible cells: a stack is as wide as
|
||||
// its wider half, drawn at DIMTFAC, not as wide as its control codes.
|
||||
#[test]
|
||||
fn text_cells_measure_the_wider_stack_half() {
|
||||
assert_eq!(text_cells("10.000", 0.5), 6.0);
|
||||
assert_eq!(text_cells(r"R\S1.020^0.98;", 0.5), 1.0 + 5.0 * 0.5);
|
||||
assert_eq!(text_cells(r"\S10.020^9.950; REF", 1.0), 6.0 + 4.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_limits_stack_is_two_halves_tall() {
|
||||
let mut s = style();
|
||||
assert_eq!(dimension_text_block_height(Some(&s), 2.0), 2.0);
|
||||
s.dimlim = true;
|
||||
s.dimtfac = 0.5;
|
||||
let expected = 2.0 * 0.5 * 2.0 * f64::from(crate::entities::text_support::STACK_HALF_SCALE);
|
||||
assert_eq!(dimension_text_block_height(Some(&s), 2.0), expected);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user