Commit Graph
271 Commits
Author SHA1 Message Date
Hakan Seven b667eeeb05 refactor(render): unify scene rendering paths
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.
2026-08-05 21:44:59 +03:00
Hakan Seven 657d023fb7 feat(ucs): integrate coordinate systems
Route coordinate input, geometry creation, transforms, properties,\nviews, and viewport persistence through a shared working plane.\n\nRefs #484
2026-08-04 23:17:54 +03:00
Hakan Seven b1d55c6a7e feat(view): add visual style previews
- preview render modes on hover without committing
- distinguish 2D and 3D wireframe fill and depth behavior

Refs #483
2026-08-04 21:23:25 +03:00
Hakan Seven 539d83de47 feat(grips): improve direct editing
Refit arcs from fixed control points and highlight hovered grips.
Let Lengthen preview from the cursor or accept a typed distance.
2026-08-04 16:27:03 +03:00
Hakan Seven 48332ee807 feat(area): add object and aggregate modes
Mesh-backed measurements need cached surface metrics. Keep shared loop collection available in web builds.
2026-08-03 22:31:20 +03:00
Hakan Seven de2707a23e fix(styles): apply active creation defaults
Resolve style properties before editors and previews open.
Use absolute annotation multipliers for style-driven objects.

Refs #401

Refs #431
2026-08-03 16:43:58 +03:00
Hakan Seven 25515fa33c feat(styles): overhaul style managers
Unify editor layouts, live previews, comparisons, read-only behavior, and localized controls across all named style managers.

Refs #629
2026-08-03 02:01:47 +03:00
Hakan Seven 3e6693b93f feat(locale): localize full interface 2026-08-02 22:09:25 +03:00
Hakan Seven 20c6d419e2 fix(dimensions): render custom arrow blocks
Refs #612
2026-08-02 16:06:37 +03:00
Hakan Seven e03e091b3c feat(annotation): integrate object contexts 2026-08-02 12:00:15 +03:00
Hakan Seven 5909540ebf fix(annotation): apply object context scaling 2026-08-02 03:02:11 +03:00
Hakan Seven 7b50d6a5a3 fix(solid): normalize quadrilateral edges
Accept perimeter and DXF Z point orders while keeping screen fill and interaction on the WCS-aware geometry.

Refs #617
2026-08-01 20:31:28 +03:00
Hakan Seven 1cf2b700ce fix(polyline): place added vertices live
Keep new vertices in grip placement until click and restore the original entity on Escape. Correct reverse direction and segment metadata across polyline variants.\n\nRefs #610
2026-07-31 23:36:07 +03:00
Hakan Seven 9fdd26e1ed build: update acadrust codec revision 2026-07-31 18:05:51 +03:00
Hakan Seven 2c64888048 fix(blocks): preserve UCS transformations
Bake BEDIT frames into block-local geometry while keeping model and viewport UCS isolated. Normalize legacy nonzero block origins during load.
2026-07-30 19:50:33 +03:00
Hakan Seven b8889ccd20 feat(mview): add viewport creation options
Support polygonal and object viewports through native clip-boundary handles, including clipped rendering and selection.

Closes #525
2026-07-27 19:28:51 +03:00
Hakan Seven 4a30928f5a fix(ui): refine empty drawing state
Show drawing defaults when nothing is selected and disable layout controls on Start.

Refs #514
Refs #515
2026-07-27 17:37:17 +03:00
Hakan Seven 759f2316aa fix(hatch): apply pattern property edits
Closes #476
2026-07-27 16:44:31 +03:00
Hakan Seven 6fb68d1c7c feat(scene): integrate DWG object data 2026-07-26 23:38:38 +03:00
Hakan Seven eb23715605 feat(scene): integrate standard DWG data 2026-07-26 22:30:14 +03:00
Hakan Seven 731df4a725 feat(cad): integrate standard codec coverage
Render, edit, query, select, and explode newly decoded standard entity variants. Pin acadifc de8d6b5 and preserve None color semantics.
2026-07-26 19:30:43 +03:00
Hakan Seven 34d0c377e2 fix(3d): complete ACIS solid rendering
- track per-face coverage and retain safe display fallbacks
- tessellate shared NURBS, pcurve trims and periodic surfaces
- pin the matching acadifc decoder revision
2026-07-26 01:35:16 +03:00
Hakan Seven ece5598372 fix: correct viewport stretch and SHX plots
Anchor the opposite viewport corner during grip and STRETCH resizing.
Match plotted stroke-font pen widths to the SDF atlas unless CTB overrides.

Closes #435
2026-07-24 19:26:10 +03:00
Hakan Seven ceddb287f5 fix(renderer): match leader and dash styles
Read canonical ACAD/DSTYLE overrides for leader color and arrow size. Scale block-local linetype patterns through INSERT transforms.

Closes #436
2026-07-24 19:04:57 +03:00
Hakan SevenandClaude Opus 4.8 ce49f4da0a fix(render): DXF leader hookline width + SHAPE name fallback; bump acadrust
Companion to the acadrust DXF-fidelity sweep (bump to 379ce12):
- Legacy LEADER hookline: underline the annotation using the leader's own
  stored text width (DXF code 41) when the MTEXT has no computed extents,
  so the landing spans the text instead of a short stub.
- SHAPE: resolve the glyph by name when the shape number is 0 (DXF SHAPE
  carries only the name), and search shape-file text styles when the entity
  has no direct style reference.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-24 11:30:03 +03:00
Hakan SevenandClaude Opus 4.8 0e61836e91 fix(properties): name AEC / proxy objects instead of "Unknown"
Selecting a proxy object we render from its cached graphics (an AEC
Wall/Door/Window and the like) showed "Unknown" as its type. The entity
now carries its real DXF class name from the CLASSES section (acadrust
bump), so surface it: ui_name_or_class title-cases the class ("AEC_WALL"
→ "Aec Wall") for the properties Type row and the status-bar label, and
still says "Unknown" only when the class truly can't be named.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-23 23:59:27 +03:00
Hakan SevenandClaude Opus 4.8 5e2b67c642 fix(linetype): keep complex linetypes precise at large coordinates
A circle with a complex linetype (embedded shapes/text, e.g. IZOLACE) drew
its dashes and symbols scattered far off the entity at UTM-scale
coordinates. Two defects compounded, both catastrophic-cancellation at a
~1.2M-unit origin:

- The single-entity complex-linetype path fed apply_along the wire's HIGH
  double-single half only (`base.points`), an absolute f32 quantised to
  ~0.1 at 1.2M. Walking the pattern along those points blew the shape /
  dash positions up to ~1e308. Reconstruct the absolute f64 path from
  high+low, re-origin it at the first vertex, walk apply_along in that
  local frame, then lift each result wire back to world with
  shift_wire_to_world (now pub(crate)) — the same local-frame trick the
  MLINE complex-linetype path already uses. Fixes every entity, not just
  circles.

- The circle was tessellated with truck's circle_arc (arc-through-three-
  points), whose fit cancels catastrophically at 1.2M and returned a ~3%
  radius wobble with uneven segments. Tessellate directly as a cos/sin
  polyline (adaptive segment count from the curve tolerance); adding a
  small ±r term to the centre stays precise, and the Lines path RTE-splits
  it. Arc and polyline bulges share the circle_arc root and remain to fix.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-23 17:16:57 +03:00
Hakan SevenandClaude Opus 4.8 2d3f33de10 fix(leader): suppress oversized arrowheads, keep them precise at UTM
Three defects made a leader's arrowhead render as one stray line far
longer than the leader itself, at UTM coordinates:

- The arrowhead was drawn even when it is larger than the first leader
  segment it sits on. A DIMASZ sized for a bigger plot (here 6 units on a
  ~1-4 unit pointer) painted a stroke longer than the whole leader.
  AutoCAD omits the arrowhead when it does not fit the first segment, so
  gate the arrow on `arrow_size <= first_segment_len`.

- Leader geometry was built as absolute f32. At UTM coordinates (Y ~ 4.5M,
  f32 ulp ~ 0.5) the oblique arrow tick's small cross-slope quantised
  away, collapsing the 45-degree tick into a flat horizontal line. Build
  the path and arrow in absolute f64 — the arrow around a local origin so
  append_arrow's f32 math stays precise — then RTE-split into the double
  single (points_low / fill_tris_low) at the end.

- The `_Oblique` / `_Archtick` arrowhead block mapped to ArrowKind::Tick
  with the full DIMASZ, but the tick emitter draws `size` to either side
  (half-length semantics, matching DIMTSZ). Pass half so an oblique
  arrowhead sizes to DIMASZ like every other arrowhead, not double.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-23 16:46:55 +03:00
Hakan SevenandClaude Fable 5 0d4bd274b4 style: clear two build warnings
- image_model.rs: drop unnecessary parentheses around a map's array
  literal return.
- text_support.rs: remove dead row_in_column / col_rows computation and
  its unused `li` binding (the only consumer).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 11:39:23 +03:00
Hakan Seven 1803f10264 Merge PR #442: cut mesh-import wire-set memory ~35% (#358)
entity_wires() returns the memoized Arc instead of a per-call deep copy;
MESH entities over 50k vertices ship no per-vertex snap/key tables
(matching PolyfaceMesh/PolygonMesh); the Face3D/other render split
caches a None marker and uses the base set directly when there is no
Face3D wire; test fix for the depth-map BlockCache::build signature.

Reviewed: correctness sound — wire AABB comes from entity_aabb (not
key_vertices) so large meshes stay selectable; snap consumers are
empty-guarded; the Arc/strong_count reasoning for try_resident_patch
holds. One consistent pre-existing quirk noted (auto_fit_viewport
centroid excludes tableless meshes, as Poly*Mesh already do).
2026-07-23 10:25:27 +03:00
Hakan SevenandClaude Fable 5 faa135a7a1 fix(mleader): read the attachment anchor from the annotation context
The horizontal attachment point was read from the entity-level field,
which only exists from R2010 on; older records (R2007 and earlier) left
it at the default and centre/right-attached leaders shifted. The
annotation context carries the same value in every version, so anchor
from there for both the render and the width-grip geometry.

acadrust bump also brings: the R2007 MULTILEADER tail gating (leaders no
longer render upside-down), the R2004-R2006 inline SAB payload read, the
v1-SAT wireframe point_present decode (3D solids/regions land in place
on R2000/R2004), and the XCLIPFRAME default of 2 so clip-frame borders
draw on files whose header omits the variable.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 08:15:51 +03:00
Hakan SevenandClaude Fable 5 bfcc71678a fix(mline): drive geometry from the stored vertex parameters
Element lines were re-derived from the style's flat offsets along the
vertex miters, but the file already stores the real numbers: each
vertex's per-element parameter list starts with the offset measured
ALONG THE MITER — corner lengthening (1/cos of the half-angle),
justification and scale baked in — followed by draw/gap toggle
distances along the segment, which is how crossing multilines cut
each other. Re-deriving pinched the channel at every corner (the ends
looked flared) and drew full uncut lines through crossings, stacking
intersecting multilines on top of each other.

mline_lines now consumes the stored parameters directly (runs chain
across vertices when continuous; an odd toggle count leaves the last
run open to the segment end) and computes end caps from the actual
per-vertex offsets. Files without parameters keep the style-offset
fallback.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 07:00:35 +03:00
Hakan SevenandClaude Fable 5 bcd1fc15ea feat(shx): real SHX glyphs for text fonts and linetype shapes
The SHX reader now serves all three consumers instead of just SHAPE
entities:

- Complex-linetype shape elements stopped being skipped: a document
  linetype's Shape{number} resolves its style's shape file (shared path
  fallbacks) and draws the real glyph; `.lin` catalog references keep
  the file token and look the shape up by name. The converted-LFF
  substitute set remains the fallback for anything unresolved.

