diff --git a/src/app/control/mod.rs b/src/app/control/mod.rs index fb73518bb..1ee429364 100644 --- a/src/app/control/mod.rs +++ b/src/app/control/mod.rs @@ -2907,8 +2907,8 @@ mod tests { assert_eq!(response["status"], "completed", "{response}"); // The plotted PDF carries two distinct pen widths — the per-layer - // 0.13 mm / 0.50 mm hierarchy survives the plot style (thin clamps to - // the 1 px floor, so the ratio is the clamped-pixel ratio 1.889). + // 0.13 mm / 0.50 mm hierarchy survives the plot style at its true + // ratio; the screen's 1 px floor does not reach the plot (#1749). let text = crate::io::pdf_export::pdf_stream_text(&std::fs::read(&pdf).expect("pdf written")); let tokens: Vec<&str> = text.split_whitespace().collect(); @@ -2931,7 +2931,7 @@ mod tests { "two layer weights in the plotted PDF: {widths:?}" ); assert!( - (widths[1] / widths[0] - 1.889).abs() < 0.15, + (widths[1] / widths[0] - 50.0 / 13.0).abs() < 0.15, "0.50 mm vs 0.13 mm hierarchy: {widths:?}" ); let _ = std::fs::remove_file(&pdf); diff --git a/src/scene/pipeline/circle_gpu.rs b/src/scene/pipeline/circle_gpu.rs index 8e3d8e06b..badb17851 100644 --- a/src/scene/pipeline/circle_gpu.rs +++ b/src/scene/pipeline/circle_gpu.rs @@ -264,7 +264,7 @@ pub fn extract_circle_instance_from_geom_indexed( } let (ch, cl) = split_ds_xyz(center[0], center[1], center[2]); - let hw = wire.line_weight_px * 0.5; + let hw = wire.line_weight_px.max(1.0) * 0.5; let pat0 = [ wire.pattern[0], wire.pattern[1], diff --git a/src/scene/pipeline/ellipse_gpu.rs b/src/scene/pipeline/ellipse_gpu.rs index 666aa3963..87eb84e8a 100644 --- a/src/scene/pipeline/ellipse_gpu.rs +++ b/src/scene/pipeline/ellipse_gpu.rs @@ -235,7 +235,7 @@ pub fn extract_ellipse_instance_from_geom( } let (ch, cl) = split_ds_xyz(center[0], center[1], center[2]); - let hw = wire.line_weight_px * 0.5; + let hw = wire.line_weight_px.max(1.0) * 0.5; let pat0 = [ wire.pattern[0], wire.pattern[1], diff --git a/src/scene/pipeline/wire_gpu.rs b/src/scene/pipeline/wire_gpu.rs index 2a64f1357..bee7f0267 100644 --- a/src/scene/pipeline/wire_gpu.rs +++ b/src/scene/pipeline/wire_gpu.rs @@ -863,7 +863,7 @@ pub(crate) fn emit_wire_packed( wire.pattern[6], wire.pattern[7], ]; - let half_width = wire.line_weight_px * 0.5; + let half_width = wire.line_weight_px.max(1.0) * 0.5; let n = wire.points.len(); let seg_count = n.saturating_sub(1); if seg_count == 0 { @@ -965,7 +965,7 @@ pub(crate) fn emit_wire_native( wire.pattern[6], wire.pattern[7], ], - half_width: wire.line_weight_px * 0.5, + half_width: wire.line_weight_px.max(1.0) * 0.5, pattern_length: wire.pattern_length, draw_depth, align_end, diff --git a/src/scene/view/render.rs b/src/scene/view/render.rs index 2113eab94..7a8f9b99e 100644 --- a/src/scene/view/render.rs +++ b/src/scene/view/render.rs @@ -3589,9 +3589,11 @@ pub struct InheritStyle { } /// Convert a concrete (already layer-resolved) lineweight to display pixels. +/// Kept below 1 px for thin weights so plots and SVG get the true width; +/// the GPU paths draw at least 1 px (#1749). pub(crate) fn lineweight_to_px(lw: &LineWeight) -> f32 { lw.millimeters() - .map(|mm| (mm as f32 * MM_TO_PX).max(1.0)) + .map(|mm| mm as f32 * MM_TO_PX) .unwrap_or(1.0) }