Commit graph cad-editor/Cargo.lock
Author SHA1 Message Date
Hakan Seven
6d60ef45d5 fix(hatch): wrong-way giant boundary arcs in blocks — bump acadrust
Hatches inside blocks (xref_Plan-Sade) drew some boundary arcs as their
near-full-circle complement, covering huge areas — in the pattern clip
when rendered through the INSERT, and in both pattern and boundary wires
after EXPLODE.

Root cause (acadrust 64efaf8): the stored sweep of a boundary arc is
always forward and AutoCAD encodes a wrap through 0 by writing the end
angle ABOVE 2π (5.81 → 6.64 for a 0.83 rad arc). transform_hatch
normalized angles into [0, 2π), turning such arcs into their 5.46 rad
complement on ANY insert pass-through — even a pure translation, which
is why the same hatch looked fine outside the block. The fix transforms
only the start angle and carries the stored sweep over unchanged
(invariant under rotation and mirror); RAW vs exploded edge angles are
now bit-identical on the reporting file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 01:01:56 +03:00
Hakan Seven
14b5067e25 fix(hatch): mirrored-block arcs — bump acadrust, document angle convention
Hatches inside mirrored INSERTs (x_scale = -1, e.g. the *U blocks in
xref_Plan-Sade) drew some boundary arcs swept the wrong way, covering
huge complementary regions — in the pattern clip before EXPLODE, and in
both pattern and boundary wires after (the exploded entity bakes the
broken angles).

Root cause was in acadrust's transform_hatch, not the renderer: DXF
stores CW (ccw=false) boundary-arc angles MIRRORED (verified against
AutoCAD output by endpoint continuity — mirrored interpretation gives
Δ=0.0 against adjacent edges), and the transform stored geometric angles
after flipping the direction flag. The legacy (TAU-θ) sampling flip in
arc_signed_span is exactly right for file data and stays; its comment now
records the verification so the convention isn't "fixed" away again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 00:41:16 +03:00
Hakan Seven
31cdd6632f chore: bump acadrust to current main (upstream sync)
Picks up the fork's merge of upstream acadrust (geodata decode, DXF
roundtrip newline sanitization, DWG alignment) on top of the current
table/multileader style work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 19:09:46 +03:00
Hakan Seven
e65a7a6d67 feat(styles): seed current table/multileader style from the file
Bump acadrust to pick up the new $CTABLESTYLE / $CMLEADERSTYLE header
variables, then on load seed the ribbon's active table style and the
tab's active multileader style from the document header so the ✓ marks
the style the file actually declares (DXF). Set Current writes the header
field as the round-trip source of truth, and the style-manager staging
snapshot now covers it. sync_ribbon_styles honours the active table style
instead of always falling back to the first one.

DWG still leaves these at "Standard" until acadrust parses them from the
binary header.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 19:05:07 +03:00
Hakan Seven
fb9f5bd4e5 chore(release): bump to 0.5.1
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:00:46 +03:00
Hakan Seven
7f94a9d66a chore(release): bump to 0.5.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 15:35:08 +03:00
Hakan Seven
70702d063f perf(hash): swap std HashMap/HashSet for rustc-hash FxHash
Phase 4.1. Handle / u64 keys dominate the hot maps (block_defn,
hatch / image / mesh caches, draw-depth map, viewport wire caches);
the default SipHash is wasted work on integer keys. Alias the std
types to rustc_hash::FxHashMap / FxHashSet crate-wide so every map and
set — including the cross-module draw-depth map shared between scene
and the GPU pipelines — uses the faster hasher consistently.

Mechanical: no behavioural change. Constructors moved from ::new() to
::default() (Fx variants carry no RandomState). Build + 13 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:35:53 +03:00
Hakan Seven
b466747074 chore(release): v0.4.9
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:14:47 +03:00
Hakan Seven
edc8cbc969 feat(scale): drive scales from the drawing's scale list
Read the model-space annotation scale from the standard CANNOSCALE /
CANNOSCALEVALUE header variables instead of a user-variable hack, and
populate both the status-bar scale picker and the viewport Scale
property purely from the drawing's ACAD_SCALELIST — no built-in
fallback set. Xref-derived scales (`_XREF` suffix, `name|` prefix)
are filtered out so only the host drawing's own scales appear.

