Real BT/Tj text objects ride alongside the vector outlines (Tr 3,
zero visual change): runs preserved at layout time, TTF styles embedded
as allsorts subsets with ToUnicode, width-matched Tm, clip-culled.
WireModel literals moved to ..Default::default() tails.
Codec: PRs #71-#74 merged (MPOLYGON layout, multiline ATTDEF/ATTRIB DXF,
DXF MATERIAL/ACSH matrix, restorable SAT/SAB + history roots) and issues
#55 #64-#69 fixed. EntityType now boxes Surface, Extended, Table,
MultiLeader and Helix (2344 B -> 848 B per entity): construction sites
wrap in Box, the entity traits forward through Box, and the python
plugin generator converts with into(). Kernel: PR #70 (cuboid ring
winding).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Point clouds: drawn from their scans, attached, cropped and stylized.
The fork's codec patch is resolved to the upstream pins: the point cloud
records landed in opencadcodec 5ef9376, carried through opencadkernel
68eeda1 and opencadgraph e204966.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bug:
background_task joined the worker thread with .expect(...). Any panic
inside a background closure (decoding a malformed file, an unexpected
None) was re-raised on the main thread and took the whole application
down, even though the worker's failure was already contained.
Reproduce:
1. Run an operation that executes in a background worker, e.g. loading
or converting a deliberately corrupted file whose decoder panics.
2. Before: the process dies with the worker's panic message.
3. After: the command line shows "background task failed: <label> -
<panic>" and the application keeps running.
Fix:
The worker closure is wrapped in catch_unwind; a panic is converted to
Message::BackgroundTaskFailed(context, message) delivered back to the
update loop and surfaced as a command-line error. Each call site passes
a context label naming the operation. A failed thread join (thread
aborted) is handled the same way instead of expect().
Bug:
Message::TabClose carried a vector index captured when the view message
was built. Closing several tabs in one batch (Close All / Close Others
with unsaved-changes dialogs, or a queue of continuation updates) let an
earlier close shift the vector before a later TabClose(idx) was handled:
self.tabs.remove(idx) either panicked (index past the end) or closed a
different tab than the one the user confirmed.
Reproduce:
1. Open several drawings and modify each so they all prompt on close.
2. Use Close All, or close two tabs in quick succession so both messages
are handled in one batch.
3. Before: panic in remove(idx), or the wrong tab closes while the tab
the user chose stays open (or its work is lost).
4. After: the chosen tab closes; an id already closed by an earlier
message is a no-op.
Fix:
TabClose now carries the tab's stable u64 id, resolved to a vector
position when the message is handled, not when it is built;
PendingClose::Tab stores ids the same way. All construction sites pass
tab.id (a raw usize index no longer type-checks), and
DocTabCloseAll/DocTabCloseOthers build their queues from live ids at
handling time. A missing id means the tab is already gone, so the
handler returns Task::none().
- Lighting follows the view: the default source is a key light from the
upper left and a fill light from the lower right over an ambient term,
the other source one light from above; POINTCLOUDLIGHTING 1 lights the
front faces, 2 both.
- A selected or hovered point cloud shows its extents box.
- A move-gizmo arrow can be grabbed along its shaft; the grab offset is
taken on the press, so click-and-place and typed distances start from
the insertion point.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A lone unlocked point cloud selected in a 3D visual style shows a move
gizmo at its insertion point: X/Y/Z arrows and XY/YZ/ZX squares. Dragging
an arrow moves the cloud along that axis, a square moves it in that
plane; the hovered part is highlighted and each drag is one undo step.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Picking the cloud opens the Extract Section Lines from Point Cloud
dialog with the reference's settings and defaults: entire cross section
or perimeter only, maximum points to process (slider and field, with
the estimated time), output layer (Use Current or a layer), colour,
lines or 2D polylines with their width, minimum line length and connect
lines tolerance (each measurable by two points on screen), collinear
angle tolerance (0-10) and Preview result. Create extracts; with the
preview it asks [Accept/Settings/Undo] and Settings reopens the dialog.
The settings are kept for the session. Automation action pc_section.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A dockable Point Cloud Manager lists each point cloud of the drawing (only
the selected ones while any is selected) with Regions (disabled, region
data is not read), Unassigned Points and Scans, the scans named by their
file stems. Each switch shows or hides points: the cloud, its unassigned
points, all scans or one scan. The hidden set is the cloud's
OCS_POINTCLOUD_VISIBILITY extended data (scan names plus *CLOUD_OFF /
*UNASSIGNED_OFF markers, app id registered), written as one undo step and
kept on save. The drawn points skip hidden scans by their index ranges,
and the hidden set is part of the placed-cloud key. Collapse all / expand
all, row highlight and a search box that filters rows (keeping parents of
matches). POINTCLOUDMANAGERCLOSE closes it; the pc_manager_toggle
automation action flips a switch.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
POINTCLOUDATTACH opens the Attach Point Cloud dialog after the file is
chosen; its Attach button lives in the Attach Underlay list instead of a
separate Insert panel. A selected cloud brings the crop tools to the
right-edge toolbar. POINTCLOUDSTYLIZE sets the stylization with the
reference's prompts, the External References palette lists point clouds
(unload, reload, detach, path), and definitions keep the header extents.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Scans (.rcs) and projects (.rcp) are read and their points drawn as
screen-sized dots, coloured by the cloud's stylization. The cloud's
placement carries its scale and rotation; its extents and crops stay in
the scan's coordinates. A missing scan shows the extents with the saved
path. -POINTCLOUDATTACH / POINTCLOUDATTACH, POINTCLOUDCROP and the
POINTCLOUD* settings follow the reference's prompts and messages, the
Properties list is the reference's, and a locked cloud is left alone by
edits.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
While a grip drags, the edited entity is hidden from snapping and its
drag-start shape got a reference-only pass: the marker appeared on the
old edge's midpoint or corner, but the grip stayed at the raw cursor,
and the pass ran only with object snap tracking on. The reference pass
now always runs, still limited to discrete points (never nearest-style,
so the point cannot be pulled back onto the old shape) and skipping the
grip's own start point, and when no snap on the rest of the drawing wins
it places the grip too.
Fixes#1528
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Entity picks switch object snap off, but COINCIDENT (and the other
constraints that take a point) only recognise a point when the pick lands
exactly on it. Without snap there were no point markers and every pick
became the whole curve. Point-accepting entity picks now keep object snap
and hand the snapped point to the command.
Discussion #1526
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The palette installed the insert command directly and kept the previous
command's last point, so ORTHO locked the insertion point to an axis
through it. The command-start reset is now a shared helper that the
palette uses too.
Fixes#1525
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>
The STEP header timestamp used SystemTime, which panics on wasm, and the
exports wrote through std::fs, which the browser does not have.
Fixes#761
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The mask is filled with the canvas colour; plotting carried that dark
colour (or the light-to-black rule) onto the sheet.
Fixes#1072
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The reference direction, base point and locked point went through f32,
so the drawn line drifted off true parallel.
Fixes#1387
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Properties… in the Plot dialog froze the application on Windows.
`on_printer_properties` called `DocumentPropertiesW` with `DM_IN_PROMPT`
from inside the closure handed to `iced::window::run`, and iced runs that
closure synchronously on the winit event-loop thread. The driver's
property sheet wants to run its own modal message loop on that same
thread, so the two loops collide: the sheet is never created at all, the
window stops painting, and the thread spins at 100% of one core with no
way back.
Measured on Windows 11 x86-64: the pinned thread is the window's own UI
thread, and compstui.dll plus the driver's PrintConfig.dll are loaded
into the process, so execution does reach the driver's property-sheet
code and never leaves it. It reproduces with a physical printer as
readily as with Microsoft Print to PDF, so the mechanism was broken for
every printer, not only the virtual one named in the report.
The system's own printing-preferences UI is now started as a separate
process, which pumps its own messages and leaves ours free, so the
freeze is impossible by construction rather than merely unlikely. The
command that does it already existed for the case where no printer is
selected; it now serves a named printer too, and the in-process modal
path is gone. Preferences still reach the job: the sheet writes the
per-user DEVMODE that the plot path reads back through
`DocumentPropertiesW`, which was confirmed by changing the orientation
in the sheet and watching the value the plot path reads change with it.
The new test pins down that the printer name must reach `printui` as a
single argument: split across several it matches nothing and the process
exits 0 without drawing anything, which would be a failure with nothing
to show the user.
Fixes#1474
Co-Authored-By: Claude Opus 5 <[email protected]>
#1511 added an orthogonal ellipse projection and a nearest-end
arc_parameter to draw/modify/geom.rs, the latter shadowing the kernel
function of the same name. Both now live in opencadkernel 237827e and
are re-exported here, so every kernel caller gets them too.
test_coincident_line_and_arc_grip_move only printed values and asserted
nothing; removed.
Pins opencadkernel 237827e, opencadgraph fe36957.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A page shown small was drawn from its full-size raster and thin lines broke
up into dots. Once a zoom settles on another quarter-octave step, PDF, DWF
and DGN underlays are rasterised again near their size on screen (never
above the full-size raster), frames are requested until that happens, and
the adjusted-pixel memo is kept per raster size. V7 element weights no longer
widen strokes, matching V8 models.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>
- 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]>
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]>
Height and distance steps (PUSHPULL, CYLINDER, CONE, PYRAMID, BOX,
EXTRUDE) replaced the point with the cursor's screen mapping onto the
command axis, discarding an acquired 3D object snap. A genuine snap now
supplies its own coordinate along the axis, as axis grips already do.
Base steps after the first base point (BOX/WEDGE opposite corner and cube
size, CYLINDER/CONE/PYRAMID radius) read the cursor on the base plane
through that point. A base started on a raised face intersected the ray
with world XY instead, so in oblique views the footprint ran far past the
mouse.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review of #1484:
- The underlay's snap geometry became one hidden wire per segment, but
every piece took the whole page's bounding box, so each cursor move
visited every piece. Each piece now gets its own box.
- Assigning unlayered images to the last layer compared Debug strings of
every layered path and text per drawn item (quadratic, formatted anew
each time); the owners are keyed once in a map.
- The `snap` automation op used (0, 0, 0) for a missing point; it now
answers invalid_point. It also left the live snapper's base point set
to the query's; the base point is restored.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#1481 skipped the shortcut whenever any text input had focus. The command
line is focused almost always, so copied drawing objects no longer pasted
with Ctrl+V. The probe now tells the command line apart from other fields:
another field keeps Ctrl+V to itself; over the command line copied objects
start PASTECLIP and plain text is left to the input's native paste; with
nothing focused text goes to the command line as before. PASTECLIP goes
through Message::Command again, which also closes the context menus. The
tests use the codec crate name and cover the command-line case.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The PDF Underlay and External Reference ribbon tabs are gone. While only
PDF underlays are selected their tools (Display in Monochrome, Create
Clipping Boundary, Remove Clipping, Show Underlay, Enable Snap, External
References, Edit Layers, Import As Objects) sit on the right-edge toolbar,
the switches drawn as on while on; while only xrefs are selected the xref
tools do. Contrast and fade stay in Properties. Toolbar tooltips are
translated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every message that makes another document active (switching, opening,
creating or closing a tab) resyncs the contextual tab with that document's
selection, so a tab offered for one drawing no longer stays on another.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Unlayered raster images go with the PDF layer drawn last before them.
- Circular Bezier arcs import as arcs: bulged polyline segments with Join,
ARC entities without it; straight chains still join.
- Imported PNGs go to "PDF Images" next to the PDF; import blocks are
numbered imp31, imp32, ...
- Background darkness is its HSL lightness below one half.
- All chosen pages attach at the same insertion point.
- PDF geometry snaps as separate pieces: centre from the rim, intersections
and perpendiculars.
- Automation: snap query with an optional base point.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The node library leaves the overlay and becomes a dock panel (PanelId::
NodeGraph), docked on the right the first time the graph opens and movable
like any other panel; closing it closes the graph. It follows the block
palette's layout: title bar, then a search box with New / Open / Save
beside it, then the categories, of which only Objects starts open. Entries
are clicked (placed at the canvas top-left) or dragged onto the canvas.
The title bar (title, auto-collapse pin, close, drag to re-dock), the
toolbar icon button and the panel frame were copied across Properties,
Block Palette, External References and Browser; they are now
dock::title_bar, dock::tool_button and dock::frame, used by all of them.
Block Palette's two tool buttons gain tooltips, and External References'
Auto / Close tooltips are now translated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>
Converts 12 selection arms of on_prop_geom_choice_changed to the shared helper: transparency, material, tol text and dim styles, dim overrides, viewport scale, UCS, named views, loft, history, surface and table style. Miss paths no longer push no-op undo entries.
Fixes a leaked undo snapshot: changing plot style in CTB mode is a no-op but pushed an entry. Guard hoisted before the shared snapshot, with a regression test.
Left manual by design: mleader, leader, block and fallback arms, all no-selection arms, and on_prop_geom_commit, whose constraint-aware invalidation the helper cannot express.
- Pin cadcodec upstream at d290dbe (the merged underlay change) and
cadkernel at 4134ae3, which follows it; drop the fork patch, move the
plugin-API and web-worker crates and the Python plugin lock to the same
codec so one copy is built.
- "Import as block" with raster images left IMAGE entities without an
image definition: block definition now creates it like add_entity does,
through one shared helper.
- The three preview outlines (attach frame, clip boundary, import area)
stay f64 instead of casting world points to f32.
- Page size / total / PDF scale entries use the catalog's positional
placeholder; the bare {name} form failed to format in 20 locales.
- The Underlay Layers bulb is the SVG layer icon, not a text glyph.
- PDF dialogs use the shared dialog buttons and radios.
- Options opened from a PDF dialog clears its saved state on return.
- Paper-space underlay background reuses the model block handle already
resolved; dead `let _ = i` lines and a misplaced doc comment removed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>