fix(render): halve polyline width — wide bands drew twice as wide

DXF codes 43 / 40 / 41 store a polyline band's full width, and
`polyline_segment_fill` offsets ±hw about the centreline, so the stored
value has to be halved. Both `wide_fills` passed it in whole and drew
every wide polyline at double width.

The codebase was writing the spec value and reading it as something else:
`make_donut` stores `outer_r - inner_r`, a full width, which `wide_fills`
then treated as a half-width. So OCS mis-drew even its own donuts.

Seen on budweiser2018.dwg handle 2579, a donut of width 2.2 on a 1.1
centreline radius: it should fill out to radius 2.2 and instead reached
3.3 — a disc 1.5× its real size, overflowing the square it sits in.

Affects every wide polyline, so TRACE and PEDIT-widened runs come back to
true size too. The writers already stored full width and are left alone,
as is the property panel, which shows the file's own value.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-17 15:00:06 +03:00
1 parent 3f060a570a
commit 07d7888b94
2 files changed
+13 -9

No files matched your search

+8 -5
View File
@@ -662,9 +662,12 @@ impl crate::entities::traits::Transformable for LwPolyline {
/// UTM-scale coordinates — building them in absolute f32 collapsed the band into
/// a string of squares far from the origin.
pub(crate) fn wide_fills(pl: &acadrust::entities::LwPolyline) -> ([f64; 2], Vec<Vec<[f32; 2]>>) {
// The stored width is applied to EACH side of the centreline (not halved),
// so `polyline_segment_fill`'s ±offset spans the full width on either side.
let hw_const = pl.constant_width as f32;
// Codes 43 / 40 / 41 store the band's FULL width, and
// `polyline_segment_fill` offsets ±hw about the centreline — so halve it.
// Feeding the stored width in whole draws every wide polyline twice as wide
// as the file asks for, which on a donut (a closed 2-vertex bulge-1 polyline)
// shows up as a disc 1.5× its real radius.
let hw_const = pl.constant_width as f32 * 0.5;
let verts = &pl.vertices;
let n = verts.len();
if n < 2 {
@@ -677,12 +680,12 @@ pub(crate) fn wide_fills(pl: &acadrust::entities::LwPolyline) -> ([f64; 2], Vec<
let v0 = &verts[i];
let v1 = &verts[(i + 1) % n];
let hw0 = if v0.start_width > 1e-9 {
v0.start_width as f32
v0.start_width as f32 * 0.5
} else {
hw_const
};
let hw1 = if v0.end_width > 1e-9 {
v0.end_width as f32
v0.end_width as f32 * 0.5
} else {
hw_const
};
+5 -4
View File
@@ -770,8 +770,9 @@ impl Transformable for Polyline3D {
/// relative to (the first vertex). See `lwpolyline::wide_fills` — offsets are
/// f32 from `origin` so the band stays precise at UTM-scale coordinates.
pub(crate) fn wide_fills(pl: &acadrust::entities::Polyline2D) -> ([f64; 2], Vec<Vec<[f32; 2]>>) {
// Width is applied full to each side of the centreline (not halved).
let hw_default = pl.start_width.max(pl.end_width) as f32;
// The stored widths are the band's FULL width and `polyline_segment_fill`
// offsets ±hw about the centreline — halve them. See `lwpolyline::wide_fills`.
let hw_default = pl.start_width.max(pl.end_width) as f32 * 0.5;
let verts = &pl.vertices;
let n = verts.len();
if n < 2 {
@@ -784,12 +785,12 @@ pub(crate) fn wide_fills(pl: &acadrust::entities::Polyline2D) -> ([f64; 2], Vec<
let v0 = &verts[i];
let v1 = &verts[(i + 1) % n];
let hw0 = if v0.start_width > 1e-9 {
v0.start_width as f32
v0.start_width as f32 * 0.5
} else {
hw_default
};
let hw1 = if v0.end_width > 1e-9 {
v0.end_width as f32
v0.end_width as f32 * 0.5
} else {
hw_default
};