Bumps the patched acadrust to the commit that adds CANNOSCALE/
CANNOSCALEVALUE read/write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 16:18:01 +03:00
Hakan Seven
8699a730bf chore(release): v0.4.8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 11:40:16 +03:00
Hakan Seven
e708f90517 fix(macos): statically link liblzma so the app launches (#56)
vtkio (via truck-meshalgo → xz2 → lzma-sys) linked the system liblzma
dynamically, baking a Homebrew path (/opt/homebrew/.../liblzma.5.dylib)
into the macOS binary. The .app then crashed on launch on any Mac
without that exact library. Enable lzma-sys's `static` feature so
liblzma is compiled from the bundled source into the binary, making it
self-contained on every platform (verified: no dynamic liblzma link).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 02:34:56 +03:00
Hakan Seven
90c9ac62c8 chore(deps): bump acadrust for DWG annotative (AcadAnnotative EED)
Picks up 5352477: STYLE/DIMSTYLE annotative now round-trips through DWG
via AcadAnnotative EED (ODA-spec encoding), matching the DXF side.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:47:04 +03:00
Hakan Seven
2c24f357e1 chore(deps): bump acadrust to standard-compliant annotative IO
Picks up bc711f0: annotative is now persisted the standard way
(AcadAnnotative XDATA for STYLE/DIMSTYLE/TABLESTYLE, native group 296 +
DWG bit for MLEADERSTYLE), superseding the earlier non-standard marker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:29:39 +03:00
Hakan Seven
94b4d536f1 fix(styles): use allocate_handle for new style records
Creating a new MLeader/Table/MLine style (and a new PlotSettings) pulled
the document's next handle without advancing the counter, so two records
created in one session collided on the same handle and the second
overwrote the first. Use allocate_handle(), which reserves and advances.

Also bumps acadrust to pick up DXF annotative-flag persistence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:00:26 +03:00
Hakan Seven
52850947d2 feat(textstyle): full Text Style editor — big/TT font, fixed height, flags, annotative
Expands the Text Style manager beyond font/width/oblique: big-font and
TrueType font fields, fixed text height, Backward / Upside-down flags, and
an Annotative toggle (applied live). Bumps acadrust for the annotative
field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:43:12 +03:00
Hakan Seven
f0b11acc88 feat(viewport): per-tile model render mode, persisted via VPORT entries
Each model-space tile now carries its own visual style instead of one
global mode shared by every pane:

- ModelTile gains a `render_mode`; the active tile renders with the live
  picker mode, inactive tiles keep their stored style, so changing one
  tile no longer changes the others. Split inherits the source style.
- SetRenderMode writes only the active tile; switching the active tile
  mirrors its style back into the tab (picker + live render).
- Persisted through the *Active VPORT entries (acadrust now round-trips
  the render mode via DXF code 281 / DWG RC 281), restored on open for
  both tiled and single-tile model layouts.
- Bump acadrust to pick up the VPORT render-mode field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 10:32:48 +03:00
Hakan Seven
b0e9270a7e chore(release): bump to 0.4.7
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 00:53:38 +03:00
Hakan Seven
b7230baae1 fix(deps): bump acadrust — keep tiled *Active viewport cameras distinct
Pull acadrust b6834f2, which stops the DWG writer from collapsing every
duplicate *Active viewport to a single zoom-extents view. Fixes tiled
model layouts all sharing one camera after save→reopen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 00:00:28 +03:00
Hakan Seven
f147e384d0 acadrust update 2026-06-01 20:09:31 +03:00
Hakan Seven
7bf9ce31ae feat(model): 3D solid modelling tab — primitives + boolean ops
Rename the Home tab to "Draw" and add a Model tab beside it with two
groups:

- Model: BOX / CYLINDER / CONE / SPHERE / WEDGE / TORUS, placed with a
  footprint + height. Each is built as a real ACIS Solid3D (acadrust
  primitive builders) plus a truck B-rep, tessellated into the shaded
  mesh pipeline, with edge wires for picking + wireframe.
- Design: UNION / SUBTRACT / INTERSECT via truck-shapeops.

A session-only Scene.model_solids cache holds each solid's truck B-rep
so the boolean tools can combine and chain them. Supersedes the old
command-line BOX/SPHERE/CYLINDER (insert::solid3d_cmds keeps EXTRUDE/
REVOLVE/SWEEP/LOFT).

Known limitations: booleans need solids created this session; curved
ACIS primitives render in-session but not after reload (the SAT
tessellator handles only planar caps); geometry assumes world_offset 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 19:27:06 +03:00
Hakan Seven
83d36e02e3 chore(release): bump to 0.4.6
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:46:16 +03:00
Hakan Seven
ac9022676f feat(mtext): editable preview with caret, blink, and new-line support
Type directly into the rendered MText preview: click to position the
caret, insert/delete, Enter for a new line, Space for a literal space,
and arrow keys to move. The caret blinks when idle.

Keep the trailing empty paragraph in the editor so the caret appears on a
fresh line immediately after Enter, before any typing. parse_mtext_paragraphs
split into a _ex variant; layout_mtext skips the blank-edge trim when
emitting glyph boxes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 13:14:35 +03:00
Hakan Seven
db6e8873f2 chore: bump version to 0.4.5
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 23:42:42 +03:00
Hakan Seven
0602ae82f8 chore: bump version to 0.4.4
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:17:20 +03:00
Hakan Seven
269e21cbfb release: v0.4.3
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:46:05 +03:00
Hakan Seven
ded1b7b158 chore(release): bump to 0.4.2
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:19:05 +03:00
Hakan Seven
b2d9660221 chore(release): bump to 0.4.1
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:48:30 +03:00
Hakan Seven
05ea31aa2a feat(commandline): autocomplete suggestions + inventory-based registry
Type-as-you-go suggestion popup above the input that filters known
command names by substring (so `LEADER` surfaces both LEADER and
MLEADER). Up / Down navigates the list, Enter dispatches the
highlighted entry, clicking a row dispatches directly. Esc on a
non-empty input clears the buffer instead of escalating to
command-cancel.

The name corpus comes from `inventory::submit!` blocks placed next
to each `CadCommand` impl rather than a hand-maintained static list.
Adding a new interactive command means dropping one `inventory::submit!`
line in its own module file — the autocomplete picks it up at the
next compile. 98 submissions seeded across 60 module files;
`command::all_registered_command_names()` flattens them at runtime.

One-shot dispatch arms in `app/commands.rs` (NEW, OPEN, SAVE, UNDO,
…) don't have a `CadCommand` impl and are therefore absent from
autocomplete by design.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:45:54 +03:00
Hakan Seven
163725ca22 chore(deps): bump to latest stable versions
Bumps bytemuck 1.14->1.25, glam 0.27->0.33, rfd 0.15->0.17,
windows-sys 0.59->0.61, ureq 2->3. ureq 3 changed the agent API
and feature flags, so update_check.rs switches to Agent::config_builder
and body_mut().read_to_string(), and the feature toggles from tls
to rustls.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 22:21:30 +03:00
Hakan Seven
ecdb0cd0a0 chore(release): bump to 0.4.0
Fix repo URLs to canonical HakanSeven12/OpenCADStudio casing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 17:32:29 +03:00
Hakan Seven
ef1f9a08d6 chore: rename H7CAD to Open CAD Studio
Joining the OpenAEC Foundation (open-aec.com). Crate/struct become
OpenCADStudio, user-facing strings use the spaced "Open CAD Studio"
form, repo URLs point to HakanSeven12/open-cad-studio. Logo (window
icon + assets/logo.svg) redrawn with OCS initials. Drop examples/
binaries — unused.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 17:16:15 +03:00
Hakan
0231d5cbfc chore(release): bump to 0.3.8
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 10:40:55 +03:00
Hakan
2790182067 fix(dependencies): update acadrust source to track main branch for recent fixes 2026-05-22 15:25:43 +03:00
Hakan
8e6491d4a8 fix(wipeout): use real clip vertices, correct image-pixel→WCS mapping
acadrust's DWG reader read the wipeout/raster-image clip boundary
points only to advance the bit cursor and then discarded them, so every
wipeout fell back to `Wipeout::new()`'s default placeholder rectangle
(`-0.5..0.5`). For files that store the real polygon mask in clip
vertices (anteen.dwg's `DIMBLOCK` style: u_vector ≈ 643k, size = (1, 1),
clip polygon ~0.0016×0.0033 in pixel space), the wipeout rendered at the
full image bbox — hundreds of thousands of units wide — instead of the
intended ~1000×2000 mask.

Pinned to the new `fix/wipeout-clip-vertices` acadrust branch (carries
the upstream parser fix). On the H7CAD side, the polygon mapping now
follows the DXF convention:

  x_off = (clip.x + size.x/2) × u_vec
  y_off = (size.y/2 − clip.y) × v_vec      (image-Y points down)

…in `wipeout_boundary_2d` (fill), `Wipeout::to_truck` (border line),
and `Wipeout::grips` (vertex handles) so all three stay in sync. The
fill path also explicitly closes the polygon loop — without it the GPU
`in_polygon` ray-cast skipped the v(n-1)→v(0) edge and the solid mask
bled far past the boundary.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 14:14:22 +03:00
Hakan Seven
c98e9ebd76 chore(release): bump to 0.3.7
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 06:57:15 +03:00
Hakan
ff31a07213 chore(release): bump to 0.3.6
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:25:00 +03:00
Hakan Seven
9527509ea2 chore(release): drop flatpak, add macOS .dmg, hide Windows console
- .github/workflows/release.yml: remove the build-flatpak job; matrix-
  add macOS (arm64 + x86_64) that builds H7CAD.app by hand, renders
  .icns from assets/logo.svg via librsvg + iconutil, and packages a
  UDZO .dmg. AppImage path updated to packaging/H7CAD.desktop.
- packaging/H7CAD.desktop: moved out of flatpak/ so the AppImage job
  doesn't depend on a Flatpak layout.
- packaging/Info.plist: macOS bundle template; __VERSION__ swapped
  for the release tag at build time.
- flatpak/: deleted (manifests, metainfo, desktop, builder cache).
- src/main.rs: `#![cfg_attr(all(windows, not(debug_assertions)),
  windows_subsystem = "windows")]` so the Windows GUI binary no
  longer spawns a console window alongside it (debug builds keep
  the console for log output).
- README: add macOS install section, document Gatekeeper / SmartScreen
  on first launch since the binaries are unsigned.

Bump to 0.3.5.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 21:13:02 +03:00
Hakan Seven
820bc3c692 chore: bump to 0.3.4 and patch acadrust to fix/hatch-boundary-handle-cap
The acadrust fix from https://github.com/hakanaktt/acadrust/pull/27
unblocks files with corrupt hatch boundary-handle counts (anteen.dwg
went from >100 s "stuck" to ~0.7 s release). Until the PR lands on
upstream/main, [patch.crates-io] points at the fork branch carrying
that commit; the comment in Cargo.toml notes the revert.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 07:02:44 +03:00
Hakan Seven
0aa026155a chore: bump to 0.3.3
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 13:45:56 +03:00
Hakan Seven
e84ae87bc5 chore: release v0.3.2 2026-05-17 20:19:39 +03:00
Hakan Seven
a0412534ae chore: release v0.3.1 2026-05-17 19:35:37 +03:00
Hakan Seven
0c10ca9dc1 chore: release v0.3.0 2026-05-17 15:50:17 +03:00
Hakan Seven
86f5ba7b62 feat: in-app update notice — checks GitHub releases on startup
Adds a one-shot update check that runs on app boot and pops up a small
"Update Available" window when the GitHub releases API reports a newer
tag than this build's `CARGO_PKG_VERSION`.

- `src/update_check.rs` — async wrapper around a blocking `ureq` GET to
  `api.github.com/repos/HakanSeven12/H7CAD/releases/latest`, returns
  `Some(version)` when a newer release exists, `None` otherwise (silent
  on network / parse failure so a missing connection never blocks
  launch).
- `H7CAD::boot` chains a `Task::perform` next to the main-window open
  so the check runs in parallel with first-paint.
- New window plumbed like the other floating panels (page setup, about,
  etc.): `update_notice_window`/`update_notice_version` state, title
  entry, `OsWindowClosed` cleanup, and a `ui::update_notice::view_window`
  modal that shows installed vs. latest version plus "Later" /
  "Open Release Page" buttons. Open routes through `open::that` to the
  releases URL and dismisses the modal.

Dependency: adds `ureq = { version = "2", default-features = false,
features = ["tls"] }` — the smallest blocking HTTP client + TLS combo
that doesn't drag in an async runtime.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 19:55:57 +03:00
Hakan Seven
de37ee04bf fix(scene): viewport auto-fit fallback + f64-precision projection
Three changes to make paper-space viewports render correctly on
UTM-scale drawings whose viewports were saved with default
view_target=(0, 0, 0) and a view_center pointing at empty WCS:

1. **Auto-fit fallback.** When the saved view's WCS rect doesn't
   overlap the IQR-bounded content cluster (`world_offset ±
   local_extent_max`), override `view_center` with `world_offset` and
   recompute `view_height` to fit the cluster into the paper viewport.
   Matches AutoCAD's silent auto-fit-on-open for stale / uninitialized
   viewports; without it those viewports rendered blank.

2. **f64 projection inner loop.** The previous f32 path computed
   `(wire_offset_rel - target_offset_rel).dot(view_right) -
   view_center` by subtracting values at ~5e6 magnitude (f32 ULP
   ~0.5 m) to land on a small paper offset. The cancellation produced
   centimetre-scale jitter on paper output even when the model was
   clean. Reconstruct the wire WCS coord, subtract the display center,
   and dot-project in f64; cast to f32 only at the final paper
   position where magnitudes are bounded by the viewport rect.

3. **examples/inspect_viewports.rs** — diagnostic that dumps every
   viewport's saved view fields (view_target, view_center, view_height
   vs paper height, custom_scale, status flags) plus drawing-level
   insertion_units and model-space extents. Used to verify that
   acadrust's DWG reader reads view_height correctly; the
   `view_height == vp.height` patterns observed on real files turn out
   to be genuine "default 1:1" file content rather than a reader bug
   (a round-trip test through DwgWriter / DwgReader survives all
   per-viewport values).

