Commit Graph
600 Commits
Author SHA1 Message Date
Hakan SevenandClaude Opus 5.5 69a2e7c73a fix(ellipse): #1532 follow-up — one transform, in the codec
The PR's principal-axis math now lives in the codec's transform_ellipse
(8464e0a), which explode, INSERT and every other codec path share.
transform_ellipse_geometry delegates to it for the block-cache tangent,
and the entity goes back through apply_standard_entity_transform, with
MIRROR delegated to the codec's apply_mirror: the old closure reflected
only the centre and major axis, leaving mirrored arcs on the wrong side,
and the PR's version turned the normal to -Z. The mirror test now checks
the kept +Z normal and the negated parameters.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 23:04:23 +03:00
Hakan Seven df8ea089d7 Merge pull request #1532 from yztink/fix/ellipse-block-transform
fix(ellipse): accurately transform ellipse and elliptical arcs in blocks and standard transforms
2026-09-29 22:58:23 +03:00
Hakan SevenandClaude Opus 5.5 60f35e2b1d fix(color): only colour 7 swaps with the background; true colours draw as authored
Every near-white colour turned black on a light background (and near-black
white on a dark one), including true colours. A 255,255,255 solid used as a
white mask became a black block. Now only colour 7 swaps: true colours and
ACI 255 resolve a hair off pure white/black and keep their value on screen
and in plots.

Discussion #1500

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 06:16:18 +03:00
yztink a35fc949f3 fix(ellipse): accurately transform ellipse and elliptical arcs in blocks and standard transforms
- Add transform_ellipse_geometry helper in scene::view::transform to compute exact principal semi-axes, normal, ratio, and shifted arc parameters under any affine transform (negative scales, reflections, negative rotations, non-uniform scaling, and translations).
- Use transform_ellipse_geometry in block_cache::transform_tangent for TangentGeom::PlanarEllipse so GPU analytical instances and curve endpoints match true WCS positions.
- Update entities::ellipse::apply_transform to use transform_ellipse_geometry for complete scaling, rotation, mirroring, and affine transformations.
- Clean up tangent parameters in to_render for Ellipse so start_param and end_param are consistently unwrapped.
- Add comprehensive unit tests in transform.rs, block_cache.rs, and ellipse.rs verifying negative rotations, negative scales, and distant origins.
2026-09-28 16:09:41 -07:00
Hakan SevenandClaude Opus 5.5 c45f22652d fix(dimension): grip menu Above Dim Line places text by the style, not a 1-unit nudge
It moved the text a fixed drawing unit off the line and then another unit
up, wrong at any real scale. It now sets DIMTAD = Above on the dimension
and lets the automatic layout place the text.

Fixes #543

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 19:44:09 +03:00
Hakan SevenandClaude Opus 5.5 4c1ddec646 fix(obj): concave OBJ faces are triangulated, not fanned
A fan only covers convex faces; architectural n-gons filled well outside
their outline (the sample's faces covered 63% extra area).

Fixes #680

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 19:33:40 +03:00
Hakan SevenandClaude Opus 5.5 746edaa32b feat(explode): MTEXT explodes into single-line TEXT at its laid-out runs
EXPLODE left MTEXT untouched. Each laid-out run becomes a TEXT at its own
baseline origin, height, rotation and width, keeping inline colours.

Fixes #760

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 19:22:41 +03:00
Hakan SevenandClaude Opus 5.5 5ccaaad48e fix(text): Middle-justified TEXT centres vertically on half its height
Middle (72 = 4) carries a Baseline vertical code, so the baseline landed on
the alignment point and the text sat half a height too high.

Fixes #767

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 19:16:05 +03:00
Hakan SevenandClaude Opus 5.5 e9e85010d8 fix(dimension): text colour (DIMCLRT) wins over the layer colour
The synthesised dimension text copied the dimension's ByLayer colour, and
its glyphs take their colour from that entity, so the layer colour showed.

Fixes #898

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 19:10:33 +03:00
ramox81andClaude Opus 5.5 cb7860e50e DWF and DGN underlays: attach, display, snaps, frames and references
DWFATTACH / -DWFATTACH and DGNATTACH / -DGNATTACH attach a DWF / DWFx sheet
or a DGN (V7 or V8) model with the reference's prompts; ATTACH routes the
file types to them. The sheet or model is read into vector paths, drawn as a
transparent underlay raster (contrast, fade, monochrome and background
adjustment apply) and offers its geometry to object snaps. Definitions are
kept in ACAD_DWFDEFINITIONS / ACAD_DGNDEFINITIONS, the External References
palette lists and reloads them, and image textures get line-keeping mip
levels so thin underlay lines stay visible when zoomed out.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 12:53:25 +03:00
ramox81andClaude Opus 5.5 7f8f8457c7 Frames: state-following ribbon list, DWF/DGN frames, image frame encoding and profile, frame-only picking
- The Frames list shows the drawing's frame state (hide / display and plot /
  display but not plot / frames vary), follows commands, undo and document
  switches, and lists the mixed state as a disabled item.
