Adds vertex-coordinate, thickness, and dimension-validity checks to
`is_entity_corrupt`. Sample files with degenerate Arcs (radius ~5e-14
and zero sweep) or 100k-vertex LwPolylines at coords ~1e244 used to
pass the previous check, then crash inside truck's parameter_division
with a 3 GB allocation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
acadrust's DWG reader occasionally desynchronises on certain files
(observed on render.dwg: 1519 of 1763 LwPolylines arrived with non-unit
normals in the 1e200+ range and 100k phantom vertices). Tessellating
those entities allocates gigabytes and produces NaN-laden wires,
freezing the UI.
Add a pre-tessellation guard that scans freshly loaded documents and
drops any entity failing a cheap sanity check: non-unit normal,
non-finite or absurd coordinate, or vertex count above 100k. Count of
dropped entities is threaded through DerivedCaches and surfaced as a
warning in the command line so the user knows the file was patched up
on the way in.
Same file in DXF form parses cleanly (0 corrupt), so this is strictly
a DWG-path workaround until the upstream parser bug is fixed.
The new examples/inspect_polyline.rs is a one-off diagnostic that dumps
LwPolyline/Polyline2D/Polyline3D fields plus a corrupt-entity count;
useful for narrowing down the acadrust bug.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Big DWG/DXF files block the UI for seconds during parse + cache build,
leaving the user wondering whether the app froze. Split the file-open
flow into pick → load and show a modal overlay during the load: file
name, size, phase label (Reading / Parsing / Building caches /
Finalizing), animated indeterminate bar, and Cancel button.
Phase is tracked via a shared AtomicU8 written by the loader thread
and read by the overlay each frame. Cancel hides the overlay and
discards the result; the parser thread runs to completion in the
background since acadrust has no interrupt hook.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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
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 <noreply@anthropic.com>
Implements a full in-app file browser window for Save As, replacing the
rfd dialog that could not expose the selected filter index on Linux.
The new chooser includes directory navigation, a scrollable file list,
filename input, and a format drop-down (DWG/DXF × 2018/2013/2010/2007/2004/2000/R14).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rfd does not expose the selected filter index, so the old DWG/DXF version
filters had no effect — every file was always saved as AC1032 (R2018).
Replace with a single custom iced Save As window that shows:
- File name text input
- Save-in folder input + Browse button (rfd folder picker)
- Format dropdown: DWG/DXF × 2018/2013/2010/2007/2004/2000/R14
- Save / Cancel buttons
The selected format is passed to save_as_version() which temporarily sets
doc.version before writing, so DwgWriter/DxfWriter emit the correct file
format. Also works in the unsaved-changes Save flow.
Closes#9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two root causes prevented paper-space viewports from loading correctly:
1. acadrust's ViewportStatusFlags::from_bits() maps bit 0 → is_on, but
the real DXF/DWG spec uses bit 15 (0x8000) for "viewport on". Post-load
fixup in io/mod.rs now corrects this for both DXF and DWG files: when
bit 0 is clear but bit 15 is set, is_on is forced true and locked is
derived from bit 14 (0x4000).
2. Some DXF exporters write id=-1 for all viewport entities instead of the
standard id=1 (sheet) / id≥2 (user) convention. The is_user_viewport_id()
helper now treats any id ≠ 0 and ≠ 1 as a user viewport, covering both
the standard id≥2 and the non-standard id=-1 cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Polyline3D tessellation now separates spline-fit curve vertices (flag 8)
from frame control points (flag 16): the curve vertices form the rendered
wire while control points are exposed as key_vertices for snap. Polylines
without spline flags are unchanged.
DXF post-load fixup now also converts AttributeEntity and AttributeDefinition
rotation from degrees to radians (group code 50 bug), matching the existing
LinearDimension fix. Attribute text rendered from DXF files now has correct
orientation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
append_linear_dimension() applied the same perp offset to both d1 and d2,
but only d2 is guaranteed to be at the definition_point level; d1 must be
projected independently onto the dimension line, otherwise non-collinear
first/second points produce a parallelogram instead of a rectangle.
Fix: compute dim_line_pos = def.dot(perp) and project each endpoint
separately so the dimension line is always parallel to axis.
Additionally, the acadrust DXF reader stores LinearDimension.rotation from
group code 50 (degrees) without converting to radians, while DWG and our
own annotation commands store it in radians. Add a post-load fixup in
load_file() that converts the rotation to radians for DXF files so
tessellation can call cos/sin uniformly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds STEPOUT / STPOUT / EXPORTSTEP command that exports all tessellated
Solid3D / Region / Body meshes to an ISO 10303-21 (STEP AP203) file.
Each triangle is encoded as a minimal ADVANCED_FACE with a PLANE surface
and CLOSED_SHELL topology — sufficient for import into all major CAD systems.
A file-save dialog picks the output path; the command line reports success or
errors. Requires at least one tessellated solid in the drawing.
Closes ROADMAP 14.10.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The PRINT command renders the current layout to a temporary PDF (reusing
the existing PDF export pipeline) and dispatches it to the OS default
printer:
- Linux/macOS: `lp` (CUPS) with `lpr` as fallback.
- Windows: ShellExecute "print" verb (compiled-in, unused on Linux).
PLOT and EXPORT still open the save-file dialog as before.
Status messages are shown in the command line during the async job.
Closes ROADMAP 1.8.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parses Wavefront OBJ files (v/vn/f, fan-triangulation, face normals
fallback) and inserts the result as a Solid3D placeholder + MeshModel
visible in the 3D viewport.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Exports all tessellated 3D mesh models in the current drawing to a
binary STL file via a save-file dialog. Normals are taken from the
MeshModel where available, otherwise computed from triangle vertices.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- src/io/plot_style.rs: PlotStyleTable and PlotStyleEntry data structures;
CTB reader (deflate/zlib decompressed text format) with ACI→RGB and
ACI→lineweight lookup; CTB writer (zlib compressed); LW_TABLE constant
- src/io/pdf_export.rs: accept optional PlotStyleTable; apply ACI color
and lineweight overrides during PDF rendering
- src/scene/wire_model.rs: add `aci: u8` field to carry ACI index
- src/scene/render.rs: render_style() now returns ACI alongside RGBA
- src/scene/mod.rs + tessellate.rs: propagate aci through wire building
- app: PlotStyleLoad/Loaded/Clear messages and handlers;
PLOTSTYLE LOAD | CLEAR | STATUS command; active_plot_style state on H7CAD
- flate2 added as dependency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add printpdf 0.9.1 dependency for native PDF generation.
- New src/io/pdf_export.rs: converts paper-space WireModels to a PDF
page (per-wire stroke color, line weight in Pt, NaN-split segments).
White/near-white colors are inverted to black for print output.
- Add PlotExport / PlotExportPath messages: opens a save-file dialog
and writes a .pdf next to the drawing file.
- Add PageSetupOpen/Close/WidthEdit/HeightEdit/Commit messages: a
centered modal panel lets the user enter paper width and height (mm);
on commit the Layout object's min/max_limits are updated in-place.
- Register PRINT / PLOT / EXPORT and PAGESETUP (PS) commands in
dispatch_command; fix MVIEW error message to English.
- Layout ribbon gains a "Plot" group with Page Setup and Export PDF
ribbon buttons.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>