Also: switch the `acadrust` patch from `HakanSeven12/acadrust@feat/
expose-blockrecord-is-loaded` (a stale branch with the abandoned
is_loaded experiment) to `hakanaktt/acadrust@main`. Upstream main
now carries the layout paper-dimensions and mirrored-arc fixes that
this branch used to add — plus PR #20's DXF reading fixes that the
old branch was missing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 19:32:36 +03:00
Hakan Seven
68fe77c133 chore: release v0.2.9
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 13:04:58 +03:00
Hakan Seven
a997490814 chore: release v0.2.8
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 23:39:19 +03:00
Hakan
4d58a905e0 chore: release v0.2.7
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 09:46:47 +03:00
Hakan
e88a946176 feat(xref): honor BlockRecord is_loaded — skip Unloaded xrefs
When the host DWG marks an xref as Unloaded (via XREF→Unload in
AutoCAD), the user explicitly chose NOT to load that reference. We
were ignoring that and pulling the external file in anyway, which
on large drawings could push GPU memory past the device budget.

Bump the acadrust dep to the branch that exposes
`BlockRecord::is_loaded`, then short-circuit `resolve_xrefs` for
any entry with `is_loaded == Some(false)`. New `XrefStatus::Unloaded`
surfaces this in the command-line log so the user can see which
references were skipped (and can re-load them via the XREF dialog).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 11:20:11 +03:00
Hakan
2e985fdc9c chore: release v0.2.6
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 17:34:21 +03:00
Hakan Seven
2600ae1815 chore: release v0.2.5 2026-05-12 22:29:22 +03:00