- Face::Shx renders resolvable on-disk .SHX text FONTS with their real
  stroke glyphs: character code → shape lookup, cap height normalised
  to the 9-unit space every stroke-font consumer expects, advance from
  the interpreter's final pen position, line spacing from the shape #0
  above/below header, TTF fallback per missing glyph.
  resolve_text_style resolves a style's .shx next to the drawing and
  passes the absolute path through; unresolvable names keep their LFF
  substitutes. Shapes-only files (no #0 header) are refused as fonts.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 06:44:48 +03:00
Hakan SevenandClaude Fable 5 1de4344280 feat(shape): render SHAPE entities from their compiled SHX shape file
SHAPE entities only drew a diamond placeholder — .SHX files were never
parsed. A new reader (scene/text/shx.rs) decodes the classic
`AutoCAD-86 shapes 1.0/1.1` container and interprets the full shape
bytecode — pen up/down, scale divide/multiply, position push/pop,
subshapes, signed XY runs, octant/fractional/bulge arcs, the 16
direction vectors and the vertical-only skip — into unit-space
polylines, cached per file and per shape number.

The entity resolves its STYLE by handle (name fallback), the style's
shape file with the shared path fallbacks (as stored → relative to the
drawing → basename next to it; traded files carry foreign absolute
paths), then places the glyph with size × relative X scale, oblique
shear and rotation through the OCS mapping. load_file now records
doc.source_path so render-time resolution knows the drawing's folder.
A missing or unreadable shape file keeps the diamond placeholder.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 03:53:41 +03:00
Hakan SevenandClaude Fable 5 f4f8c0687c fix(image): stop darkening rasters; X only for broken references
Image textures were created Rgba8UnormSrgb: sampling decoded sRGB to
linear, but the surface isn't sRGB, so every raster (images, OLE, PDF
underlays) rendered visibly dark. Rgba8Unorm passes the texels through
in the same space as every other colour in the app.

The frame wire also always carried the X diagonals — that's the
broken-reference placeholder, and it scribbled over resolvable images.
The diagonals now draw only when the reference doesn't resolve.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 03:41:52 +03:00
Hakan SevenandClaude Fable 5 1e913e9e78 feat(underlay): render PDF underlays end-to-end
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]>
2026-07-23 03:41:41 +03:00
Hakan SevenandClaude Fable 5 ac0a6ac150 fix(mleader): honour the baked context — anchors, rotation, dogleg, frames
The annotation context is AutoCAD's baked display state; the renderer
now trusts it instead of re-deriving:

- text_attachment_point (L/C/R) is the stored horizontal anchor — the
  leader-side guess shifted centre/right-attached texts by their width.
- ctx.text_direction/text_rotation apply as stored; forcing the
  Horizontal angle type to 0 un-rotated angled leaders. The conn.y
  baseline snap now applies only to unrotated text.
- The dogleg runs along the leader root's stored direction (angled
  leaders drew it world-horizontal), and vertically-attached leaders
  draw no dogleg at all.
- Underline attachments (BottomLine / BottomOfTopLineUnderline…) draw
  the leader-coloured rule under the attached line(s), full text width.
- Vertical text flow (ctx.text_flow_direction) feeds the shared
  vertical layout; frame/background boxes wrap the laid-out glyph
  bounds padded by ctx.landing_gap, and run-less decoration strokes +
  inline \C colours reach the output instead of being dropped.
- The wrap-width grip rides the shared flow_grip_axis() (rotation, flow
  and attachment side), and its drag projects on the same axis.

acadrust bump: every MULTILEADER decodes (has_ds peek), MTEXT
top-to-bottom direction reads correctly.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 02:58:17 +03:00
Hakan SevenandClaude Fable 5 6e225e068c feat(text): real top-to-bottom layout; shared flow-aware width grips
Vertical (top-to-bottom) text used to reuse the horizontal line stack —
every line landed on the same baseline and overlapped. The layout now
stacks each character in its own 1.4h cell down the column, one column
per paragraph (1.2h apart), with word-boundary column wrap against the
defined width (which measures COLUMN LENGTH for vertical flow — the
horizontal pre-wrap is disabled there). Justification anchors place the
column block from wrap-accurate metrics: the pre-pass simulates the
render's word wrap exactly, so right/centre/bottom-attached blocks stay
put as columns grow. Layouts also report pre-rotation local_bounds so
frames and fills can box what was actually drawn.

Width grips route through one shared helper, flow_grip_axis(): the flow
axis (rotated baseline, or down the column) plus an attachment-side
factor — a right-attached text forms LEFT of its insertion, so its grip
sits there too; centre attachments use ±half. MTEXT's grip and drag
projection both use it, covering all 9 attachments × both flows × any
rotation from a single table.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 02:58:02 +03:00
Hakan SevenandClaude Fable 5 f1c494b81e fix(solid): skip display-cache wires when ACIS parses; real centres
The embedded solid display-cache wires are body-local (unplaced), and
R2013+ AcDs-backed solids used to misparse them into garbage points near
the origin — a clipped region rendered a stray fragment at (0,0,0). When
the ACIS payload parses, the mesh pipeline (fill + feature edges +
isolines, all body-placed) is the authoritative render, so the wires now
only serve as a last resort for unreadable ACIS data.

