Skip to content

Fix a bulge over a zero-length segment discarding the whole polyline - #1229

Open
redbluevn wants to merge 1 commit into
DomCR:masterfrom
redbluevn:moredwg/pr77-degenerate-bulge
Open

Fix a bulge over a zero-length segment discarding the whole polyline#1229
redbluevn wants to merge 1 commit into
DomCR:masterfrom
redbluevn:moredwg/pr77-degenerate-bulge

Conversation

@redbluevn

Copy link
Copy Markdown

The problem

When any vertex carries a bulge, a polyline's bounding box is computed by tessellating each segment through Arc.CreateFromBulge.

A repeated vertex that still carries a bulge describes an arc over a chord of no length. Arc.GetCenter computes c = start.DistanceFrom(end) / 2.0 — zero — so radius = c / sin(theta/2) is exactly zero, and Circle's Radius setter throws:

if (value <= 0)
	throw new ArgumentOutOfRangeException(nameof(value), value, "The radius must be greater than 0.");

One such vertex therefore threw away the measurement of the entire polyline — and, because polylines live inside blocks, of every insert of that block.

Duplicated vertices are common in real exports.

The fix

Such a segment covers no ground, so it contributes its endpoints and nothing else.

Evidence

Across eighteen architectural drawings: two zero-length bulged segments, one of them throwing. After this, no entity in the corpus fails to report a box. The only remaining non-measurable entities are Regions, which return BoundingBox.Null by design because modeler geometry is not tessellated — that is not a defect and is left alone.

Adjacent, not fixed here

Three more paths can throw out of GetBoundingBox for the same reason — a raw value the readers store faithfully and an entity setter refuses:

  • Hatch.BoundaryPath.Arc.GetBoundingBox builds an Arc entity, so an edge with radius ≤ 0 throws. (The entity reader already clamps this — DwgObjectReader maps radius <= 0 to MathHelper.Epsilon — but the boundary-edge reader does not.)
  • Hatch.BoundaryPath.Ellipse.GetBoundingBox builds an Ellipse, so an edge ratio of 0 or above 1 throws.
  • BlockRecord.GetBoundingBox evaluates every child's box twice, once for the infinite check and once for the merge — quadratic through nested blocks.

None of the three occurs in my corpus (measured: 0, 0, and the double evaluation is a cost not a fault), so I have left them out rather than ship unexercised code. Raising them in case they are worth a separate look.

Tests

ABulgeOverAZeroLengthSegmentDoesNotThrow fails against the current code with ArgumentOutOfRangeException.

dotnet test: 2314 passed / 17 failed, against master at 592d70a on this machine at 2313 / 17.

Related

#1223, #1224, #1225, #1226, #1227 and DomCR/CSUtilities#23.

When any vertex carries a bulge, a polyline's bounding box is computed by
tessellating each segment through Arc.CreateFromBulge. A repeated vertex that
still carries a bulge describes an arc over a chord of no length: the radius its
own maths recovers is exactly zero, and Circle's Radius setter throws
ArgumentOutOfRangeException over it. One such vertex therefore threw away the
measurement of the entire polyline - and, because polylines live inside blocks,
of every insert of that block.

Duplicated vertices are common in real exports. Such a segment covers no ground,
so it now contributes its endpoints and nothing else.

Measured over eighteen architectural drawings: two zero-length bulged segments,
one of which was throwing. After this, no entity in the corpus fails to report
a box - the only remaining non-measurable entities are Regions, which return
BoundingBox.Null by design because modeler geometry is not tessellated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@redbluevn
redbluevn force-pushed the moredwg/pr77-degenerate-bulge branch from 010c53c to 6767f53 Compare September 5, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant