Creating a block from selected entities now bumps the geometry epoch, so the
block palette's per-update stale check notices the new definition and refreshes
its list in place instead of requiring the user to close and reopen the panel.
Share source buffers across block placements and render nested content with GPU instance transforms.\n\nChunk silhouettes and compact mesh material data so large drawings stay under device buffer limits and remain responsive.
The last four truck crates are gone from the manifest. What they were doing
falls into three parts, and each now has one answer instead of two.
NURBS evaluation. truck was carrying B-spline curves and surfaces for the
SPLINE entity, hatch boundaries, BLEND's endpoint frames, the spline preview
and ACIS spline-surface faces. The kernel now has both, over one de Boor
written across however many coordinates a control point holds — so a plane
curve and a space curve cannot drift apart, and a surface is the same
algorithm applied twice. The rational and the polynomial cases stop being
separate types: weights absent means polynomial.
The entity conversion. Every LINE, ARC, ELLIPSE, SPLINE and polyline was
built into truck topology purely so it could be sampled back into points.
They are sampled through `entities::curve` now, which is where each one's
geometry is already defined once and what EXTRUDE and REVOLVE read — so a
circle drawn on screen and a circle handed to the Model tab come from the
same definition. That retires four of TruckObject's variants and the module
is renamed for what it does.
SWEEP and LOFT. Both only ever produced a mesh, so both are built from point
lists: a band of quads per span, and a lid where a profile closes. Lofting
profiles of different densities resamples them by distance rather than by
index, so a circle lofted to a square no longer twists.
Two things worth noting for anyone reading the old comments. The tolerance
globals that lived in the tessellation module were never about truck at all —
they are the per-frame chord height, and they move to `curve_tol`. And the
rule that a profile handed over as `Lines` silently broke EXTRUDE and REVOLVE
no longer holds: those read the curve directly and never look at this channel.
The two `automation` test failures are unchanged from before this and are not
caused by it.
Co-Authored-By: Claude Opus 5 <[email protected]>
Route model, paper, viewport and nested block content through one traversal while preserving leaf renderers. Carry decoded material state into mesh shading and harden solid geometry conversion.
Keep Layout output on the selected physical sheet and preserve hatch lineweights and plot styles through paper, viewport, and nested block paths.\n\nRefs #607
Use the same area pipeline as model space while keeping Layout bound to the physical sheet and printable margins. Share scale, rotation, clipping, and viewport fills across preview, PDF, and printer output.
Avoid full document, cache, and GPU rebuilds for entity deltas so add, delete, history, selection, and live polyline edits stay responsive on large drawings.
Keep resident wires, draw depths, GPU slabs, and edit history incremental across entity changes. Defer rollover work to avoid cursor jumps on dense drawings.
Replace full-document snapshots with Arc first-touch deltas and batch cache invalidation. Reuse interaction and GPU category caches across unrelated edits.
A wipeout defined inside a block never masked the geometry once the block
was inserted — wipeout_models only scanned top-level entities, so the
wipeout was invisible unless you entered block-edit (where it is
top-level). It also drew a stray mask at its raw block-local coordinates
because the top-level scan lacked the block-defn reject the hatch path
uses.
Descend visible inserts and place each block-internal wipeout in world
space, applying the accumulated insert transform via apply /
apply_rotation. Add the belongs_to_visible_block filter so block-defn
wipeouts only appear through the descent, in world space.
Bumps acadrust for the matching transform_wipeout fix: its u/v basis was
double-scaled (apply_rotation then another scale-factor multiply), so a
scaled insert grew the mask; the descent sidesteps that path but the
explode/copy commands need the crate fix.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Two rendering defects surfaced on the budweiser benchmark drawings, both
tied to a drawing's annotation scale.
Annotative scale representations. A drawing may materialise each annotation
scale as its own object (here a block insert per scale, on a "0 @ <scale>"
layer, each carrying a per-object AcDbContextData bound to one scale).
Nothing filtered them, so every scale drew at once — a 1× copy stacked
under a 10× one. Add annotative::annotative_offscale and apply it in the
three paths that expand block content: the wire block-defn cache, the
resident/top-level visibility gate (model space only — paper viewports use
their per-viewport frozen scale layers), and the exploded-insert hatch/fill
walk (filtered before normalize strips the handle). An object is shown when
a representation matches the current scale; the off-scale ones are hidden.
When the current scale is unsupported by any representation, fall back to
the base "1:1" copy instead of hiding everything (the object must not
vanish) or showing everything (the copies must not stack).
Model-space linetype scale. PSLTSCALE (a paper-space flag) was applied to
model-space linetypes via the annotation scale, so a drawing saved at e.g.
CANNOSCALE 10:1 drew its linetypes 10× off. Thread a `paper_space` flag
through tessellate_entity and gate the PSLTSCALE factor on it, so it only
scales linetypes for content shown inside a paper-space viewport; model
space keeps LTSCALE × CELTSCALE.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
A dimension bakes its geometry into a per-instance *D block, offset into
the owning block by the dimension insertion_point. When that dimension
sits inside a block (INSERT → block → Dimension → *D), only its top-level
form drew; nested it rendered nothing, and once the lines/text/arrow
outlines were routed through the block cache the arrowhead FILLS were
still missing:
- 2D SOLID arrowheads: block_cache's Dimension arm now expands the *D
block, translating each sub by insertion_point (WCS → block-local) and
routing Insert subs through build_nested_ref, others through
tessellate_sub_local (which emits the solid fill_tris).
- Insert(hatch) arrowheads (custom arrow blocks = LwPolyline + Hatch):
the hatch renders via the separate GPU explosion path, which only
descends INSERT→INSERT→Hatch trees and so never reached a hatch behind
a Dimension. block_has_hatch now recurses through a Dimension into its
*D block, and the fill explosion's new explode_including_dims lifts
each dimension child's *D content into the owning block's frame
(translate insertion_point, then apply the insert transform) so its
arrow inserts / hatches ride the normal walk.
Table *T baked blocks get the mirror treatment in block_cache.
Co-Authored-By: Claude Fable 5 <[email protected]>
The wipeout pass ran after the wire pass with no draw-order bias, so
the mask erased its own boundary frame (and everything else at its
plane regardless of draw order). The mask uniform now carries the
entity's draw-order depth (uniform grows 80 → 96 bytes) and biases its
clip-z like every other pipeline, and the frame wire rides a
+half-rank override — the later mask pass fails the depth test at the
frame's pixels, so the boundary stays visible, while entities drawn
above the wipeout are no longer erased.
Co-Authored-By: Claude Fable 5 <[email protected]>
PDF underlays only drew their clip outline / insertion cross; the page
itself never appeared. The chain now runs: the definition's file path
resolves with the raster-image fallbacks (as stored, relative to the
drawing, basename next to the drawing — attach-time relative paths go
stale), the page rasterises through the system pdftoppm (poppler) at
150 dpi — no new crate; missing tool degrades to the outline — cached
per (path, page) including negative results, and the pixels feed the
existing image pipeline as an ImageModel: 1 underlay unit = 1 PDF inch
(px/dpi × entity scale), rotated about the insertion, fade as opacity,
the clip polygon (non-inverted) as the textured region. Draw-order,
layer visibility and per-viewport freezes ride the generic image path;
in-place edits rebuild through the shared image seed.
When the page renders, the wire path draws its frame with an interior
pick surface instead of the lone cross, so selection covers the visible
page. wasm keeps the outline placeholder (no external process).
Co-Authored-By: Claude Fable 5 <[email protected]>
- Block reference Name (Misc) is editable: the dropdown re-points the
insert to another definition; typing a new name renames the definition
everywhere (record re-key, Block marker, every INSERT reference).
Anonymous (*) and xref blocks stay read-only, with the same guards
added to Scene::rename_block.
- Custom single-control dropdown (text field + caret) built on the
shared floating_below overlay so the list always opens downward,
unlike iced's space-based menu placement.
- Consecutive "<Base> X/Y/Z" rows (Position, Scale, Start, Center, ...)
collapse into one expandable summary row across all entities; the
expand state persists across rebuilds and selection changes.
- The BEDIT block tab no longer offers the layout Rename/Delete
context menu.
Co-Authored-By: Claude Fable 5 <[email protected]>
Follow-up to the LINE/POINT WCS fix - the same bug class elsewhere:
- 2D SOLID rendered its OCS corners raw in both the wire path and the
shared fill builder (solid_hatch_model); SHAPE placed its marker at
the raw OCS insertion. Both now map through the arbitrary axis.
- Grips: central wrap in view/dispatch.rs shows planar entities' grips
at their world position (OCS→WCS) and converts drags back (WCS→OCS
via the new wcs_point_to_ocs) - per-entity grip code stays in raw
field space, INSERT keeps handling its own OCS.
- Pulls acadrust 81ebfee: OCS-aware bounding boxes, translate,
transform and mirror for the ten planar entity types, so MOVE /
ROTATE / MIRROR and culling work on mirrored entities too.
Co-Authored-By: Claude Fable 5 <[email protected]>
Xref merge now inserts entities in the source block's chain order and
carries SortEntitiesTable objects across (remapped to merged handles).
draw_depth_map values become [depth, half] so exploded block/xref fills
and wide-polyline band wires both compose child depth as
insert_depth + in-block rank x half, recursing into nested inserts with
the same divisor - bands and fills from one block interleave by the
block's internal order instead of stacking at the insert's single depth.
Band batches split per rank via WireModel.depth_override; thin wires
stay merged. The wire arena falls back to a full rebuild when a slab
carries mixed depths so refreshes don't flatten band overrides.
Co-Authored-By: Claude Fable 5 <[email protected]>