acadrust bump brings the decoded wireframe section and real reference
points: solids/regions report the file's stored bounding-box centre (or
a geometry-derived one) instead of (0,0,0), which feeds OCS grips,
Position properties and insertion snaps.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-23 01:13:43 +03:00
Hakan SevenandClaude Fable 5 bf06a8e330 fix(leader): derive hookline for DWG leaders; size it from the dim style
DWG stores no "hookline exists" flag (only the direction bit), so every
DWG-loaded leader kept hookline_enabled=false and drew no hook. Derive
it: a text-annotated leader hooks when its final segment leaves the
horizontal by more than 15°, shared by the render and snap/grip paths.

Hook length comes from the dim style like the arrowhead (DIMASZ ×
DIMSCALE), and with DIMTAD "text above" it extends under the annotation
to the far edge of the MTEXT's laid-out extents — newly exposed by
acadrust (lock bumped); the old text-height heuristic stays as the
no-style fallback.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 23:36:25 +03:00
Hakan SevenandClaude Fable 5 48e8988528 fix(spline): honour end tangents on a two-fit-point spline
fit_spline_polyline bailed to a straight chord below three fit points,
ignoring the stored begin/end tangents — a short tangent-clamped spline
rendered as a line. The C² solver handles n=2 as-is (both end rows are
clamp or natural conditions), so only the guard drops to n<2; tangentless
two-point splines still solve to the straight chord.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 23:36:15 +03:00
Kevin GriffinandClaude Fable 5 5aecdff12e perf(mesh): skip per-vertex snap tables above 50k vertices
The subdivision MESH converter emitted one snap candidate and one key
vertex per mesh vertex — ~56 B/vertex retained in every copy of the
wire set. On NWD-scale imports (#358: tens of millions of vertices)
that is GBs spent on snap targets far too dense to distinguish on
screen. PolyfaceMesh and PolygonMesh already ship empty tables at any
size.

Above 50,000 vertices, ship none. Smaller meshes (including the #358
repro sample at 34.6k vertices per mesh) keep vertex snap unchanged.

Measured (mem_probe_meshent, 1M-triangle MESH): 646 -> 589 B/face
resident; wire content 210 -> 183 MB per 1M triangles.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 12:59:07 -07:00
Hakan SevenandClaude Fable 5 e7eb84b514 feat(pedit): convert prompt, join, fit/spline/decurve; join fixes (#263)
PEDIT reworked around a mode machine:

- Picking a line/arc asks "Object is not a polyline. Turn it into one?
  [Yes/No] <Y>" — Yes converts in place (arc keeps its bulge) and
  editing continues on the result. Pickfirst: an already-selected
  polyline skips the select step, a selected line/arc goes straight to
  the convert prompt.
- Join gathers with the normal selection system (single picks AND
  window/crossing boxes) and merges through the JOIN machinery.
- Fit replaces every segment with a classic equal-parameter BIARC: two
  arcs per segment meeting tangentially at an inserted knee, both
  segments at a vertex sharing that vertex's tangent — the whole run is
  tangent-continuous (verified: zero tangent jump on L/closed/zigzag/S
  shapes). Spline resamples the vertex frame as a uniform cubic
  B-spline (8 samples per span); Decurve straightens every bulge.
- Earlier hardening kept: undo snapshot before the mutation, immediate
  repaint, polyline-only pick validation.
- Vertex editing lives on grips, so no Edit-vertex submode; instead the
  vertex grip hover menu gains Break — a closed polyline opens at the
  vertex, an open one splits into two (interior vertices only),
  handled driver-side as an entity replacement.

JOIN itself: segs_of now emits one segment per span of an OPEN
polyline (bulges kept), so polylines merge with their neighbours —
PEDIT Join's set always contains the target polyline and used to abort
every time; plain JOIN had the same gap. JOIN also honours pickfirst:
launched with two or more objects selected it joins them immediately.

Closes #263

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 20:06:04 +03:00
Hakan SevenandClaude Fable 5 b998082c82 fix(props): angle rows format via AUNITS, not LUNITS (#297)
Every angle row went through the linear formatter, so switching LUNITS
to Architectural showed a block's Rotation as feet-and-inches — and the
string wouldn't parse back, wedging the field until it was cleared and
retyped. Only the decimal/fractional LUNITS survived by accident.

New edit_angle row helper formats angles with format_angle
(AUNITS/AUPREC: decimal degrees, DMS, grads or radians), applied to all
17 angle rows (rotations, obliquing, arc start/end, hatch pattern
angle, multileader text rotation). parse_angle_deg converts every
AUNITS display form back to degrees ("30°"/"30d", DMS 30°15'20",
33.33g, 0.52r) and parse_f64 falls back to it, so the displayed value
round-trips through an edit.

Closes #297

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 16:42:14 +03:00
Hakan SevenandClaude Fable 5 d2be0c9bea fix(pline): Convert to Arc follows the cursor and seats on click (#339)
Three fixes to the polyline arc-segment grip:

- bulge_from_midpoint keyed the sign off which chord side the midpoint
  lies on — the opposite convention of BulgeArc::from_bulge, so every
  grip-drag frame flipped the arc to the other side and the radius
  jumped wildly ("snaps to a restricted range of radii"). It now
  derives sign and sweep from the p0 -> mid -> p1 traversal
  orientation, verified as the exact inverse of BulgeArc's midpoint.

- The arc segment's mid grip dragged in Translate mode, feeding
  per-frame deltas through the recomputed arc midpoint — the drag
  deadlocked the moment the cursor crossed the chord. Arc grips now
  drag in Absolute mode: the arc re-fits through the cursor itself.
  Straight-segment grips keep the Translate stretch.

- Picking Convert to Arc in the grip menu now engages that segment
  grip (the Add Leader placement mechanic), so the new arc follows the
  mouse immediately and the next click seats it.

Closes #339

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 12:15:36 +03:00
Hakan SevenandClaude Fable 5 87049967a2 fix(render): close remaining OCS/WCS gaps for mirrored entities
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]>
2026-07-21 17:58:09 +03:00
Hakan SevenandClaude Fable 5 eb0073781f fix(render): LINE/POINT endpoints are WCS, not OCS
DXF/DWG store LINE endpoints and POINT locations in world coordinates -
the extrusion normal only orients the thickness sweep / glyph. Running
them through the arbitrary-axis OCS mirrored every line and point
carried over from a MIRROR (normal 0,0,-1) onto the wrong side of the
drawing: bolt shafts of a mirrored detail block landed in the adjacent
panel while its nut arcs (correctly OCS-mapped) stayed put.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-21 17:27:51 +03:00
Hakan SevenandClaude Fable 5 e177f92ff5 fix(xref): blocks respect their internal draw order
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]>
2026-07-21 15:53:28 +03:00
Hakan SevenandClaude Fable 5 1546c1dc30 fix(polyline): spline-fit 2D polylines draw the curve, not the frame
A curve-/spline-fit heavy polyline stores both the fitted curve points
(vertex flag 8 / 1) and the spline-frame control points (flag 16),
which only SPLFRAME is meant to show. Chaining every stored vertex
drew spokes from the curve to the control frame — stray points on the
curve and, on wide polylines, a blobbed band (#408). drawn_vertices2d
now drops the control points whenever fit data is present (falling
back to the stored vertices when it is not) and feeds the wire, the
wide-band fills and the tapered band alike, so snapping no longer
lands on frame points either.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-21 15:12:52 +03:00
Hakan SevenandClaude Fable 5 930d8c51ea feat(gradient): selectable gradient types + working creation
GRADIENT silently degraded to a plain hatch: add_hatch rebuilt the
render model from the DXF entity but never encoded the gradient on it,
so the committed fill lost its gradient entirely. The entity now
carries the full gradient record (name, angle, colour stops,
solid-fill flag), and the standard shape set became selectable:
Linear / Cylinder / Spherical / Hemispherical / Curved plus an Invert
toggle, offered as prompt buttons on the GRADIENT command and as a
Gradient type dropdown + Invert box in the properties panel. All nine
standard DXF names round-trip (inverted linear persists by swapping
the colour stops), and the shaders shape each kind distinctly —
mirrored cylinder, eased curve, dome-profiled hemisphere — on both the
native and web pipelines without changing the GPU struct sizes.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-21 12:51:08 +03:00