PolyfaceMesh and PolygonMesh were wireframe-only. They now render with
the same flat-color solid fill as Face3D entities.
- Add fill_tris: Vec<[f32;3]> to TruckEntity and WireModel
- PolyfaceMesh: fan-triangulate each face into fill_tris
- PolygonMesh: triangulate each grid quad into fill_tris
- tessellate.rs Lines branch: apply world_offset to fill_tris
- Face3DGpu::from_wires: collect fill_tris from all wires in addition
to Face3D key_vertices quads
- upload_face3d: pass all_wires so fill_tris are batched into one draw call
Parsing + DerivedCaches construction now runs entirely in a dedicated
OS thread inside open_path(). FileOpened handler only assigns the
pre-built caches, keeping the UI thread free during file load.
- Add build_derived_caches(): parallel hatch + mesh tessellation via rayon
- Extend Message::FileOpened / open_path return type with DerivedCaches
- Drop populate_*_from_document() calls from FileOpened handler
- Hatch pattern_scale multiplied by annotation_scale in model space so
pattern density stays consistent when CANNOSCALE changes
- Annotative check now uses AcAnnoPO xdata (R2007+ marker) instead of
relying solely on group-code-293 flag; falls back to is_annotative
for files with no xdata (old DXF backward compat)
- acadrust patched to local path for is_annotative field
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Scale popup dropdown replaces cycle behavior; paper-space viewport scale
editable when a viewport is active/selected
- CANNOSCALE persisted via DXF $USERR1 (read on open, write on save)
- PSLTSCALE: linetype dash lengths scaled by viewport anno_scale so dashes
appear uniform physical size in paper space
- MultiLeader: arrow size, dogleg length, and text height scale with
anno_scale; leader line paths (world coords) stay fixed
- Leader: arrow size and hookline length scale with anno_scale; also
corrects world_offset subtraction that was previously deferred to the
TruckObject::Lines path
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Viewport-projected wires now clip at pixel level to their viewport boundary.
- WireModel.vp_scissor: Option<[f32; 4]> — paper-space bbox set on projection
- WireGpu.vp_scissor carries it through to the draw loop
- Pipeline.compute_wire_scissors() converts paper→NDC→pixel each frame
- render() calls set_scissor_rect() per wire, reset after viewport group
- INTEGRATION_GAPS.md: Viewport ⚠️ → ✅, all 51 gaps resolved
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
LwPolyline PLINEGEN=0 (DXF default): emit SegmentedLines with NaN
separators between vertex-to-vertex segments; wire_gpu resets
arc-length to 0 after each NaN so linetype pattern restarts per vertex.
PLINEGEN=1: existing Contour path unchanged (continuous pattern).
WireModel gains plinegen field propagated through tessellate pipeline.
Solid3D/Region/Body: call SabReader::read() when parse_sat() returns
None due to binary SAB format (DWG files / newer AutoCAD exports).
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
cxf.rs: missing non-ASCII glyphs now emit eprintln! once per font+char
pair via a global Mutex<HashSet> dedup set. ASCII chars silent (expected).
INTEGRATION_GAPS.md: ellipse partial arc snap marked done — endpoints are
correctly emitted via key_vertices → SnapType::Endpoint in snap engine.
Unicode warning gap closed. plinegen behaviour documented.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
OLE2Frame: full TruckConvertible/Grippable/PropertyEditable/Transformable
impls in src/entities/ole2frame.rs — grips on corners + center, properties
panel, translate/scale transforms.
Shape: rotation (DXF code 50) now converted degrees→radians on load in
fix_dxf_dimension_rotations(), matching Dimension and Attribute behaviour.
All ❌ gaps resolved. Remaining: Viewport GPU scissor, LWPolyline plinegen.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Tessellates bottom + top paths with NaN-separated walls at each vertex.
Arc segments (bulge != 0) use 16-step parametric tessellation.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Arc: tessellates bottom + top arcs (32 segs each) with 2 endpoint walls.
Circle: tessellates bottom + top circles (64 segs each) with 4 quadrant walls.
Both use TruckObject::Lines with NaN-separated segments.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
When line.thickness != 0, renders 4 NaN-separated wire segments
(bottom, top, left wall, right wall) using TruckObject::Lines.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Dimension measurement origin points (first_point, second_point,
definition_point, angle_vertex, etc.) are now emitted as Node snap
hints so OSNAP Node mode can locate them precisely without relying on
the tessellated geometry wire alone.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Hatch boundaries with arc or ellipse edges were silently dropped from
the wire outline, leaving gaps in the hatch contour. CircularArc and
EllipticArc boundary edges are now tessellated as polyline segments and
their centers are emitted as Center snap hints.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Entities carrying a non-standard extrusion normal (normal ≠ (0,0,1)) were
rendered flat in the XY plane. The DXF arbitrary-axis algorithm is now
implemented in scene::transform::{ocs_axes, ocs_point_to_wcs} and applied
during tessellation of Arc, Circle, and Line so they render correctly on
tilted planes in 3D DXF files.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Splines backed by rational NURBS (circles, conics) were tessellated as
uniform B-splines, losing the weighting that defines the curve shape.
Now BSplineCurve<Point3> is used only when weights are absent or empty;
when weight data is present a NurbsCurve<Vector4> is built from the
homogeneous control points so circles and conics render accurately.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Block INSERTs are expanded into sub-entity wires for rendering but the
OSNAP Insertion hint at the block reference origin was never generated.
Now a zero-geometry WireModel carrying the Insertion snap hint is appended
so OSNAP Insertion mode can locate the block origin.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Debug output revealed the sheet viewport has id=0 (DWG reader never sets
the field), scale=0.8965 (not ≈1.0, so the 0.02 tolerance missed it),
and center=(0.0, 0.0) — exactly at the paper-space origin.
In DWG format the overall/sheet viewport always has its center at the
origin. Content viewports are placed at their actual paper positions and
always have a non-zero center. Switching from the scale heuristic to the
center-position check makes the detection reliable regardless of what
scale value the sheet viewport happens to carry.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Remove unused `screen_delta_to_world` camera method (superseded by the
corrected pan_active_viewport formula).
Fix `is_content_viewport`: the old geometry fallback required the viewport
center to be near the origin, but DWG files never write the viewport id
field (stays 0) and the sheet viewport center is the paper centre
(e.g. 105, 148.5 mm for A4) — not the origin. This caused the sheet
viewport to be classified as a content viewport in DWG files, making it
both tessellated (border visible) and enterable via double-click.
The new heuristic uses only the scale: a sheet viewport has scale ≈ 1:1
(view_height ≈ paper height); true content viewports have deliberate
drawing scales (1:50, 1:100, …) that are far from 1.0.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
The old formula (distance × 0.001) was a fixed approximation that ignored
the paper camera's current zoom level and the viewport's paper-space size,
causing panning to feel sluggish.
New formula: model_per_pixel = (2 × paper_half_h / canvas_height) × (view_height / vp_height)
This converts screen pixels → paper-space mm → model units correctly,
making the content follow the cursor regardless of paper zoom or scale.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
When a corner grip is dragged, view_height is now updated proportionally
with the new frame height so that scale = height/view_height stays constant.
The visible model-space area grows/shrinks with the frame instead of the
content appearing to zoom.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
GripApply::Absolute adds world_offset to convert local-space coordinates
back to DXF space for model-space entities. Paper-space entities (viewports,
etc.) use sheet mm coordinates with no world_offset, but the grip drag code
was unconditionally adding scene.world_offset — causing grips to jump by the
full model-space centroid offset (potentially hundreds of km for UTM drawings).
Now world_offset is only applied when current_layout == "Model".
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>