Fixes BIM 3D solids rendering at wrong positions — the AcDs SAB blob→solid
pairing now follows handle order instead of object-stream order, so every
solid gets its own geometry and body transform. Corrects the regression that
broke 3D solids in 0.7.3 (they were correct in 0.7.2) and places wall/floor
solids that previously piled near the origin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pulls the acadrust fixes that make a saved DWG containing 3D solids open
cleanly in a strict conformance reader: the AcDsPrototype datastore section is
now built correctly (segment-header ds_version, datidx, and the handle-sorted
search index) so 3D solids keep their geometry instead of being dropped, and a
dim-style/block handle collision on read is repaired so layouts round-trip.
Validated end-to-end on two real 107- and 273-solid files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OCS models 3-D solids with truck, but extrude/boolean results carried no ACIS
body, so other CAD apps dropped them on open. Add an exact planar exporter and
run it at save time.
- scene::convert::acis_export::planar_solid_to_sat walks a truck Solid whose
faces are all planes bounded by straight edges into a vertex/face-ring mesh
and builds an exact ACIS body via acadrust's build_planar_body. Curved
faces/edges return None (left for the NURBS path). A signed-volume check
flips the winding if the shell comes out inside-out.
- OpenCADStudio::sync_truck_solids_to_acis fills in ACIS geometry for every
cached truck solid that still has none, just before a Save / Save-As, so the
written DWG/DXF carries real modeler geometry.
- Bump acadrust to 9142a50 (build_planar_body + classic-ACIS AcDs roundtrip fix).
Booleans (already cached as truck solids) now export exact geometry. Extruded
polygons will too once the EXTRUDE command caches its truck solid (a separate
change kept out of this commit because command_driver.rs holds unrelated
in-progress edits).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pulls the acadrust fix that links R2013+ 3DSOLID/REGION/BODY geometry to its
AcDs SAB blob (writes the has_ds_data flag, corrects the AcDsPrototype header,
and pairs blobs in object-stream order). DWG files saved with 3D solids now
reopen with their geometry intact in AutoCAD/BricsCAD instead of being dropped
as an empty data stream.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump acadrust to ef0e231 (region/body history handle + viewport clip
boundary now stored) and populate the rows the builders left blank:
- Solid3D / Body "Show History": derived from the history handle's
presence (there is no separate stored bool — the DWG carries only the
H 350 history link).
- Body "History": the history handle, matching how Solid3D already shows
it.
- Viewport "Clipped": Yes when the clip-boundary handle is non-NULL.
Hatch Origin X/Y and Boundary retention stay blank by design: they are
not part of the persisted AcDbHatch record in DWG or DXF (retention is a
BHATCH command setting), so there is nothing to read.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump acadrust to a46cb8b (spline knot parameterization + mtext line-space
style now stored) and populate rows the builders left blank:
Entity-local: spline Knot Parameterization + closed-spline Area (shoelace),
mtext Line space style, hatch Spacing (pattern-line offset), leader Text
offset (annotation offset), region Area + Perimeter (wire-loop approx).
Doc-dependent (resolved in app/properties.rs where the document is
reachable): insert Block Unit + Unit factor (block record units vs
INSUNITS), underlay Name + Path (definition object), leader Text style /
vertical placement / overall scale and tolerance Text style (dimension
style), multileader Max points + segment angles (mleader style).
Rows needing an annotation-scale / sheet-set subsystem or an internal
PDF/DWF layer parser are intentionally left blank.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull in this session's acadrust work — the HELIX / ACAD_TABLE read+write,
underlay reader/writer/definition, spline tolerances & tangents, etc. The new
EntityType::Helix variant breaks three exhaustive matches; add its arm to
entity_type_name, the UI-name / DXF-name maps and entity_type_key.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#249 — plugin XDATA written via write_record survived only in memory: the
acadrust DWG writer dropped ExtendedData::records on save. Bump acadrust to
e88a9a6 (records now encode to EED and decode back on read) and fix the host
side that fed it:
- ensure_app_id allocates a real APPID handle; a null handle serializes as
0 and the EED reference can't resolve, so the XDATA vanished on reopen.
- write_record / remove_record drop stale raw_dwg_eed for the target app so
an edit made after a save/reopen wins over the pre-edit bytes.
#250 — out-of-process plugins got a throwaway document_mut() snapshot, so
edits to existing entities were silently discarded and deletion wasn't
expressible at all. Add the missing mutation surface:
- UpdateEntity / RemoveEntity IPC requests + HostApi::update_entity /
remove_entity (default in-process impls, RPC overrides on the client that
invalidate the stale document cache).
- Scene::update_entity replaces the entity in place, preserving its handle
and owning block, and reseeds only its derived caches; remove reuses the
cache-coherent erase_entities (which also honours layer locks).
- document_mut() is documented as a local-only snapshot out-of-process.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull in acadrust 4ae2ceb, which fixes two R2013+ (AC1027) DWG writer
bugs that made OCS-saved files unreadable in AutoCAD/TrueView/BricsCAD:
- #182: R2013 header string stream was unlocatable because the file
wrote maintenance_version 0 (omitting the R2010+ extra RL).
- #225: 3DSOLID/REGION/BODY omitted the R2013+ revision block, corrupting
the entity stream and dropping 3D solids on load.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull in acadrust ad0471e, which corrects the entity ENC color decode
for book colors. R2007 files whose hatches carry a book color (e.g.
the santeen.dwg from issue 46) desynced on read, dropping all 270
SOLID hatch boundaries; they now load and render.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pulls the acadrust translate fix: MOVE now carries a block's attributes
and the whole MultiLeader (text/base/block-content anchors + break
points), not just the insert point / leader line. No OCS code change —
the transform path already calls translate and re-tessellates.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each row in the attribute editor now shows the attribute's prompt — the
text defined on the block's ATTDEF — falling back to the tag when the
block defines no prompt. The prompt is read from the block definition,
since attribute instances carry only tag + value.
Bumps the acadrust pin to pull the matching reader fix: its DWG object
reader was discarding the ATTDEF prompt, so every prompt came back empty.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pulls the quadratic→linear AcDs blob-extraction fix in acadrust. 3D-heavy
DWGs (and master files that xref them) that took 28s+ to parse — minutes
for a multi-discipline set — now open in well under a second each.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DWG→DXF conversion now drops references to objects that have no DXF form
(unsupported AEC/application objects dropped on conversion), so the output
opens clean instead of auditing 619 dangling handle references.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
printpdf's default = ["html"] pulled in azul-layout, rust-fontconfig,
kuchiki, xmlparser and their transitive trees (~40+ crates including
two with cdylib targets) — none of which are used by the project's
PDF export (only basic primitives like Mm, Line, Polygon, Rgb).
Also fixes a MinGW linker error (export ordinal too large: 100035)
triggered when ld.bfd tries to build a DLL for printpdf with >65535
exported symbols.
R2018 cross-version saves now open in AutoCAD with NO recovery: the
MLEADER entity tail (block labels + dir/bottom/top attach order) is
correct, so all 3 MLEADERs are accepted — the Civil3D test file opens
clean (only the unconvertible AEC objects are dropped, as expected).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Save As now defaults the version dropdown to DWG/DXF 2018 (latest)
instead of the loaded file's version; the selected version is written
as-is (removed the source-version fallback for version-locked data).
- Pin acadrust 55a2caa: allocate_handle respects header.handle_seed as a
floor, fixing the corruption where opening a file and saving it
silently overwrote existing XRECORD/DICTIONARY objects (handle reuse)
and AutoCAD refused the result.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pins acadrust 0831995 (HakanSeven12/acadrust main): cross-version DWG
writer/reader conformance so R2004->R2018 saves open in AutoCAD for
LAYER, VPORT and ATTRIB objects (22/25 previously-discarded objects in
the Civil3D test file now open clean). MLEADER cross-version still WIP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Civil3D/AEC objects (and raw MLEADER/Surface records, EED) can only be
written losslessly in their source DWG version. On save, fall back to the
source version when the chosen version is an incompatible encoding family
(acadrust CadDocument::has_version_locked_data), with a command-line
notice, across every save path (Save, Save As, save-before-close/quit)
via a shared dwg_save_version helper. Default the Save-As format dropdown
to the loaded file's version so a round-trip preserves it.
Picks up acadrust DWG-writer conformance fixes (3dbae05) so a Civil3D
R2004 drawing round-trips through OCS and opens in AutoCAD with no errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-pins acadrust to the dimension DXF round-trip fixes (rotation/text/oblique
degree<->radian units, radial/angular/ordinate group codes, ordinate X/Y bit)
and drops the OCS-side fix_dxf_dimension_rotations dimension arm, which now
lives in the acadrust DXF reader (keeping it here would double-convert).
Completes the dimension audit (Batch 5). Refs #181.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picks up acadrust 2a59d3e, which reads/writes LWPOLYLINE thickness and
extrusion as BD / 3BD instead of BT / BE. Without it, polylines carrying
a thickness or extrusion flag parsed with a garbage normal and point
count and were dropped by the corrupt-entity guard on open — e.g. ~1600
valid polylines in the PLN_Sev block of a route drawing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tracks acadrust main at 0.4.x: plotstyle/material common-entity
ordering fix plus in-flight DWG reader work. Patch comment updated
to match; drop the git patch once these land in a published 0.4 crate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Text elements previously rendered as hollow wireframe outlines and sometimes
fell back to the wrong system font due to case-sensitive exact matching. Also,
the viewport background grid drew on top of solid entities.
Case-insensitive and partial-name fallback matching (e.g., mapping "arialn"
to "Arial Narrow") is now added to `sysfont::canonical_family_name`, ensuring
text resolves to the correct installed system font.
TrueType font contours are now triangulated into solid fills (`fill_tris`)
using `lyon_tessellation` in `ttf_glyph.rs`. To prevent the GPU from misclassifying
this 2D text as a 3D mesh (which broke flat shading), text tessellation splits
the output into separate outline and fill `WireModel`s.
The background grid is extracted from `SelectionCanvas` into `GridCanvas` and
moved beneath the 3D viewport to ensure proper layering. Finally, `DepthBiasState`
is enabled on all face/fill pipelines to apply a polygon offset, perfectly
resolving Z-fighting between coplanar wireframe lines and solid faces.
Pull in acadrust 16332e5, which reads/writes the DWG SORTENTSTABLE in the
correct stream layout (sort handles inline in the data section; owner block
+ entity handles in the handle stream). Draw order set in other CAD apps —
e.g. a line sent behind a hatch — is now honoured instead of falling back to
handle order.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The web build had bit-rotted: native-only features added since it last
compiled pulled crates that don't build for wasm32-unknown-unknown.
- printpdf (PDF export / printing) → native-only target; the web build gets
stub export_pdf / print_wires. It pulls a wasm-incompatible memchr 1.0.2
via lopdf → nom_locate, and the web has no filesystem.
- getrandom 0.3 (via ahash via acadrust) → enable its wasm_js feature and add
the matching --cfg getrandom_backend rustflag in .cargo/config.toml.
- ocs_plugin_api "host" feature (out-of-process plugin runtime: interprocess,
libloading, memmap2, rkyv) → native-only target; the web gets the
dependency-free manifest/ribbon contract. The host code was already
wasm-gated; only the Cargo wiring pulled it in unconditionally.
`trunk build --release` succeeds again.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pull in acadrust 88ea9f0, which fixes the DWG VPort zoom-extents safety
net to be twist-aware. A twisted saved view on a survey-coordinate
drawing no longer has its camera flung to empty space on save/reopen
(the view_center was double-rotated about the origin).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-ups after merging the out-of-process plugin isolation work:
- Convert the out-of-process interactive adapter's `on_point` /
`on_entity_pick` to `glam::DVec3`, matching the `CadCommand` trait,
which moved to f64 pick coordinates. The branch predated that change
and no longer compiled against the trait.
- Contain plugin constructor panics in `export_plugin!`: the constructor
runs across the C ABI boundary in `ocs_plugin_register`, where an
unwinding panic is undefined behavior. Catch it and return null, which
the loader already treats as a failed registration.
- Reap killed runner processes. The spawn-timeout and disconnect paths
called `child.kill()` without `wait()`, leaving a zombie on Unix until
the host exited. Route both — and `shutdown()` — through a shared
`reap()` that kills and waits on a detached thread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A toolchain/libc shift broke the previously-locked transitive set on wasm32
(memchr 1.0.2's libc::memchr binding stopped resolving), failing the web/Pages
deploy. Re-resolve within the existing version requirements — no Cargo.toml
change needed. Native and wasm32 both build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picks up the fix that keeps a block's owned-handle list in sync with the
entities actually written, so AutoCAD no longer drops model-space geometry from
OCS-saved files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Builds on the acadrust viewport/PlotSettings round-trip fixes:
- Write the sheet viewport's view position into view_center (DCS) with
view_target at the origin, matching AutoCAD; the old view_target form shifted
the layout.
- PAGESETUP now writes paper size, rotation, origin and units onto the Layout's
embedded PlotSettings (not just a side object), and bumps geometry, so an edit
shows on the sheet immediately and survives a save.
- Draw the printable-area guide (paper inset by plot margins, rotation-aware) as
a dashed rectangle, matching AutoCAD's layout view.
- Plot/PDF export falls back to the Layout's embedded PlotSettings via
effective_plot_settings(), so a loaded file's rotation/origin/scale apply.
Bumps acadrust to pick up the viewport-status and PlotSettings round-trip fixes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picks up the acadrust transform_arc fix that rotates/reflects an arc's
start/end angles, so editing a rotated or mirrored block in place (and
rotating/scaling a standalone arc) keeps arcs intact.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Solids were missing from the entity transform dispatch, so move / rotate /
scale / mirror were silently no-ops on a 3D solid (only its wires shifted)
and a pasted solid stayed at its original location. Add a Transformable impl
for Solid3D/Region/Body/Surface (delegating to acadrust, which now composes
the move into the ACIS body placement) and register them in the dispatcher.
Also make cross-drawing paste land at the cursor: the clipboard centroid is
measured in the source drawing's offset-relative frame, so correct the paste
translation by the source/target world_offset difference (zero within one
drawing). Bumps acadrust for the solid-geometry transform fixes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump acadrust to pick up real ACIS body transforms (so moving/copying/
rotating a 3D solid relocates its geometry) and OCS-aware INSERT placement.
- body_transform: read the SAT transform record from its first 13 float
tokens instead of by raw index, which skipped the matrix because the
record leads with a book-keeping pointer — so the body placement was
silently ignored and solids never honored their stored transform.
- Insert grips: the grip lives in world space but insert_point is stored in
the block's OCS, so grip display and grip-drag now round-trip through the
OCS. A block whose extrusion normal isn't +Z no longer shows its grip in
the wrong place or drags along the wrong axes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The web build has no system-font access, so CAD text in non-Latin scripts
(Cyrillic, Greek, CJK, …) rendered as nothing — build_fallback was a hard
None on wasm (#141). Instead, ship per-script Noto subsets under web/fonts
(one alphabet per file, SIL OFL 1.1) and fetch them lazily over HTTP the
first time a drawing uses that script, then outline glyphs with ttf-parser.
- web_font: Script enum + script_of (char → script font), a per-script
store with lazy fetch, and a pending queue drained by the app loop.
- CJK is split by language (chinese/japanese/korean). Han ideographs share
code points but differ by language, so the shared block is routed by the
document's $DWGCODEPAGE (932→JP, 949→KR, GB/936→CN); kana is always
Japanese, Hangul always Korean. Re-tessellates when the language changes.
- build_fallback (wasm) outlines from the fetched subset; clear_fallback_cache
lets glyphs that missed while a font was in flight reappear on load.
- PollWebFonts subscription (web only) + WebFontLoaded message drive fetches.
- Trunk copy-dir serves web/fonts; nothing is bundled into the native binary
(desktop keeps using system fonts).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the ad-hoc `--serve` arg sniff with a clap-parsed CLI:
- positional <file> to open at startup (also the OS file-association path)
- --new, --read-only, --backend, --safe-mode/--no-gpu
- --serve/--port (headless JSON automation, unchanged behaviour)
- --export IN OUT (headless format convert via the automation load/save infra)
- --script FILE (run command lines at startup)
- --log/RUST_LOG, plus --version/--help for free
GUI-only options pass to app::boot through a OnceLock config; read-only
gates the save paths. The web build skips parsing (no args).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build pierced planar faces (a wall with a window opening) as truck faces
with inner hole boundaries: collect every face loop (outer + holes), wind
each hole opposite the outer so try_attach_plane cuts it, and let truck
triangulate. Drop the back-face cull on the solid-mesh pipelines so faces
show regardless of the import's winding (the shader already lights
two-sided). Relies on the acadrust SatLoop next_loop fix that makes hole
loops reachable. (#123)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>