A path made of straight segments and circular arcs (a slot, a D shape,
a rounded rectangle, a pie) was written as one SPLINE, or as a flattened
polyline in R12. It is now one polyline whose vertices carry a bulge
(group 42) for each arc: an LWPOLYLINE in R14 and later, a POLYLINE with
VERTEX entities in R12 and R13, closed when the path is closed. Each run
of cubics on one circle becomes one arc. A path with any other curve
stays a SPLINE, and whole circles, arcs and ellipses keep their CIRCLE,
ARC and ELLIPSE entities.
- The circle test's tolerance is 5e-4 of the smaller of the radius and
the curve's extent, so a shallow curve that is not circular is no
longer written as an ARC.
- The drawing extents take each ARC's and each bulge's furthest points.
Part of #1299
A projection now counts as invertible when its determinant, or its
adjugate's determinant, is more than 1e-15 times the largest of the six
products that determinant sums. The adjugate of the adjugate is the map
times a number, so the inverse of a projection that inverts also inverts,
is stored and reads back. The adjugate's cofactors are formed with exact
products, so the inverse of that inverse gives back the original map up
to scale, within 1e-6 of each row's largest entry, and a map whose third
row is the sum of its first two is still refused.
Homography::conjugated and Node::transform_projection judged the affine
map by an absolute determinant of 1e-15, so a scale by 1e-8 left type and
symbol instances in perspective with their old projection. Both now use
Homography::affine_is_invertible, which compares the determinant with
the two products it sums at any scale of the map. An affine map whose
determinant or inverse is not finite, such as a scale by 1e200 or
1e-200, is inverted through Homography::inverse. When the direct product
underflows to a map that is not invertible, as for a projection stored
at a subnormal scale, conjugated forms it again with its powers of two
kept apart.
- crates/geom/src/projective.rs: the_inverse_of_an_invertible_map_is_invertible,
conjugating_does_not_depend_on_the_scale_of_the_affine,
conjugating_a_map_at_a_tiny_scale_gives_an_invertible_map
- crates/doc/src/node/tests.rs: a_projection_follows_the_transform_or_is_removed
covers an invertible scale by 1e-8 and a singular map at that size
With Snap to Point alone, an anchor behind the start could pull the
projected end behind it, and the measurement read 180 degrees from the
pointer's step. Such an end is now turned back onto the pointer's step,
keeping its length, as an end rounded nearer another step is.
With a Constrain Angle other than 0, the grid point a Shift-drag's end
rounds to can lie nearer another 45-degree step, and the measurement then
reported that step. A Shift-drag from (0, 0) to (5, -3) with a 30-degree
Constrain Angle and a 9 pt grid measured -15 degrees instead of 30. The
end is now turned back onto the step nearest the pointer's direction,
keeping its length.
With SCALED_COMPONENT_OFFSET, a component's offset now scales each axis
by the length of that axis's basis vector, as the outline loader does,
instead of going through the whole matrix. A rotated or skewed
component's caret no longer lands away from its drawn point.
UNSCALED_COMPONENT_OFFSET now turns the scaling off when both flags are
set.
A composite glyph whose components expand into glyphs with no points
could make the contour-point caret lookup read billions of glyphs. The
whole lookup now shares a budget of 65,536 glyph reads and gives no
caret when it runs out, so the caret falls back to dividing the advance.
On a path, vertical type turns an upright glyph about its pen, so its cell
runs from 0.12 em before the pen to 0.88 em after it without the font's
vertical metrics. The ligature caret, a click and the selection measured
the cell from the pen instead. They now take the cell where the glyph's
transform draws it, with its placement, baseline shift, Horizontal Scale
and Skew.
With Preview on, the selected type on a path follows Effect, Flip, Align
to Path and Spacing while the dialog is open. Cancel puts it back with no
history step; OK keeps the previewed values as one undo step. Preview
starts off. The public pages list no Preview for this dialog, so this is
a VectorCraft choice, recorded as such in the parity docs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to #5301. flavour_types (and clipboard.flavours) still listed PNG for art too large to render at the smallest scale, and the omission was only logged. PNG eligibility is now shared, and flavours_with_warnings returns a warning the status bar shows.
Follow-up to #5305. Stripping passwords from remembered settings made the next export of a password-protected PDF row write an unencrypted file without a word. The stripped settings now keep a non-secret passwordRequired flag, and an export refuses them until a password is given again (or security without the flag is given).
Follow-up to #5288. A dashed compound path keeps its dash pattern on the compound node and on each loop, so the dash budget is charged for every copy. A symbol's name is charged against the text budget before the symbol is kept. Running out of block work now says so instead of reporting more than 2,000,000 objects.
Follow-up to #5303. When deduplication shortens a thread ([[a, b], [b, c]] -> [[a, b], [c]]) and no frame changed, the fast path dropped [c] without clearing its threaded continuation. A thread that lost a listing now counts as changed and is flowed again.
Follow-up to #5293. draws_brushed rejected masks, symbol instances and pattern paints whose art names a brush the library doesn't have, though such a stroke draws plain. It now counts only brush names that resolve.
Follow-up to #5306. A DXF placed off the UI thread against an artboard that changed meanwhile is read again in finish(), on the UI thread, outside the automation roots captured when the read started. Pending now keeps that scope and poll runs finish inside it.