A DIMENSION moved by an older AutoCAD keeps its *D block contents where
they were and the move in DXF group 12, and is drawn translated by the
insertion point. Group 12 was never read into Dimension, so the block
rendered at its pre-move position and the extents reached there too.
Read group 12 into a new Dimension::insertion_point, draw the block
translated by it, move its bounds with it in the extents, test the
block's text where it draws, and write group 12 back whenever the block
written is the one read from the file. Regenerated geometry (edits drop
the block link) sits at its definition points, so no offset is kept or
written for it.
Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
* OVERKILL: objects within the tolerance are duplicates wherever their numbers fall
OVERKILL compared objects by rounding every number to a multiple of the
tolerance. Two numbers closer than the tolerance on either side of a
rounding step round apart, so the objects were kept: at 0.01, circles at
x = 80.001 and 80.003 were merged but circles at 50.004 and 50.006 were
not. Arcs on one circle were bucketed the same way.
Duplicates are now found by shape (the JSON without its floating-point
numbers; counts and flags must match exactly) and a weighted sum of the
numbers on a grid of the tolerance, looking in the neighbouring cells too,
then compared pairwise to within the tolerance. Arcs and circles look in
the neighbouring cells of centre and radius and are grouped with a
union-find. Lines were already grouped by sorting and are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* OVERKILL: within the tolerance doesn't chain
Arcs and circles were grouped with a union-find over pairwise matches,
so A ~ B and B ~ C put A and C in one group even when A and C are
farther apart than the tolerance: a circle C was deleted for matching
only the arc between it and the kept circle A, and arcs were combined
across the chain. Each object now joins the first group whose every
member is within the tolerance of it, or starts its own.
In the duplicates pass, a followed object displaced an earlier keeper
that later objects had already matched, leaving them deleted up to twice
the tolerance from what stays. Followed objects are now looked at first,
so every deletion is within the tolerance of an object that stays.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Tyler Chiriboga <18270301+Tyler-Chiriboga@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(inquiry): AREA, PERIMETER and DISTANCE system variables, as AutoCAD sets them
AREA, DIST and MEASUREGEOM now leave AREA, PERIMETER and DISTANCE for
getvar, read-only and not saved: the area just measured (the running
total in Add and Subtract mode) with the last area's perimeter, and the
distance (the total of Multiple points). After DIST's two points
LASTPOINT stays at the first point, as measured. AREA's Object option
measures splines, closed by their chord like open polylines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address review: spline area over narrow spans, finite distances, list order
- AREA of a spline samples it span by span (Spline::tessellate_spans), so
a narrow knot span no longer drops out of the area. The spread over the
spans is one helper shared with Spline::bounds, whose boxes are
unchanged.
- DIST refuses a distance that isn't finite on all three paths and leaves
DISTANCE as it was.
- sysvars::list puts the session's values after the drawing's header, so
it shows what get returns (AREA, ORTHOMODE, LWDISPLAY...).
- LASTPOINT after DIST's Multiple points is pinned to AutoCAD 2024's
measured behaviour: the last point entered, also after Length and Undo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address review: measure every knot span of a spline in AREA
A spline with more knot spans than half the sample cap fell back to an
even grid over the domain, which can step over a narrow span and measure
the wrong area: a 100 x 100 square as a degree-1 spline, its right and
top edges two spans a millionth wide after 4,500 spans along the bottom,
measured 4,998.75.
Spread the samples over the spans at any span count: at least one
segment per span, within the cap up to MAX_SAMPLES spans and one each
past it, as Spline::length integrates every span. One evaluation per
span costs 85-285 ms on a million spans in a release build, against
32-52 s for the length AREA already takes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address review: share AREA's spline samples by how much each span bends
Past the sample cap, tessellate_spans gave each knot span one segment, so
a bent span among many straight ones was measured by its chord. Example:
a quadratic spline along the x-axis, one control point 1000 above it,
past 4,500 spans. It measured 750; the area is 1750/3.
Each span now keeps one segment. A span whose control points are
collinear is straight, so its chord is exact. tessellate's count is
shared among the spans that bend, by the cube root of a measure of their
control points' convex hull, which holds the span and its chord. The
shares are rounded on the running total, so they use the whole count
however many spans share it. The example now measures 583.33343, below
the cap and past it.
The spreading by parameter width that this replaces goes, and
span_params with it: bounds is main's code again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* DIST: a measurement refused as too large leaves LASTPOINT at the first point
Session::feed sets LASTPOINT to the second point before DIST checks the
distance, and the refusal returned before DIST put the first point back,
as it does after a measurement. It now does so before refusing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* AREA: a spline too long to measure is too large, not a perimeter of 0
Spline::length reads a length past f64's range as 0, and AREA took that
as the spline's perimeter. Spline::checked_length returns None there,
and AREA reports the perimeter too large, as it does a polyline's.
The overflow was hidden twice: in the sum, and before it in the
derivative, which read as zero speed once past f64's range. The length
integral now takes the derivative before that (Spline::velocity), so an
overflowing speed counts too. param_at_length keeps the speed it had,
and finite lengths are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Say "or" once in prompts that offer options
Twelve prompt messages ended in "or", and the command line adds "or"
before a prompt's options, so they read "or or": HELIX height, XLINE angle
and offset, BLEND, four LENGTHEN prompts, two NCOPY prompts, PEDIT and
table breaks. They now read as AutoCAD's do.
The interface catalogs are keyed by these messages: each key loses its
"or" and each translation its trailing word for "or"; where the shorter
key already had a translation, the longer row is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Say "or" once in HELIX's radius prompts; rename the Vietnamese keys
HELIX's base and top radius prompts ended in "or" before their Diameter
option too, so they read "Specify base radius or or [Diameter]". They
now read "Specify base radius or [Diameter] <1.0000>:", and their keys
lose "or" in all 17 catalogs, as the other twelve did.
The Vietnamese catalog, merged from main, gets the same renames as the
other catalogs; where the shorter key already had a translation, the
longer row goes. The unused "Specify rotation angle or" row goes from
every catalog too: RECTANG has asked "Specify rotation angle" since
#2554.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Write option prompts without "or", as AutoCAD does
AutoCAD writes " or [" only when a prompt asks for something besides its keywords ("Enter block
name or [?]"); a prompt asking for one of them has none ("Enter an option [...]", "Enter layout
option [...]", "New color [Truecolor/COlorbook]"). The 27 messages read without "or" from
AutoCAD 2024's command line are listed in NO_OR and displayed that way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Address review: the window's command line drops "or" as the prompt does
The command line in the window draws a prompt's keywords itself and
wrote " or [" after every message, so -LAYER still read "Enter an option
or [?/Make/...]" there, and questions such as AUDIT's had "or" too. Only
the prompt text (the control channel, the state JSON, the tests) had
dropped it.
Prompt::keyword_lead gives what goes before the keywords; display() and
the command line both use it, and the command line translates only
" or [". A render test reads what the command line draws, in English and
German, for -LAYER, LINE and AUDIT. Suggested in review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/array.rs:380 (run_arraypolar, `fill: f64_or(p, "angle", 360.0)`)
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
* OOPS brings back what -WBLOCK erased
-WBLOCK erases the objects it writes, and OOPS brings back what the
last ERASE or BLOCK removed; the two landed separately, so OOPS never
saw what -WBLOCK erased. -WBLOCK now erases through erase_kept, as ERASE
and BLOCK do.
As AutoCAD 2024 does (accoreconsole, the drawing's entnext order read
back): OOPS after -WBLOCK brings its objects back, each where it was and
with its handle; only the last erase counts, -WBLOCK's or ERASE's; and
-WBLOCK * erases nothing, so OOPS still brings back the erase before it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* OOPS: keep the last erase through a refused REFEDIT command; Block Editor
During REFEDIT, a command that removes an object outside the working set
is undone (refedit::after_command), but erase_kept had already replaced
what OOPS kept: the objects came back, and the erase before them was
lost. erase_kept now leaves OOPS as it was when an object it removes is
outside the working set. That covers BLOCK, -WBLOCK, ERASE and the
Delete key.
In the Block Editor, its objects keep the handles they have in the block
definition, so in_blocks found them there and OOPS brought back nothing
erased in the editor. in_blocks now skips the block open there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Polyface meshes stay one object through DXF and DWG
A polyface mesh (POLYLINE flag 64) was read as loose 3D faces. It is now
read, drawn, exploded into its 3D faces and written back as a POLYLINE.
Hidden edges aren't drawn. A mesh too large for the 16-bit groups 71-74
is saved as 3D faces.
Split from #1005.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* A polyface face ends at its first zero index
A face record with a gap ([1, 2, 0, 3]) has two corners and is dropped,
not read as a triangle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Polyface meshes: write only faces that name their vertices; ID gives their Z
The writer drops the faces the reader would drop, so no record names a
missing vertex, and the 16-bit check only needs the counts. ID and DIST
give a mesh the Z of its nearest visible edge, as they do for 3D faces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
There was no OOPS. It now brings back what the last ERASE removed (the
Delete key too), or BLOCK deleting the objects it makes a block of, as
AutoCAD 2024 does (accoreconsole, the drawing's entnext order read
back):
- Each object keeps its handle and goes back directly above the object
that was under it, or under the one that was above it when that is
gone. An erase records both neighbours (EntityStore::neighbours).
- Only the last erase counts; entdel doesn't. OOPS says nothing and is
one undo step.
- An object stays out when it is already in the drawing, when an undo
took the drawing back to before it was made, when its layer, block or
layout is gone, and, during REFEDIT, when it isn't in the working set.
REFCLOSE forgets the working copies; the Block Editor has an OOPS of
its own.
- The command's label is in the 17 interface catalogs.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Measured in AutoCAD 2024 (accoreconsole):
- N, E, S and W are taken on their own in any angle format (LINE to
@10<N goes north at AUNITS 0, 1 and 4).
- A bearing or a compass point is an angle like a number, measured from
ANGBASE in the ANGDIR sense: with ANGBASE 90 and ANGDIR 1, @10<N45dE
draws at 45 degrees and @10<N east; (angtof "N") is 0 there.
- <<< takes them from east counterclockwise; << (degrees) refuses them.
main took the letters in surveyor's units only, and read them and
bearings as absolute directions. One cardinal() now serves every angle
format, and the test that pinned the surveyor-only reading expects the
measured values. -UNITS uses the shared parser.
Also write the -UNITS tests' scripts with \n escapes again; they had
become multi-line strings.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Inside a routine, commands recorded no undo step (the routine becomes
one when it ends), so U inside a routine took back the step from before
the routine: after drawing a line D, ERASE B then U in one routine
brought B back and removed D.
As AutoCAD 2024 does (accoreconsole, the drawing read back after one
routine), U inside a routine now takes back the routine's last command,
with what the routine did after it (entdel, entmake); U again, UNDO n
and REDO go on through its commands. With none left, U takes back the
drawing's step before the routine, as before, and the routine's step
then starts from there. Once the routine ends it is still one undo step.
The routine's steps live in the session's LISP state (RoutineSteps), not
in the drawing's undo stack, so a long routine doesn't push the drawing's
earlier steps out. A command inside the routine ends what REDO could
bring back; UNDO Control One and None apply. DocState::swap_in is the
one restore step undo, redo and the routine share.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
LEADER had only its JSON form, so a script's LEADER drew nothing. This
adds the command-line command with AutoCAD 2024's prompts: the points,
Format (Spline/STraight/Arrow/None) and Undo, then annotation lines, or
the options None, Block, Copy, and Mtext and Tolerance (which come back
to the first line at the command line, as in accoreconsole).
Measured, and followed:
- A hook line, a horizontal last segment DIMASZ long, is added when the
last segment is straight and more than 15 degrees off horizontal and
text follows: 14.9 and 15 degrees keep the end, 15.1 hooks. A spline,
no annotation and a block take none.
- The text sits DIMGAP past the end on the side the leader runs to:
above it, bottom-attached, with DIMTAD on; centred on it with DIMTAD
0. Sizes are DIMSCALE times the style's, with SETVAR overrides.
- A copied text keeps its contents, height and width, is centred on its
line, and with DIMTAD on the leader ends half the text height lower.
The JSON form now draws through the same code. The drawing model has no
link from a leader to its annotation, so the two are separate objects.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* -ATTDEF at the command line: attribute modes, AFLAGS, and the text's prompts
-ATTDEF asked for the tag first. A script's mode answer ("_V", "_C",
"_P") became the tag; the attribute kept no mode; AFLAGS never changed.
The definition was made at the start point, so the height and rotation a
script gives next ran as commands. It now asks as AutoCAD 2024 does:
- "Current attribute modes:" from AFLAGS, then "Enter an option to
change [Invisible/Constant/Verify/Preset/Lock position/Annotative/
Multiple lines] <done>", each answer toggling a mode, kept in AFLAGS.
- The tag (spaces taken, upper-cased; an empty one gets "Tag cannot be
null"), the prompt and default value, or a constant attribute's value.
- "Current text style: ...", the point with Justify and Style, the
height and the rotation.
The definition takes Invisible, Constant, Verify, Preset and Lock
position from the modes; a constant attribute stays in its block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -ATTDEF: a typed height is a distance, as TEXT takes it
The height was read with str::parse, so 1'6" (or any distance TEXT
takes) was refused as "Requires a positive height." It now goes through
the shared distance parser, `number`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -ATTDEF: a wrong answer at Justify is asked again
A wrong answer at "Enter an option [Left/Center/...]", or Align or Fit
(not available here), went on to the point prompt with the justification
unchanged, so a script's next answers landed one prompt off. Only a
justification goes on to its point now; anything else is asked again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -ATTDEF test: the modes start from AFLAGS, not from the default
The other cases start from AFLAGS 16, which is also the default, so
reading the modes from the drawing went untested. This starts from 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add -ARRAY, the classic command-line array, as AutoCAD lays it out
Rectangular arrays move the copy in row r and column c by (c * column distance, r * row
distance), asking for a distance only when there is more than one row or column; polar arrays
space n items 360/n apart around a full circle and fill/(n - 1) otherwise, turning the copies or
moving them with the group 10 point of the object selected last. The copies are separate
objects; the type asked defaults to the one used last.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -ARRAY: refuse an unknown type and oversized arrays before making transforms
The JSON form errors on a type other than rectangular or polar, and checks MAXARRAY before the
copies' transforms are made; the command line bounds the columns by the rows (CodeRabbit).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Add CHANGE, changing objects by a change point or their properties as AutoCAD does
A change point moves each line's nearer end to it (level or plumb under ORTHOMODE), passes a
circle through it, and places a text, attribute definition or block reference by it when that is
the one object selected; otherwise "Change point ignored" and the object's questions follow, in
selection order. Properties is CHPROP's loop with Elev, applied as the command ends. Objects on
locked layers are left out, through selection helpers now shared with CHPROP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CHANGE: refuse a JSON call without a readable point or elevation
A `point` or `elevation` that can't be read is an error, and so is a call with neither, instead
of changing nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CHANGE: Elev on every kind AutoCAD sets it for; Aligned and Fit text; rotation default
Measured in AutoCAD 2024: Elev also sets the z of ellipses, multiline texts, solids and flat
3D polylines (a 3D polyline between heights keeps them), and of hatches, which stop being
associative ("Hatch boundary associativity removed."). Aligned text isn't asked its height or
rotation and Fit text its rotation, their two points setting them. The rotation default shows
as the drawing measures angles (ANGBASE 90 shows a text at 0 as 270.00). Shared z is compared
to rounding, and the radius and height prompts say what they need.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: ATTREQ, Preset and Verify attributes as AutoCAD asks them
ATTREQ 0 inserts blocks with their attributes' default values without asking (a session
setting, as AutoCAD keeps it in the registry). Preset attributes are never asked for, "Enter
attribute values" heads the questions, and Verify attributes are asked again after "Verify
attribute values", each with the value typed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: a click doesn't answer a Verify attribute
Only typed text or Enter answers "Verify attribute values"; anything else asks again (CodeRabbit).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
RECTANG's polyline now starts at the first corner and runs along X to
the other corner, as AutoCAD 2024 draws it; each chamfer cuts the edge
into its corner by the first distance and the edge out by the second,
and fillet arcs start on the edge into their corner (clockwise outlines
get negative bulges). RECTANG keeps its chamfer, fillet, width,
elevation, thickness and rotation for the next rectangle, lists them as
"Current rectangle modes:" and offers the rotation as "<50.50>"; chamfer
and fillet clear each other. A circumscribed POLYGON starts at the end
of the picked edge counter-clockwise from its midpoint.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
AutoCAD 2024's SCALE is a uniform 3D scale about the base point: every Z
and elevation scales about the base point's Z (the current ELEVATION for a
point given without one) and every thickness by the factor. cadcraft
scaled X and Y only. The JSON form also takes a Z with the base point.
OFFSET's copy now keeps the source's height: a line's end Zs, a circle's
or arc's centre Z, a polyline's elevation. A circle's or arc's copy has no
thickness and a polyline's keeps it, as AutoCAD makes them.
Grip scaling, ALIGN's scale option and MOCORO stay 2D: their base point is
often a grip or snapped point whose Z cadcraft doesn't keep.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add -UNITS; show due surveyor bearings as one letter
-UNITS asks for the length format and precision, the angle format and
precision, the direction of angle 0 and whether angles turn clockwise,
with AutoCAD 2024's prompts, listings, defaults and messages. As in
AutoCAD, each answer is kept as it is given, and choosing another format
resets its precision to 4. The direction is typed in the chosen angle
format and turns as ANGDIR says.
Surveyor's units show a bearing that is due north, south, east or west as
that letter ("E"), except to whole degrees ("N 90d E"), as AutoCAD's
ANGTOS does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* units: read a due bearing typed as one letter (E, N, W, S) in surveyor's units
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Refuse mirror lines whose points are closer than the geometry EPS
Found while testing crates/engine/src/cmd/modify/transform.rs:run_mirror (coincidence check `a.near(b, 1e-12)`), with crates/geom/src/mat.rs:43-47 (Mat3::mirror)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* mirror: the interactive prompt also refuses points closer than the geometry EPS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Add CHPROP, asking for properties as AutoCAD does
CHPROP selects objects, then asks "Enter property to change
[Color/LAyer/LType/ltScale/LWeight/Thickness/TRansparency]" until Enter,
applying each value through properties.set. Measured from AutoCAD 2024
through AutoLISP's command: colours 1-255, names, BYLAYER, BYBLOCK or
Truecolor; 0, 256 and 300 refused; a layer must exist; a linetype not
loaded is loaded from the standard file; a lineweight goes to the nearest
standard one with a note.
Keyword prefixes now have to reach past the keyword's last capital, so
"L" alone matches none of LAyer, LType, ltScale and LWeight, as in
AutoCAD.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CHPROP tests: transparency, and refused true colours and transparencies
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CHPROP leaves objects on locked layers out, as AutoCAD does
Each pick and the pickfirst selection lose the objects on locked layers,
followed by "1 was on a locked layer." or "N were on a locked layer.";
with none of the pickfirst selection left, CHPROP asks for objects. The
JSON chprop leaves them out too and returns {changed, locked}.
The keywords test also pins QDIM's DA and PEDIT's vertex E, which AutoCAD
2024 refuses although only one keyword starts with them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chprop: look up locked handles in a set, and always report "locked" (CodeRabbit)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* SOLID: draw 2D solids, chained as AutoCAD chains them
CADCraft had the SOLID entity but no command to draw it. As AutoCAD
2024 asks from AutoLISP: first, second, third point, then "fourth
point or <exit>" (Enter makes a triangle); further solids take the
previous one's last two corners and ask their third and fourth points
until Enter. Corners stay in the order given.
The command (alias SO) has a JSON form taking the points chained the
same way. solid_chains_its_corners_as_autocad pins seven measured
calls to 1e-9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* SOLID: offer it in the Draw menu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: X, Y and Z presets, XYZ, and the Z factor AutoCAD stores
The insertion point prompt offers X, Y and Z: the factor for that axis
alone, the others 1, and no scale prompts after the point. The X scale
prompt offers XYZ, which asks X, Y and Z in turn. A Z factor not asked
is the size of the X factor: X -1 with Y as X stored Z -1, where AutoCAD
stores +1. Basepoint picks on the block dropped at the cursor, as
AutoCAD drops it where it is being dragged (the origin in a script),
instead of at its definition position.
Each was measured in AutoCAD 2024 from AutoLISP's command and is pinned
in insert_options_match_autocad.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: store the Z factor as AutoCAD does after Scale, Z and XYZ
Measured in AutoCAD 2024: Scale -2 gives X and Y -2 and Z 2; a Z preset
of -3 gives Z 3; XYZ with X -2 and Enter at Y and Z gives Z 2; a Z typed
at XYZ's Z prompt (-4) stays as typed. XYZ followed by a corner, with
Corner or a point straight away, still asks for Z, which defaults to
the size of the corner's X factor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT: an axis preset after Scale changes that axis alone
Measured in AutoCAD 2024: Scale -3 then X 2 gives 2/-3/3; X 2 then
Scale -3 gives -3/-3/3; Scale 2 then Z -5 gives 2/2/5. Scale now sets
all three presets, so a later X, Y or Z keeps the other two.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* -INSERT test: Basepoint with the cursor away from the origin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* xtask: the test suite and clippy pass on Windows
Two Windows-only failures stopped `cargo xtask ci` before it got going on
a Windows checkout (CI runs the gate on Linux only, so neither showed):
- parity::tests::civil_dates built a SystemTime 115,740,740 days after
the epoch (year 318857). Windows' SystemTime ends in the year 30828, so
the addition panicked ("overflow when adding duration to `SystemTime`").
That case now checks `civil_from_days` on the day count, which is what
it was about, on every platform.
- stats.rs imported `walk` for a test that only exists on Unix, so the
import was unused on Windows and `clippy -D warnings` refused it. The
Unix test calls `super::walk`, as its neighbour calls `super::walk_inner`.
Checked on Windows 11 x64: `cargo test --workspace` and
`cargo clippy --workspace --all-targets -- -D warnings` both pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(engine): refresh attribute baselines after value changes
CC-046: invalidate the derived XY baseline for changed justified attribute
values, including small changes inside the writer's imported-font tolerance.
Preserve no-op placement, alignment anchors and Aligned/Fit endpoints.
Regression reproduced on current upstream; all three focused tests pass.
Full cargo xtask ci passed all seven stages on Windows (2558 passing test
executions, zero failures, one ignored). Release Trunk web build passed.
Browser interaction verification is pending user dismissal of a Windows
Security prompt; do not treat the build as a runtime pass.
Windows validation prerequisite: original upstream PR #2198 commit a2dd814.
Independent of editor/ribbon changes; reverting restores only this setter,
its regression tests and corresponding file-format parity record.
* fix(io): preserve insertion elevation when refreshing text baselines
CC-046 review follow-up to PR #2214 comment 4377706777. Regression reproduced insertion Z 9 becoming 7. Preserve group 10 Z; test DXF independent elevations and document the DWG bridge shared elevation. Full cargo xtask ci passes all seven gates. This separate commit is reversible; reverting it restores elevation loss during baseline recomputation. Existing browser UI verification predates this writer correction.
* test(engine): cover global attribute no-ops and two-point exports
CC-046 review 5653054817: verify equal-value global JSON and scripted
-ATTEDIT preserve imported placement, and Aligned/Fit DXF save/reopen
retain both placement points and justification.
Validation: cargo xtask ci passed all seven gates on this branch;
git diff --check passed. Test-only follow-up, no application change.
Depends on CC-046 and unchanged Windows prerequisite #2198.
Revert this commit independently to remove only these assertions.
Runtime evidence remains separately recorded for the production commits.
---------
Co-authored-by: 2ez4gcx <108074836+2ez4gcx@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Dimensions: fill in the measurement when one is created (#2421)
A dimension made in the session kept measurement 0.0 until it was saved and reopened.
add_dim now sets it with the geometry call the DXF/DWG writer uses for group 42.
Block names are still assigned at save time. Test: a_new_dimension_reports_its_measurement.
* Parity checklist: regenerated after merging main
* Dimensions: a jogged radius dimension stores its radius as the measurement (#2421)
draw_jogged_radius set the text but not DimGeometry.measurement, so DIMJOGGED dimensions
kept measurement 0 (and the DXF/DWG group 42 was 0). It now sets the radius.
Test: jogged_radius asserts the stored measurement.
* Parity checklist: regenerated after merging main
* Dimensions: fill in a new dimension's text position when it is created (#2421)
A dimension made in the session kept text_mid (0,0) until it was saved and reopened.
add_dim now sets it from the same dimension_geometry result as the measurement, the
position the writer puts in group 11, unless the user placed the text.
Test: a_new_dimension_reports_its_text_position.
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* fix: keep WIPEOUT closure coherent across grips and outlines
Treat WIPEOUT as a closed polygon with an optional exact terminal closure marker, not as an open polyline. Centralize logical vertices, explicit outlines and closure-preserving vertex edits in the document type. Reuse this contract in grips, geometric primitives, rendering and DXF export without changing the stored schema or writer closure convention.
Add six-version DXF ASCII/binary and DWG regressions for implicit/explicit closure, both windings, all corners, API/interactive edits, undo/redo and repeated saves. Keep open/closed polylines and their coincident endpoints distinct. Cover multiple hot grips, hostile inputs and equivalent mask/frame output.
Validation: cargo xtask ci, all seven stages passed (2571 tests passed, one pre-existing skip). Two unrelated network tests failed transiently in earlier runs; each passed in isolation and the complete final run passed without exclusions. Direct and reopened grip edits produce byte-identical CLI PNG output.
Fixes#2256; related test-only matrix PR #2237 and tracker #2238 B3.
* fix(doc): keep coincident WIPEOUT endpoints separately editable
When an edit makes the endpoints of an implicit boundary coincide, add a separate closing marker rather than reclassifying the edited corner as that marker. Retain the logical vertex count and allow either coincident corner to move independently afterwards.
The document regression fails before the fix. Add API/interactive coverage for both endpoint directions and both closure forms, undo/redo, and subsequent separate edits across all six DXF/DWG versions including binary DXF and save-after-edit. Update the documented editing contract.
Validation: cargo xtask ci passed all seven stages; 2573 tests passed, one pre-existing skip.
Addresses the coincident-endpoint review on PR #2284; related #2256.
---------
Co-authored-by: cloudj <jonbahnes@gmail.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* PEDIT Multiple at the command line (#2182)
`M` at "Select polyline" answered that Multiple was only available through the JSON form. It now
works as in AutoCAD: select objects (polylines, lines and arcs), turn the lines and arcs into
polylines on Yes (left out on No), then each option applies to all of them: Close, Open, Width,
Fit, Spline, Decurve, Ltype gen and Reverse. Join joins the selected objects with each other,
ends within a fuzz distance, and reports how many it added. Undo takes the last option back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Geometry parity status line for PEDIT Multiple
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* PEDIT Multiple: objects selected first, and Decurve after Fit or Spline
Several objects selected before PEDIT go straight into Multiple, as in AutoCAD, and M keeps a
selection made first. Decurve gives back each polyline's vertices from before its first Fit
or Spline, as single-polyline PEDIT does; a Join drops that record for the joined polylines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* PEDIT Multiple: the Decurve record follows Undo and survives a Join that joins nothing
Each Undo step keeps the record of the vertices from before Fit or Spline, so Fit, Join, Undo,
Decurve gives them back; a Join drops the record only for a polyline that took on segments.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* PEDIT: Yes/No asked again on another answer; Decurve keeps a later Width
The convert questions (single and Multiple) take Y/Yes, N/No or Enter and ask again for any
other answer instead of treating it as Yes. Width clears the per-vertex widths of the vertices
kept for Decurve too, so Decurve after Fit or Spline and Width keeps the new width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
AREA's next-point prompt and DIST's Multiple points prompt offered Arc,
and MEASUREGEOM's Distance, Area and Volume options ask the same
prompts, but Arc printed "Arc: not available yet". Arc now turns on arc
mode with PLINE's arc options (Angle, CEnter, CLose, Direction, Line,
Radius, Second pt, Undo; CEnter takes an end point, Angle or chord
Length), and the arcs count in the distance, area, perimeter and
volume. A point in arc mode ends an arc tangent to the
last segment, Length after an arc continues along its end tangent, and
Undo removes the last arc. CLose ends with an arc back to the first
point. A point straight behind the last segment is refused with
"Invalid arc endpoint.".
In a DIST measured through one viewport, an arc's computed end, a typed
radius and a typed chord length are in the viewport's model units, as
Length's distance is.
LAYOUT SAveas printed "LAYOUT SAveas is not available yet." It now asks
for the layout (the current one by default) and the template file
(<layout>.dwt beside the drawing by default), and writes the layout as a
template: its page setup and paper space objects, viewports included, no
model space objects and no other layout. Named objects nothing in it uses
are left out, as PURGE All removes them. Layers the layout's viewports
freeze or recolor are kept, with those settings. The open drawing is not
changed.
The JSON form is layout.saveas {name?, path}, also reached as LAYOUT
{option: saveas}. A path without an extension gets .dwt. The command
also writes .dwg and .dxf paths and refuses other file types.
-VPORTS saved, restored and deleted named model space viewport
configurations, and MVIEW Restore placed one in a layout, but View >
Viewports > Named Viewports... had no command. The new command
vports.named runs from the menu item. Typed or from the menu it opens
the Named Viewports dialog: the saved configurations, a preview of the
selected one's tiles, and in the Model tab the name of the configuration
whose tiles are where the Model tab's are, else *Active. Restore shows
the configuration in the Model tab, and in a layout it starts MVIEW
Restore with the name, which asks for the corners. Delete deletes the
saved configuration. The JSON form takes {name?, delete?, p1?, p2?,
layout?}, and without a name it returns the configurations and the
current one.
Catalog rows for the new menu label are added in all 15 languages. In
docs/gaps.md, U11 is narrowed, and F15, U11 and F21 no longer list MVIEW
Restore (#633) or PURGE of multiline styles, which are on main.
docs/parity-checklist.md is regenerated with cargo xtask parity.
AREA reported an area or perimeter past f64's range as "Area = 0" (the
JSON form returned `"area": null`), and Add area or Subtract area could
push the running total past it, after which every total read
"Total area = 0". In MEASUREGEOM's Volume option, such an area waited
for a height that could never give a volume, so every later area in
Add or Subtract mode waited behind it.
`area` now returns "the area is too large" or "the perimeter is too
large". Typed, AREA echoes the same message instead of the result, and
an area that would carry the total past f64's range echoes "The total
area is too large." and leaves the total as it was. The Volume option
echoes "The area is too large." and does not ask for a height for that
area.
CECOLOR now reads "BYLAYER", "BYBLOCK", the index as text ("1" after
"red") or "RGB:r,g,b" for a true colour, from getvar, LISP and the
SETVAR ? list, where it was the ACI number (256, 0, 1, or the nearest
index of a true colour). The header still keeps the index and
CECOLOR_RGB, so DXF output and new objects are unchanged.
SETVAR CECOLOR takes "RGB:r,g,b" too, so a value saved with getvar
can be set back, true colour included.
No command changed an existing block's description; it could only be
given when the block was made or redefined (BLOCK, -BLOCK, entmake).
blocks.description (Modify > Object > Block Description...) changes
it: the block is the one the Block Editor edits, else the selected
reference's, else a name typed or a reference picked. In the Block
Editor, Properties with nothing selected shows the block's name and an
editable Description; BSAVE saves the new description with the block,
BCLOSE without saving drops it, and BSAVEAS gives it to the new block
only. A description is one line of up to 255 characters, and BLOCK and
-BLOCK now refuse one that is longer or has a line break.
Catalog rows for the new menu label are added in all 15 languages, and
docs/parity-checklist.md is regenerated with cargo xtask parity.