- DWFFRAME and DGNFRAME are frame variables of their own, kept in the header,
  and FRAME sets them with the others.
- Out-of-range frame values say "Requires an integer between 0 and 2." and
  ask again; a set value reports "Regenerating model.".
- IMAGEFRAME is stored in the image variables as bits (2 is written as 3) and
  a drawing without them uses the profile value, which setting IMAGEFRAME
  updates and the settings file keeps.
- Raster images, PDF underlays and wipeouts are picked on their frame only;
  underlay snap geometry is never picked.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 10:53:53 +03:00
Hakan SevenandClaude Opus 5.5 315df5cd47 chore: pin opencadcodec 4f7bd51 (merlinnot codec fixes #56-#61)
Brings in: unchanged ACSH extrusion history and DIMASSOC records kept
byte for byte; native dynamic-action field layouts corrected; evaluation
graph expressions written as owned; evaluated block metadata copy;
source class numbers kept on same-version legacy saves; explicit block
attribute flags kept.

The dynamic-action model now names its fields after their native
meaning, so the object summaries read parameter ids, the move offsets'
distance multiplier and the lookup table's columns. The empty
PropertiesTable variant is gone; such tables stay opaque objects.

Pins opencadcodec 4f7bd51, opencadkernel 8186605, opencadgraph 048c9c5.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 07:11:40 +03:00
Hakan SevenandClaude Opus 5.5 83e1ebd44a fix(dimension): lay automatic text out from the style again (#1412)
Since the stored text point became authoritative (85619f49), new linear
and aligned dimensions drew their text at the placeholder the commands
stored (the middle of the dimension line), so DIMTAD Above/Below and the
text offset had no effect; a style or override edit left the stale point
in place too.

reset_automatic_text_position clears the point of text the user did not
place, so it is laid out from the current settings. DIMLINEAR, DIMALIGNED,
DIMBASELINE, DIMCONTINUE and QDIM call it on creation; a DIMSTYLE edit, a
dimension override row and a style change call it for the dimensions they
touch. Loaded, untouched dimensions keep their pictured position.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 22:20:16 +03:00
Hakan SevenandClaude Opus 5.5 89512c2f20 fix(text): no stroke-font tracking after big-font and fallback glyphs (#1470)
Every glyph advanced by the face's letter spacing, including CJK glyphs a
style's big font or the TrueType fallback supplies. Their advances already
carry the gap (big font) or side bearings (TrueType), so with an LFF primary
such as iso each ideograph took 1.33 heights instead of one.
Face::spacing_after(ch) gives the tracking only to glyphs the stroke font
draws itself; every layout path uses it.

The 1.8-height widths in the report were the TEXT bounds estimate counting
UTF-8 bytes; opencadcodec 1109d52 counts characters.

Pins opencadcodec 1109d52, opencadkernel 8a246b0, opencadgraph 3c4af1c.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 21:27:17 +03:00
ramox81andClaude Opus 5.5 bd17e7e0d4 CLIP on raster images and viewports, IMAGECLIP, VPCLIP, clip depth rules
- CLIP continues as IMAGECLIP on a raster image and as VPCLIP on a layout
  viewport, with the reference prompts and stored data.
- Image clip boundaries sit on pixel centres, OFF only clears the display
  flag, and an inverted boundary cuts the image.
- VPCLIP polygon (Arc/Length/Close/Undo), clipping object and Delete; the
  viewport shrinks to the boundary's exact extents, view kept.
- XCLIP Clipdepth: Remove clears only the plane asked, a front plane behind
  the back one is rejected with the reference message.
- Attached and imported images carry the reference display flags.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 10:33:49 +03:00
Hakan SevenandClaude Opus 5.5 f537aff75c feat: node graph overlay; move to opencadcodec/opencadkernel/opencadgraph
The codec and kernel repositories and crates are renamed opencadcodec and
opencadkernel. Inside OCS they are depended on under short keys, so code
reads `codec::`, `kernel::` and the new `graph::` (opencadgraph, the node
graph engine). File-format and protocol spellings stay as they were: the
ACIS product id `acadrust`, the ACADRUST_* switches and the plugin
version keys `acadrust_version` / `acadrust_source`.

A button left of MCP on the command line opens a translucent node graph
over the viewport, with a palette of object, input, math, logic, list,
text and geometry nodes added by click or drag. An object node owns
drawing entities and its rows are the Properties panel's own rows for
them: the single-object page is extracted from refresh_properties as
entity_property_sections, values use the control protocol's
property_json, and writes go through set_property_value with a property
target override, so the panel, MCP and the graph share one read/write
path. A list reaching an object row makes one entity per element. Each
graph action is one undo step; the canvas pans and zooms.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 07:34:23 +03:00
Hakan SevenandClaude Opus 5.5 56c04408d6 Merge remote-tracking branch 'origin/main'
The command driver was split into command_driver/ upstream; the PDF
underlay and XCLIP additions to the old file move with it: their
CmdResult arms into the router (mod.rs) and the block-reference
selection filter with its clip lookup into utilities.rs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 00:05:11 +03:00
Hakan Seven 0ea8599f86 Merge pull request #1476 from ramox81:codex/insert-reference-panel 2026-09-24 23:48:30 +03:00
Karim Jerbi 7052016dce refactor(kernels): extract reusable clipboard and matchprop kernels
Publishes app-free domain logic for shared use: match_special_props and PolylineMatchStyle move to entities::match_props; xdict trio usable headlessly; new match_layer, copy_to_clipboard, paste_entities and match_properties kernels over CadDocument. Handlers stay thin shells keeping undo, dirty flags, selection and command-line echo.

Adds cross-document copy, paste and property-match tests plus a headless proof driving copy, paste and match with no app instance.
2026-09-24 21:47:14 +01:00
ramox81andClaude Opus 5.5 95e2bae0d2 Insert Reference panel: one Attach, labelled underlay tools, slide-out with Edit Reference and xref fading
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 19:39:23 +03:00
ramox81andClaude Opus 5.5 3f6bdf8c59 PDF underlays: attach dialog with pages, underlay tab, layers, import settings and file import, unload on the definition
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 18:31:40 +03:00
ramox81andClaude Opus 5.5 0c50013ca7 PDF underlays: attach prompts and definitions, display adjustments and clipping, Properties, snapping, PDFCLIP and PDFIMPORT
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 16:00:12 +03:00
huanldandClaude Opus 5.5 279a87418e feat(automation): entity, block, publishing and REST operations from the fork
The operations docs/automation/API-SPEC.md (PR #1383) describes, brought
over from huaninstratech/OpenCADStudio so the specification no longer runs
ahead of the code:

- entity CRUD: entities_create, entities_delete, entities_transform,
  entities_copy_to, and `where` filters on query
- blocks and export: block_define, block_delete, a normalised wblock
- publishing: layout_create, page_setup_set, plot (per_page included)
- metadata: sysvar, xdata_set / xdata_get, file_identity
- collections: group_create, selection_set_save / load
- control plane: batch, events, view_focus, close
- the REST transport: `--http <port>`, the /api/v1 routes and their
  OpenAPI 3 description
- person-in-the-loop picks: user_select and getpoint, hosted by the GUI
  over the same REST routes, with on-screen pending signals

Taken from the fork's commits b7a7ed80, 69396b42, 64f1cf6a, c3aafc8e,
bb5a7bfa, 52317a5c, 50d293ba, b90e194f, 517c6397, 53a5c4c9, a49ac045,
37de5a46, a78b1822, 6d9aed2a, 33f522da, 5b5cafe2, 02a7e78d, 94df40dc,
fd5bc14d, 485fac61 and 2c5fc994.

Left out on purpose: 37de5a46 also removed the donation surface (the
Patreon fetch, the donation prompt, the Start-page supporters rail, the
DONATE command and its locale strings) and replaced the About dialog's call
to action; that is the fork's own product decision and stays out. The
fork's version bump and its unrelated IFC/BIM work are not part of this.

Adapted while porting: the REST server and the GUI bridge are desktop-only
and a template start is refused in the web build, so the wasm target still
compiles; the two plot tests read the PDF through the shared stream helper,
because exported streams are Flate-compressed; the benches set the new
crosshair field; comments and docs describe each operation in its own
terms rather than by another product's API names.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 13:41:07 +03:00
Karim Jerbi eff55b27f1 perf(tessellate): optimize polyline arc sampling and skip wide fills on thin polylines
Directly sample double-single coordinates with sin_cos, short-circuit
wide fill processing on thin polylines, and preallocate band capacities.

1. Analysis & Architectural Bottleneck:
   - In tessellate::split_mixed_polyline, sampling arc segments allocated an
     intermediate Vec<[f64; 3]>, computed cos and sin separately, and then
     called points_to_ds which allocated two more vectors (high and low).
   - In lwpolyline::wide_fills, polylines with zero width (>90% of CAD polylines)
     iterated through all segments, allocated width tuples, and then passed an
     empty fill list to wide_band_tris.
   - In common::tapered_band_points, vector capacities were unreserved.

2. Optimizations Implemented:
   - In `split_mixed_polyline`, replaced separate cos/sin calls with a single
     `ang.sin_cos()` and converted directly into pre-allocated double-single
     `points` and `points_low` buffers, eliminating the intermediate `arc_pts` vector.
   - In `points_to_ds`, added early exit if capacity is 0.
   - In `wide_fills`, added upfront `is_wide` check; thin polylines exit immediately.
   - In `wide_band_tris`, added immediate return for empty fills.
   - In `tapered_band_points`, reserved vector capacity `seg_count + 1` upfront.

3. Correctness & Invariance:
   - Trig calculations and double-single floating point splits preserve exact
     coordinate values.
   - Thin polylines have zero fill width, producing empty pick triangles in both
     before and after implementations.
   - Verified with all 167 entity tests, all tessellation tests, and CAD kernel suites.

4. Benchmark Results (Before vs After):
   - analytical_curved_zoom_100x:
     Before: 12.75M FPS (0.01 ms)
     After:  14.08M FPS (0.01 ms)
     Improvement: -9.4% latency (+10.4% FPS throughput)
   - scene_entity_ingestion_10k:
     Before: 1.99 ms (1.01M entities/s)
     After:  1.82 ms (1.10M entities/s)
     Improvement: -8.5% latency (+8.9% throughput)
   - spatial_interaction_index_build:
     Before: 0.77 ms (2.47M wires/s)
     After:  0.71 ms (2.68M wires/s)
     Improvement: -8.2% latency (+8.5% throughput)
   - draworder_depth_map_incremental_patch:
     Before: 0.40 µs (2.50M patches/s)
     After:  0.36 µs (2.78M patches/s)
     Improvement: -10.0% latency (+11.2% throughput)
   - wide_and_tapered_arc_tessellation:
     Before: 6.36 ms (235.8k entities/s)
     After:  5.97 ms (251.1k entities/s)
     Improvement: -6.0% latency (+6.5% throughput)
   - analytical_curved_tessellation:
     Before: 7.79 ms (359.5k entities/s)
     After:  7.38 ms (379.2k entities/s)
     Improvement: -5.2% latency (+5.5% throughput)
   - wire_partitioning_per_frame:
     Before: 0.18 ms
     After:  0.06 ms
     Improvement: -64.9% latency (3x faster)
2026-09-24 09:05:08 +01:00
Hakan Seven 0f02a74eb1 Merge origin/main 2026-09-22 23:26:44 +03:00
Hakan SevenandClaude Opus 5 41ecc0c458 Merge pull request #1423 from felixriestra:pr/python-host-model
The bundled `opencad.python` plugin drives OCS through plugin API v7: all
43 canvas entity kinds, the drawing tables, and OCS's own commands run
step by step. RustPython stays in the plugin process — the plugin crate is
outside the workspace with its own lock file, so the application's own
dependencies are unchanged.

Reconciled with the plugin command work that landed as #1425, which the
branch was written before:

- Both added `impl Drop for PluginProcessInteractiveAdapter`, which git
  merges silently into two impls that do not compile. One body now
  cancels the command and then drops it from the runner, in that order: a
  plugin waiting on a step has to be released before the runner forgets
  the command.
- `execute_command` (#1425) and `run_command` (#1423) are both routes from
  a script to the command line, and only the second was guarded. The
  SCRIPTCOMMANDS switch and the denylist are shared now, so neither route
  is the unguarded one.
- `run_command` dispatched with plugin dispatch still enabled, so a script
  naming a plugin command re-entered the plugin that was blocked waiting
  for it. It sets the suppression flag for the length of the dispatch, as
  `execute_command` does.

The denylist read the command as typed, while the dispatcher resolves
aliases: a user-defined `Q` for `QUIT` (ALIASEDIT writes those) walked
past it. It resolves the alias first.

Also: the active-command comparison ran on every message, a mouse move
included, allocating two strings for names that are already `&'static
str`; SCRIPTCOMMANDS' own messages go through the translation macros; and
`docs/.DS_Store` (now ignored) and an unrelated RTF note about constraint
commands are out of the tree.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:26:30 +03:00
Karim Jerbi 02f4ca0cf7 fix(grips): XLINE/RAY direction grip uses stretch semantics, not move
The direction handle was built with center_grip (is_midpoint), so drags
arrived as Translate, which the direction arm ignores — the grip engaged
but silently did nothing. Build it with square_grip (same marker) so the
drag arrives as Absolute and repoints the line.

Tests:
- xline_direction_grip_drag_changes_direction: press, drag, direction is +X
2026-09-22 20:41:35 +01:00
Hakan SevenandClaude Opus 5 889a19c362 Merge pull request #1447 from ramox81:codex/diameter-constraint-parity
#1447 branched from the same commit as #1443 and rewrote the radial
dimensional constraint a second time, so the two designs had to be
reconciled rather than stacked. #1447's is the one kept: it covers
DCRADIUS and DCDIAMETER through one command, places the dimension by the
direction the location was picked in rather than storing a text point,
and names the parameters `radN` / `diaN`. #1443's radial command result,
its entity builder call and its follow-up code are gone; its own
independent work stays — the ribbon's small-button grid and tool
descriptions, the magnitude reading of a negative radius, and the centre
anchor a parameter edit resizes a circle about.

The DIMCONSTRAINT default follows #1443: running DCRADIUS or DCDIAMETER
directly leaves it alone, and the Dispatch arm sets it when DIMCONSTRAINT
is what asked for the command.

The second commit's radial drawing — the dimension line broken around the
text, the elbowed leader, the centre-mark and arrowhead rules — applied to
every radius and diameter dimension, not just a constraint's, and three
layout-parity tests said the old layout was the measured one. It is now
scoped to a dimensional constraint's own dimension, as #1443 scoped its
version, and ordinary radial dimensions draw as they did.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 17:51:16 +03:00
ramox81andClaude Opus 5 368aa69f4e Radial dimensions: text on the line, a short leader when it moves out
The text of a radius or diameter constraint sits on its dimension line,
which breaks around it, and no centre mark is drawn while that line is
there. Text that no longer fits inside moves beside the circle at the end
of a short leader that leaves the rim, elbows and hooks under the text,
with the arrowheads keeping the circle. A dynamic dimension now keeps
only its text at a constant screen size; arrowheads and extension lines
keep the style's size in drawing units.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 17:11:09 +03:00
Hakan Seven de4387f9dc Merge origin/main 2026-09-22 13:47:03 +03:00
Karim Jerbi 00e102607c fix(dist): respect units settings in DIST measurement output 2026-09-22 11:42:56 +01:00
Hakan Seven 6605a71fdd Merge pull request #1443 from ramox81:codex/radius-constraint-parity 2026-09-22 13:37:57 +03:00
ramox81andClaude Fable 5.1 aab42e2aa9 DCRADIUS: reference radial dimensional constraint with a dynamic radial dimension
Select arc or circle / Dimension text / dimension line location / value or
name prompts with a radN parameter, invalid-selection, miss, duplicate and
invalid-expression messages, negative values as magnitudes, a dynamic radial
dimension on the constraints layer drawn as the reference does (mid-radius
text on the center-to-rim line, no hook, no center mark, one text grip), the
stored text position following the radius, center-anchored resizing, the
Properties title and Constraint section, DIMCONSTRAINT's Radius default,
the small-button Dimensional ribbon grid and tooltip descriptions.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-22 13:09:47 +03:00
Hakan Seven d37ce4d617 Merge pull request #1431 from ramox81:codex/angular-constraint-parity 2026-09-22 12:28:04 +03:00
Hakan Seven 4a8f8af36c Merge pull request #1432 from swit33:fix/text-fallback-empty-outline 2026-09-22 12:27:59 +03:00
ramox81andClaude Fable 5.1 b435af64cd Dynamic angular constraint: screen-size extension lines, reference grips, Properties parity
Dynamic dimensions carry DIMEXO/DIMEXE/DIMASZ overrides in text-height
ratios, a two-line angular dimension draws extension lines only beyond
its sides, a selected dynamic angle shows triangle grips at the arc ends
with squares at the arc point and text, and the constraint dimension's
Properties follow the reference: kind titles, General before Constraint,
angular-precision Value and Measurement, drawn text position, reference
row order for Fit, Primary Units and Tolerances, and text/dimension line
alignment rows reading On as the aligned state.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-22 11:58:59 +03:00
Karim Jerbi 874dd9debf perf(scene): optimize view render environment resolution and wire splitting
Eliminate major performance bottlenecks in the per-frame view render path:
- Memoize document render environment resolution using (geometry_epoch, len) keying, replacing per-viewport O(N) linear scans over document.objects.
- Index render_environments and render_settings handles in ObjectDataCache during the single build_cache pass.
- Cache resolved background image lookups in memory to eliminate repeated path.is_file() filesystem syscalls per frame.
- Add has_face3d fast-path to bypass wire splitting when no Face3D entities exist, and use FxHashSet<u64> handle indexing when present.
- Invalidate all cached structures across bump_geometry, bump_geometry_no_blocks, and bump_entities.
- Add comprehensive correctness unit tests and before/after benchmarks.

Performance impact (10k objects):
- P95 latency reduced from 341.00 µs to 173.00 µs (-49.3%)
- Throughput increased from 4,700 FPS to 6,000 FPS (+27.7%)
- Direct render environment evaluation: ~85 µs down to <50 ns (>1,700x)
2026-09-22 09:27:47 +01:00
ramox81andClaude Fable 5.1 160930b99a Angular dimension drawing: ray-based three-point frame, text beside the arc
Three-point angular dimensions take their sweep from the two rays and the
arc point (extension lines follow their own rays, straight and reflex
angles draw), dynamic angular dimensions store no text point so DIMTAD
places the text beside an unbroken arc, and dynamic dimensions carry a
DIMGAP override of a quarter text height.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-22 10:41:52 +03:00
Alexey Bagno f954c7f495 fix(text): resolve a style's font file name against installed faces
A DWG text style stores its TrueType font as a *file* name — `GOST2304_TypeA_italic.ttf`,
sometimes with a directory — which is what AutoCAD resolves. The family lives
inside the file and is usually a different string (`GOST2304 Type A`), so looking
the reference up as a family missed an installed font and fell through to the
embedded stroke fonts. Those carry no Cyrillic at all (`simplex`, `standard`,
`romans`, `iso3098` hold no U+04xx glyph), so a Russian drawing came out with
every word missing: the letters went on to the system-font fallback, which
returns nothing on macOS.

Installed faces are now indexed by file name, and a reference — a style's font
file, or an inline `\f` code, which carries either form — resolves by family
first and by file name second. An embedded stroke font still wins, so
`romans.shx` keeps rendering as it did.

`cargo test --lib face_files_resolve_to_their_family`
2026-09-22 09:39:43 +03:00
Felix Riestra b1e6d2a349 Merge remote-tracking branch 'origin/main' into plugin/host-model-api 2026-09-21 22:20:09 +02:00
Hakan Seven 697ea4984b Merge pull request #1418 from Chrisyeh1983/fix/viewport-wide-polyline-plot-width
fix: wide-polyline plot width through viewports; CJK text (big fonts, fallback size, atlas growth, MTEXT wrap/indents); compressed PDF
2026-09-21 22:49:31 +03:00
Hakan Seven 7490b2bebd Merge pull request #1415 from ramox81/codex/aligned-constraint-parity
Aligned dimensional constraint: Point & line, 2Lines, value and property parity

# Conflicts:
#	src/app/command_driver.rs
#	src/app/update/viewport.rs
#	src/entities/dimension.rs
#	src/scene/parametric_constraints.rs
2026-09-21 22:41:42 +03:00
Chris YehandClaude Opus 5 876513d009 fix(mtext): wrap between ideographs; paragraph indents and tabs in text-height units
Two layout defects that together broke every numbered note in a Chinese
drawing:

- Words were split on whitespace only, so a Chinese sentence — which has no
  spaces — was one unbreakable word. When it did not fit after "7.<tab>" the
  whole sentence dropped to the next line and still ran past the column.
  Ideographic text may break between any two characters except before a
  closing mark or after an opening one (the basic kinsoku rule); the atom
  splitter now emits those break opportunities.

- `\pxi…,l…,r…,t…;` paragraph indents and tab stops are multiples of the
  text height, and the first-line indent is relative to the left indent
  (a hanging list is `i-1.5,l1.5`). They were applied as raw drawing units,
  i.e. a fraction of a unit, so wrapped lines snapped back to the margin
  and the number/tab column collapsed. Scale them by the entity height and
  resolve the first line from the left indent.

Adds a layout test: a 40-ideograph paragraph in a 30-unit column wraps into
several lines, none wider than the column.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-21 22:02:13 +08:00
Felix RiestraandClaude Sonnet 5 6b8056cfeb Merge origin/main into plugin/host-model-api
Conflicts were additive: main's AddLayer/ModifyLayer (LayerConfig, OptHandle)
alongside this branch's v7 system-variable, transaction, selection and solid
operations. Main's variants keep their positions in the IPC enums; the v7
additions follow them. src/io/mod.rs takes main's reworded Shape-rotation note.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-21 15:12:58 +02:00
Chris YehandClaude Opus 5 ff4981ffe6 feat(text): read unifont and big-font .shx files; pair a style's big font
`shx.rs` only accepted the classic `AutoCAD-86 shapes 1.x` container, so
every modern Autodesk font (`txt.shx`, `simplex.shx`, `romans.shx`, … are
`unifont 1.0`) and every Asian big font (`chineset.shx`, `hztxt.shx`,
`bigfont.shx` — `bigfont 1.0`) was rejected and text fell back to the LFF
substitutes and TrueType fallback glyphs. Drawings authored with SHX big
fonts (the norm for Chinese / Japanese / Korean sheets) never showed their
real glyphs.

- Parse all three containers. Unifont glyphs are keyed by Unicode; big-font
  glyphs by their double-byte code from a sparse hash table of
  (code, length, offset) entries. Big fonts reference subshapes with a
  two-byte `7, 0, hi, lo`.
- `bigfont_glyph` encodes a character with encoding_rs (Big5 / GBK /
  Shift_JIS / EUC-KR, most likely first for the file name) and takes the
  first code the font has.
- `Face::WithBig` pairs a style's big font with its primary face: full-width
  characters come from the big font, everything else from the primary —
  how a STYLE with a "Big Font" behaves in AutoCAD. `resolve_text_style`
  resolves `big_font_file` like the primary (next to the drawing, then the
  user fonts folder) and rides it along in the font name.
- The missing-fonts dialog lists unresolvable big fonts too.

Unit tests cover a synthetic big font (Big5 lookup, cap-height scaling, no
aliasing of unknown codes), a synthetic unifont, and the pairing.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-21 21:01:05 +08:00
ramox81andClaude Fable 5.1 6969c19746 Aligned dimensional constraint: Point & line, 2Lines, value and property parity
DCALIGNED opens with `[Object/Point & line/2Lines] <Object>`. Point & line
asks `Specify constraint point or [Line] <Line>:` then `Select line:` (or the
line first and `Select constraint point:`), measures perpendicular to the
line from the constraint point to the line end nearest to it, and stores a
directed distance with the line as direction reference. 2Lines asks
`Select first line:` and `Select second line to make parallel:`, adds a
Parallel constraint solved with the first line pinned, then measures on the
solved geometry between the nearest ends. Unsupported line picks report the
reference's message; the same measurement again reports `The constraint
already exists on the selected objects.` and ends the command; an invalid
expression reports both reference lines and asks again.

The offered default and seeded expression carry twelve significant digits;
a typed value moves the second point (or the other object) while the first
point and its measured line stay, negative values keep their sign in the
parameter and use their magnitude, zero folds the points together, and the
dynamic dimension's origins follow every solve. The lock mark sits after the
text, a selected dynamic dimension shows triangle grips at its points and the
text square, and its Properties show the Constraint section (Name and
Expression editable) plus Text rotation.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-21 14:52:37 +03:00
ramox81andClaude Fable 5.1 aa51765a62 Dynamic dimensions: reference text format, horizontal text, lock after the text
A plain number shows as typed (d1=100), an expression under the fx: prefix
(fx: d2=d1*2); the text stays horizontal through DIMTIH/DIMTOH overrides
and the lock mark follows the text.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-21 13:57:06 +03:00
ramox81andClaude Fable 5.1 971abe64a4 Dimensional constraints: dynamic dimension persistence, lock mark, display variables, DIMCONSTRAINT
The dynamic dimension of a dimensional constraint is now linked in the
drawing file (AcDbAssocDependency + AcDbAssocDimDependencyBody on the
constraint node), reread on load, hidden by DCHIDE/DYNCONSTRAINTDISPLAY
and never plotted; it carries a lock mark before its text. New
CONSTRAINTNAMEFORMAT and DYNCONSTRAINTDISPLAY variables and the
DIMCONSTRAINT option front end. A transformed entity whose own end points
a driving dimension measures keeps only the first constraint point, so a
scaled line returns to its dimension value.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-21 12:13:36 +03:00
Hakan SevenandClaude Fable 5.1 fd2062bdec fix(insert): attribute grips follow ATTMODE 2 and annotative scale
Follow-up to the block-attribute grips picked from #1386.

- Movability no longer includes the invisible flag: an attribute ATTMODE 2
  displays is grippable, so the grip the display-aware list shows can be
  dragged. The document-less grips() still skips invisible attributes,
  since it cannot consult ATTMODE.
- The grip sits on the displayed attribute, which an annotative insert
  scales about its insertion point; Scene::apply_grip now unscales the
  dragged target the same way before the attribute stores it, so the grip
  no longer jumps to twice the drag at scale 2.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-20 21:31:54 +03:00
copilot-swe-agent[bot] 2b92fc5b09 Fix missing brace in insert attribute visibility filter
Co-authored-by: dasmatus <[email protected]>
(cherry picked from commit 6cf16d8621)
2026-09-20 21:29:15 +03:00