8) A moved entity that a Fixed holds only in part no longer pins its free
points as hard anchors: they stay where the edit put them unless another
constraint on the entity (e.g. Vertical) moves them, so the fixed point
holds and the solve no longer fails when the two disagree.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1) VCONSTRAINT (and the new GCVERTICAL name) uses the axis constraint flow:
"Select an object or [2Points] <2Points>:", 2Points mode with the
reference's re-prompts and messages, and the same object types as
Horizontal — line, polyline segment, text, MText, ellipse axis.
2) Object mode turns the object about its first vertex; a two-point relation
across two objects slides the second object rigidly onto the axis.
3) Re-applying an axis constraint reports that the constraint already
exists; Vertical follows the UCS Y direction.
4) The constraint bar draws Vertical as the reference's axis mark, with the
point marker for a two-point relation.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7) The constraint bar draws Fix as a padlock instead of the letter F: a
white lock with a small orange point marker when one point is held, a
red lock when a whole curve or polyline segment is held.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On Windows a plot with no printer chosen went to the PDF application's
bare "print" verb — whatever that application considered its default —
and a viewer without a "printto" verb (Edge, store readers) silently
dropped the printer the dialog had chosen. The dialog also never named the
system default, and a failed printer enumeration left only "Default" and
"PDF" with the reason written to a console nobody sees.
- The default printer is looked up by name (GetDefaultPrinterW) both for
the dialog's "System default printer (…)" entry and before every job.
- A pure route decision (plan_print_route) resolves "Default" to that
name and uses the PDF application only when it registered a "printto"
verb for .pdf (AssocQueryStringW); otherwise the job goes straight to
the spooler through the existing GDI path. The report says which:
"Sent to printer: NAME (direct print | via the PDF application)".
- list_printers reports the system's own error; the plot dialog shows it
under the printer row and the command line warns once. A desktop without
CUPS is an empty list, not an error.
- PRINTERS command: default printer, listed printers (or the error) and,
on Windows, the print route — a report to paste into an issue.
- Properties… on the Default entry opens that printer's preferences sheet.
- GDI path: the driver's dmSize is kept (its private data lives behind
it), the print raster is no longer memoised for the session, and a
spooled temporary PDF is removed.
Tests: route planning (named / blank / no default / printto or not), the
PRINTERS command; the two Windows-only GDI tests pass the resolved name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1) FXCONSTRAINT (and the new GCFIX name) prompts "Select point or [Object]
<Object>:" — a pick fixes that constraint point; Enter or O asks for one
line, polyline segment, circle, arc, ellipse or spline; misses and
unsupported objects report the reference messages and re-prompt.
2) Point, block, text, MText, attribute and table insertion points are
addressable constraint points.
3) Re-applying Fixed to the same point or object reports that the constraint
already exists instead of adding a duplicate.
4) A persistent Fixed holds its pre-edit geometry through MOVE, ROTATE,
SCALE, STRETCH, grip and Properties edits: fixed points stay, free points
of a partly fixed entity follow the edit, and size retention skips fixed
entities.
5) Object mode on a polyline fixes the picked segment (natively persisted)
instead of the whole polyline; arc segments pin endpoints, center and
radius.
6) Ribbon label "Fix" with a padlock icon.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- PSETUPIN / -PSETUPIN: with no arguments a file picker offers the chosen
drawing's named page setups in the Plot dialog; `PSETUPIN <file>` opens
the same chooser on that file; `PSETUPIN <file> *` or
`PSETUPIN <file> name,name` import straight away. Same-named setups are
replaced, the import is one undo step, and the report counts both.
- The Plot dialog's page-setup list gains "Import…": the chooser shows the
source drawing's setups with a tick each, All, Import and Cancel, and
selects the first imported setup afterwards. The source is read off the
UI thread with the same reader the editor uses for its own setups
(`scene::document_page_setups`), and handles that only meant something
in the source drawing (plot view, visual style) are dropped on import.
- Options → General → Plotting: "Show the page setup for new layouts"
opens the Plot / Page Setup dialog whenever a layout is created
(persisted with the plot preferences).
Tests: the document reader, the command (all / named / unknown / missing
file / undo) against a drawing saved by the app, the chooser flow, and the
new-layout option. Nine new strings in all 21 locales.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
When a display plot style maps an ACI to a fill pattern, wire fill
triangles are re-emitted as PLOTSTYLE hatches. Those took
depth_override raw — a per-block child label for block wires and 0.0
for top-level ones — while everything else in the hatch/wipeout pass
sorts at the composed depths[insert] + label * half. The fill could
land outside its host's band and get buried under its own block's
masks (same shape as the block-text bug).
Both the display and PDF paths now travel through wire_draw_depth /
the PlotWire's composed depth, and the display cache key rides the
depth generation so a DRAWORDER edit re-ranks the fills without
needing a wire rebuild.
Unselected block text (the BS33-11 Mark/SectionMark labels) was erased by
its own block's wipeout pass and only came back through the selection
xray. Two compounding causes:
- Glyph quads rendered at the bare insert level, an exact depth tie with
every sibling fill, so the later wipeout pass won LessEqual. Wire
batches now carry the composed child rank as depth_override (the same
units the scene graph composes: depths[insert] + label * half), which
the block-text upload resolves per instance. Glyph vertices stay
neutral on purpose — baking the raw per-block label into them
double-counts and, for a negative rank, sinks the text BELOW its own
masks.
- The wipeout pipeline's depth bias (-8 quanta) was larger than the
whole within-block band: once child ranks compress into the insert's
half-band, sibling steps are ~3 quanta and a wipeout-to-text gap is
only 9-16 quanta of the 24-bit buffer. The mask only needs to break
exact ties, so the bias is now WIPEOUT_DEPTH_BIAS_QUANTA = 2.
block_text_draw_depth regression pins the contract: neutral vertices,
override carrying the rank, and a margin over the wipe that exceeds the
bias on a 600-entity scene.
Retaining a line's length added a P2PDistance constraint, whose gradient
divides by the current distance. For a zero-length line the solver got a NaN
Jacobian and its SVD fallback never returned, freezing the editor (e.g.
ECONSTRAINT on a line drawn by clicking one point twice). Hold coincident
endpoints together with per-axis differences instead.
Control-point splines read without knots are given a degree their control
points can carry (at most n - 1) and a clamped knot vector when a drawing
loads. Generating knots for fewer points than the degree underflowed during
DWG write: a panic in debug builds, an unbounded allocation in release, and
reachable from autosave. A lone control point with no knots or fit points is
purged as corrupt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A drawing saved by a commercial CAD application (tests/fixtures/plot,
provided by Panos: one 10 m line, three layouts) corrects several
assumptions of the previous commit:
- rotation is relative to the medium's own orientation: an unchanged sheet
keeps the driver's exact medium (its PDF driver lists landscape media of
its own, written with rotation 0; a system printer's portrait A3 plotted
landscape carries 90); only a newly picked sheet is written as the
catalogue's portrait medium
- the stored scale factor (DXF 147) is the ratio × 25.4 on millimetre page
setups and the plain ratio on inch ones; the "use standard scale" bit
stays clear for standard and custom scales and is set for fit-to-paper;
a standard code is kept across a paper-unit conversion ("1:1" on an
inch page setup over a millimetre paper space is 1 in = 25.4 units)
- layout plots take the same scale path as every other area, so a foreign
layout's paper-space unit survives
- "plot with plot styles" / "display plot styles" round-trip as the
dialog's checkboxes, independent of a style table being named
- layout limits place the sheet at minus its displayed margins, the way the
source application does (the printable corner is the paper-space origin);
the margin ↔ rotation mapping shared by the printable-area guide now
turns the medium's top margin into the layout's left one at 90°
The fixture round-trips through the dialog with every stored field
unchanged; picking a new sheet on it writes the canonical form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One writer (plot_settings_from_dialog) now serves both the layout's embedded
settings and named page setups, so the two can no longer drift apart:
- media are stored as the portrait sheet with the orientation in the
rotation code (0/90/180/270; upside-down adds a half turn) instead of
swapped width/height with rotation limited to 0/180
- standard scales are written by their code (1:1 … 100:1) with matching
numerator/denominator; other scales as a readable custom ratio in the
layout's own paper unit, converting from the drawing's scale-family unit
(a metre drawing plotting "1:100" stores 10 mm = 1 unit, an inch layout
stores 1 in = 2540 units); reading converts back and keeps a ratio the
scale list has no name for instead of snapping to 1:1
- the layout's paper unit and every flag the dialog does not edit survive a
round trip untouched; layout limits follow the paper-space unit
- new drawings, new layouts, CLEAR and the automation "new" op share one
default page setup (canonical A4 name, rotation 90, none_device, 1:1
layout plot) through Scene::reset_to_new_drawing
Scene gains scale_family_unit_mm, scale_ratio and a scale-name ratio parser
(ratios and architectural names). Round-trip tests cover orientation,
standard/custom/fit scales, unit conversion, named-setup parity, preserved
flags and the default layout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The viewport context menu is now built from a pure model
(ui::popup::context_menu) rendered by the overlay: while a command runs it
offers Enter / Cancel / every keyword of the command's options() with the
keyword shown as a hint, a Recent Input submenu and M2P; when idle it offers
Repeat, Recent Input, Clipboard, Undo/Redo with history labels, the edit
block (Erase/Move/Copy/Scale/Rotate/Mirror/Draw Order), Isolate, Pan/Zoom,
selection tools, Properties and Options. The default row is anchored under
the pointer and the menu is keyboard-navigable (arrows, Enter, mnemonic
letters; any other key closes it and types into the command line).
Right-click behaviour is a user preference (Options → User Preferences,
SHORTCUTMENU / SHORTCUTMENUDURATION): shortcut menu (commercial solutions default),
time-sensitive, or the previous Enter-first cycle.
LINE gains options() (Close/Undo/eXit).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Grid snap locks to SNAPUNIT instead of magnetizing; snapped 3D points keep elevation instead of flattening to z=0. New SnapTypes Vertex/EdgeMidpoint/FaceCenter/Knot/FacePerpendicular/NearestFace with their own F4 master toggle and mode set, tiers, and markers, fully independent of the 2D master. Solid B-rep corners/edge-midpoints/face-centers from mesh edges and kernel faces, spline knot points, and live perpendicular/nearest-to-face on mesh triangles merged priority-aware in move/click paths. Drafting Settings 3D Object Snap tab is fully live (was dead placeholders); Nearest-to-face off by default. TDD: behavioral LINE-to-solid tests plus engine/scene unit tests.