mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-06 20:02:16 +00:00
stack/render-11087
1423 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8829c1c3c5 | Render: restore saved shots, progressive images and exports | ||
|
|
a137f2d459 | Sketch Trim: keep the driving distance when trimming a line offset first (#11442) | ||
|
|
abeb232f17 |
Sketch Mirror: use an origin axis that is not in the sketch plane (#8201) (#12091)
* claim: #8201 * Sketch Mirror: use an origin axis that is not in the sketch plane (#8201) A sketch on a part face does not hold the world X, Y or Z axis, so Mirror refused the pick. It now mirrors about the axis's projection into the sketch plane and keeps that line linked as fixed reference geometry. An axis perpendicular to the plane stays refused because it has no line in the plane. The sketch's own X and Y axes keep working as before. |
||
|
|
09bb8aaaf5 |
Revolve: an axis origin written as an expression is no longer read as zero (#10252)
* fix: Revolve axis origin takes expressions instead of silently zero - AxisRef::Line origin is a PointExpr evaluated with parameter values in the design unit (format note in pending) - An unreadable origin or dir is a BadParams error instead of (0, 0, 0) - Edit Feature keeps the saved expressions of an untouched origin or dir, for solid and surface revolves, in moved components too - Face role names stay stable with a parameter-driven axis * chore: Re-run PR checks after the description fix * fix: Edit Feature of a revolve maps nothing where nothing is placed - unplaced designs skip world_state and the pick table, as before the merge - the untouched-edit test checks that OK applied the edit (CodeRabbit) --------- Co-authored-by: P'tite Tête <asso@ptitetete.com> |
||
|
|
c5d3dabd1b |
Split Body: the tool face follows a parameter change (#11674) (#11699)
The tool face of Split Body is now a face pick: it is named when it is picked and found again by that name, as other face picks are, so a split by a rail's face follows the rail when a parameter moves it. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
92171bd79b |
Hole: a hole on a face that another part touches drills its own part, not the other one (#12066) (#12067)
* claim: #12066 * Hole: a hole on a face that another part touches drills its own part (#12066) A hole placed by position with no direction drills against the outward normal of the face at the point. That face was looked for on every body, so where another part touched the face at the hole, the part made first won. The hole then drilled away from the part `targets` named and cut only the tool's run-in pocket into it, without an error. A hole that names its bodies now goes by their faces wherever one of them passes through its position, when it is made (hole_direction_at) and when a design is evaluated (hole_dir_into_face). Saved holes whose direction leaves their own body's face there are mirrored into it, as format 18 does for a thin plate's far side; the pending format note records it. A hole whose bodies have no face at its position (placed on another part's face to drill the part behind it) goes by every body's faces, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVKpSUSGYjbrBhfZGjqZEE --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3c1074cfc6 |
Timeline: moving a construction axis now updates the features that use it (#9544) (#9545)
* Evaluation: a construction axis moved past a feature makes it evaluate again (#9544) The state digest in a feature's cache key left out the construction geometry before it, and the context digest hashes construction features without their order. A feature started from the same key with or without the axis before it, so after a move it kept its old result, and a cached state restored whole brought back the construction list it was made with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Evaluation: say plainly what an empty construction list hashes (#9544) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
4678a04827 |
Agents and scripts: the contact commands describe their exact parameters and reply (#11949) (#11950)
* claim: #11949 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contact sets: input and output schemas for the seven contact commands (#11949) describe_command now gives the exact parameters and reply of contact.enable_sets, enable_all, disable_all, create, edit, list and check, and the warn and strict parameter checks use them. The handlers read their parameters from the raw JSON, so the contracts in schema/motion.rs read each key as its handler does, with its message: `occurrences` (OccurrenceKeys) and `set` are required in the schemas but left to the handlers' messages in the types, through a small `require` transform. The replies are built from typed values instead of json! literals, with the same JSON; the listed sets mirror the doc crate's ContactSet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
aee947f0f9 |
Sketch: hovering over a large sketch no longer slows down (#9614)
* claim: Sketch: keep profile outlines and trim/extend cuts between mouse moves * Sketch: keep profile outlines and trim/extend cuts between mouse moves Hovering a large sketch sampled every profile's loops into polylines for each point asked, and Trim/Extend intersected the hovered curve with every other curve on every mouse move. - Loop2::contains rejects points clearly outside a box from the loop's end and control points before sampling; Region2::outline samples the loops once (RegionOutline). Profile keeps both in OnceLocks and answers Profile::contains from them (viewport pick, profile_at_point, profile selection by points). Answers are unchanged: the box margin covers rounding, and non-finite values or negative conic weights skip the box. - sketch_modify splits the cuts on a curve (TrimHover) from choosing the piece around the cursor. The UI keeps one per sketch state and curve, and Extend's preview per sketch state, curve and growing end (afresh when the sketch has an infinite line). Plate with 400 circles (801 profiles), release, per mouse move: UI frame 5.19 -> 1.11 ms, with Trim 9.45 -> 1.50 ms; 30 lines x 30 splines: Trim piece 6.10 -> 0.0002 ms. Equivalence tests compare with the old answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: keep the profile outline helpers in the sketch crate The outer loop's box, the clearly-outside test and the outline sampled once move from geom into crates/sketch/src/profiles.rs as private items built from geom's public types, so the PR leaves crates/geom untouched. Profile::contains answers exactly as before; the geom test moves to the sketch profile tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
155387bac1 |
Sketch Trim: a cut on a shape's centre ends the piece there, with no second point (#12101) (#12103)
* Sketch Trim: a cut on a shape's centre ends the piece there, with no second point Trimming half of a center rectangle's diagonal left two points at the centre. Trim dropped the diagonal's Midpoint constraint and ended the kept half on a new point held only on the other diagonal, so the old centre was free and the new end slid along the other diagonal. Dragging a corner pulled them apart. A cut that lands on a point held at the middle of the trimmed line or of the cutter now ends the kept piece on that point. When the trimmed line held it, the Midpoint moves to the cutter if the point is the cutter's middle too (a rectangle's diagonals bisect each other), and otherwise the point is held on the cutter as a new end would be. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch Trim: weld the cut end before a parallel distance moves onto it A distance between parallel lines that measured from the trimmed line's end moves to the kept piece's start. When that start is a cut welded to a centre point, the move named the new point, which the trim then removed along with the dimension. The weld now happens first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch Trim: test that a parallel distance moves onto the welded centre Trimming the start half of a center rectangle's diagonal moves a distance to a parallel line onto the kept half's start, which is the centre. The test fails if the weld runs after that move: the dimension then names the cut point and is removed with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch Trim: the centre comment names the case that reaches it Only a line carries a Midpoint, so the comment's ellipse case could not reach this code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch Trim: a crossing line whose middle is only near the cut gets no midpoint hold Trimming a line at its held midpoint moved that hold onto the cutter whenever the cutter's middle sat at the cut, so a crossing line that merely happened to have its middle there was tied to the point. The hold now moves only when the sketch makes the two lines diagonals of a parallelogram (each pair of opposite sides held parallel, horizontal or vertical), as a center rectangle's are; otherwise the point stays on the cutter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch Trim: ask the solver whether a cutter's middle is held at a cut midpoint Moving a cut midpoint's hold onto the cutter only for a parallelogram of parallel, horizontal or vertical sides missed rectangles the sketch holds another way: with the bottom side held square to a side instead of horizontal, trimming a diagonal at the centre left the centre held only on the other diagonal, one degree of freedom freer than before. The hold now moves when the sketch already implies it, that is when adding it to the sketch as it was takes away no degree of freedom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch Trim: solve for the implied midpoint only when a cut lands on one Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
6578d591ac |
control::execute: check the undo depth before placing the world for the first-body fit (#5940)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
315d8cfeb7 |
fix: sketch.intersect keeps a small round between short walls (#9962)
- section() kept the loose fit whenever it had fewer curves, even when it had merged 2 mm walls and an R2 round into one R2.85 arc that misses the walls, leaving the outline open - The tight fit is now also kept when the loose one strays from the exact crossings (on planes and rulings) and the tight one does not; capped work, other curves count as near - Test: a box with R2 corner rounds and four tapered grooves stopping 2 mm short, cut at Y=20 Co-authored-by: P'tite Tête <asso@ptitetete.com> |
||
|
|
0690ee5875 |
Web app: run as a modelling editor inside another page that keeps the design files (#8517) (#11273)
* claim: #8517 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * web: editing embed for host pages (?embed=editor, #8517) A host page that keeps the files itself and frames SolidCraft for modelling needs the modelling UI without the application chrome. `?embed=editor` runs the web app as such an embed: - no application bar (logo, File menu, document tabs, update, help, report a bug) and no start page; the layout is docked; - the ribbon, browser, timeline and properties stay; Ctrl+Z and Ctrl+Y still undo and redo; - Ctrl+N, Ctrl+O, Ctrl+S, Ctrl+W and Ctrl+, are left to the host; - nothing is kept in the browser (no stored designs, autosave, recovery prompt, preferences or leave-page prompt), as with the existing viewer embed. The existing `?embed&open=` viewer embed is unchanged. SolveApp gets one flag, `embed_editor`, for desktop and test hosts too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * control: document.export / document.import / document.saved for a host (#8517) An editing embed's host keeps the design itself. Three control methods (window.solidcraft.request in the browser; the desktop control channel too; not the agent chat's, whose method list is unchanged): - `document.export` -> {name, revision, dirty, format: "json", text}: the active design as a `.json` design file holds it. `revision` is the one `document.revision` answers, so a host that follows the design compares one number. - `document.import {text, name?}`: replaces the active design with that text, timeline and parameters as saved, opened saved with a new `document_id`. It runs as a design opened in a tab of its own, with the old tab closed without asking, so whatever was open in the old design leaves with it. A text that does not read leaves the design as it was. Waits behind a file loading or a design change, as commands do, and evaluates on the window thread. - `document.saved {revision}`: the host saved that revision; refused when the design has changed since. They are control methods, not commands: they act on the app's open design. The browser API test gets a round trip through all three. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: aduijs <7501203+aduijs@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1dd921fc52 |
Components: stop Capture All Positions from doubling moves (#11259) (#11364)
* Model cache: a body made by rounds keeps them, so a later round blends them the same after opening A design gave another body when opened from its model cache: the rounds a body was made of lived only in memory, so a later round at their mitre was built sequentially (or refused, as too large) after opening and blended with them when evaluated anew. The saved model now records, per kernel body made by rounds, the body they were made on (a place in the bodies, stored once though no state holds it) and the edges with their radii; reading it attaches them back down each chain, and a thinned model keeps those bodies with the bodies made from them. Model cache format 7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: a corner patch of rounds 2/3/4 takes no more than the strips leave in its block three_rounds_at_a_corner bounded the patch's extra cut at 3 mm³ beyond the strips, a figure with no derivation; SMLib's all-at-once body at radii 2, 3, 4 takes 3.099 (V 7878.579574 against strips 7881.678). That body is the strips' outside the block its patch lies in: its rounds are the strips' cylinders ending at a's section y = rc, b's x = 20 − rc and c's rails where they meet a's and b's (the patch's four corners, now asserted), so the patch takes at most what the strips leave in that block (11.86 at 2/2/3, 32.69 at 2/3/4). The lower bound is that block; the upper one, at most the strips' volume, stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: the io crate's hand-built saved models list their rounds, as format 7 records do Model cache format 7 ( |
||
|
|
1d387d3f21 |
Measure: the area of a curved face on the exact surface, not the display mesh (#9086) (#11486)
* Measure: the area of a curved face on the exact surface, not the display mesh (#9086) * Measure: a non-straight border edge leaves the band to the mesh; fix the Vec3 imports (#9086) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
df4f9d3529 |
Inspect menu: Component Colors is a normal on/off item with a check mark (#11854)
* Inspect menu: Component Colors is a normal on/off item The Component Colors entry in Inspect > Check was labelled "Enable Component Colors" and swapped to "Disable Component Colors" with a different icon while on. It is now labelled "Component Colors" in both states, keeps one icon, and shows a check mark when on, like Draft Analysis and the other toggles beside it. The command id and parameters are unchanged. The now-unused "disable" strings and the colored_components_off icon are removed. Other languages' old "Enable ..." wording is dropped so they fall back to English until retranslated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the Component Colors label in the fully translated catalogs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Checkable menu rows tell screen readers whether they are on Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Georgian: Component Colors loses its Enable/Disable wording Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
07ef94e102 |
Hole: drill only the shown bodies when no target is picked (#7520) (#7562)
* claim: #7520 * Hole: drill only the shown bodies when no target is picked (#7520) A Hole that names no bodies drilled every body in its path, hidden ones too, and its dialog preview replaced the hidden bodies with drilled ones. Like a cut (#3961), it now takes the shown bodies of the active component as its participants while some are hidden, stored so showing the others later changes nothing. With nothing hidden, or everything, it still drills every body. Its face points are named on the bodies it drills first, so a hidden body's face in the same plane no longer takes the picked face's name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FN5eEMrqWWXqi65FcK8GXq * Hole: drill the picked body though it is hidden (#7520) Review on #7562: with the picked face's body hidden (picked through Select Other, or hidden while the dialog is open), the shown-bodies default left it out, so the hole drilled only shown bodies further along, or nothing, without a message. The body whose face holds the hole's position now joins the shown ones, unless a shown body has a face there too (a face shared by a shown and a hidden body is the shown one's, as a pick in the view takes it). The test also covers editing a hole made with nothing hidden while a body it drills is hidden: timeline.redefine stores participants only when the edit passes them, so the hole keeps its empty scope and the hidden body its bore. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMbqRqYimvY26QzcvrojSC * Hole: test that a hole made with a body hidden replays the same (#7520) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Hole: follow the face-name lookup now returning a Result (#7520) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Hole: tests follow main's Vec3 and world_state (#7520) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Hole: format (#7520) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Hole: with every body hidden, drill them all as before (#7520) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: sascha2101 <221609842+sascha2101@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
8f4d7959df |
Agents and scripts: Parameter Sweep describes its exact parameters and reply (#10977) (#10978)
* claim: #10977 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Parameter Sweep: input and output schemas (#10977) inspect.parameter_sweep gets a typed contract and reply types in schema/parameter_sweep.rs and leaves unconverted.txt. Each key reads as the handler reads it, with its message; the reply is built from ParameterSweep and its item types, with the same JSON as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Parameter Sweep schema: a missing parameter reaches the handler's message Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * parameter_sweep schema: do not publish a null default on the required parameter Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
727bb23c7e |
Section Analysis: a body standing on another keeps its own cap, also in CPU pictures (#4622)
Where one body stands on another (a post on a plate), the post's bottom, seen through the cut, and the plate's top are the same plane. In the CPU rasterizer (headless pictures without a GPU) the plate's top won that depth tie and showed through the post's cut. The cut now wins a tie by a few f32 steps (DEPTH_EPS). The viewport already draws this right since #6363 and #6728; a GPU regression test now covers it, both creation orders, orthographic and perspective, with both depth formats. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ef92f35b16 |
Sketch drag: a step solved ahead that solves becomes the sketch, one step per core (#7648) (#7649)
Past a failed step a scripted drag solves the next steps at once and takes those that fail in a row as tried; the first that solved was then solved again by the walk. It now becomes the sketch from its solved copy, so no step is solved twice. A batch holds one step per core (at most 8), and on one core or in the browser build, where a batch would run its steps one after another, the walk solves the steps itself. The walk takes the same steps with the same outcomes, so results and counted solves don't change. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
cfc4908291 |
Sheet metal: returns on a notched tray now close at the convex corner (#8823) (#9714)
* claim: #8823 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sheet metal: returns on a notched tray close at the corner away from the notch (#8823) Closing two returns at a corner was refused when either return already lay over another flange in the flat pattern, even far from that corner. On a tray with a notch, the walls on either side of the notch's inner corner both unfold into the notch, so the return on one of them lies over the other there; the return's opposite convex corner was then left open ("closed, the flanges would overlap in the flat pattern") and the two returns ran through each other. A closure is now refused only when it makes the two returns overlap or adds to what either already shares with another flange in the flat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1432131e95 |
English: command labels in title case, other labels in sentence case (#9085) (#10734)
* English: command labels in title case, other labels in sentence case (#9085) The rest of #9085 after #9194 (the plural and the spelling) and #9907 (the Preferences page names). Command labels are in title case (422 of 430 were already); the seven in sentence case follow, and Fix/UnFix reads Fix/Unfix. The UI text skill states the rule. The user docs name the Preferences footer's button by its current label, Restore page defaults (#10295). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Navigation bar menu test: the echo names the command by its own label Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * UI text skill: state the case rule in one short sentence, under the 3600 limit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Localization doc: the case rule in full, with examples Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Localization doc: the example button is Restore page defaults now Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
91ecea8cfd |
Properties: account for sheet perforations (#6025) (#6028)
* claim: #6025 * fix(engine): account for sheet perforations in physical properties * fix(inspect): retain kernel topology counts for sheet bodies |
||
|
|
863b0777da |
Sketch: dragging a constrained line by its middle no longer stalls (#11696) (#11714)
* claim: #11696 * Sketch: move constrained lines that stall during dragging |
||
|
|
80889762ce |
Agents and scripts: Configure, Configuration Column, Row and Rule describe their exact parameters and reply (#11895) (#11896)
* claim: #11895 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Configuration table: input and output schemas for Configure, Configuration Column, Row and Rule (#11895) describe_command now gives the exact parameters and reply of the four commands that change a design's configuration table, and the warn and strict parameter checks use them. The handlers read their parameters from the raw JSON, so the new contracts in schema/config.rs read each key as its handler does, with its message: lists of names as params::string_list (whose json_brief and MAX_STRING_LIST become pub(crate)), exactly one column target, faces picked or a face column's key, a row's cells, and rules (whose schema describes them; the handler keeps its own check). What only the design can answer stays the handler's. All four reply with ConfigTableReply, as config.table does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
a3f293c987 |
Error messages: an out-of-range value names the field that is wrong (#9625) (#9684)
* claim: #9625 Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch> * Name the value at fault when a hole, sheet rule, joint or extrude is refused (#9625) Several refusals were right but named a check the input had passed, so the user changed the wrong field: - solid.hole: an unknown `fit` was reported as an unknown bolt size; it now says the fit must be close, normal or loose. A countersink angle out of range was reported as a countersink too narrow; the angle and the width are now checked apart. A `diameter` number out of range was reported as missing; it now gives the range, as other parameters do. - Sheet rules: a thickness of 10000 mm or more said "must be positive"; it now gives both limits. The K-factor and the bend radius are named on their own, and the message no longer implies a radius of 0 is refused. - joint.drive: a number out of range said "numbers or expressions"; it now gives the range. - Extrude: a distance past the kernel's limit said `end = 1000000000`; it now says the extrusion is too long and gives the limit. Fixes #9625 Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch> * Refuse a too-long extrusion before the kernel and match the countersink floor (#9625) The kernel is paused, and its `finite()` check also guards a revolve's angle and a cylinder's and a torus's sizes, so its message must not say "extrusion". crates/kernel is back as it was; the doc evaluator now refuses an extrude (plain, tapered, or redefined from the Edit Extrude dialog) whose end lies 10000000 mm or more from the sketch plane, mirroring the kernel's limit, and says so. A cylinder of radius 2e7 keeps the kernel's own message. The countersink check refused 0.1° while the message said "more than 0°". The floor stays (the cone grows as 1 / tan of the half angle) and the message now names it: more than 0.115°. Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch> --------- Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch> |
||
|
|
aba00427fa |
Render shots: input and output schemas for Duplicate, Rename and Remove (#11450) (#11451)
The handler's strict parameter type moves to schema/render_shots.rs as ShotParams, with descriptions and JsonSchema, and becomes the contract of all three commands; the handler reads the same type. It builds ShotChange instead of a json! literal, and takes its operation as a ShotOperation enum. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
cccf8c1ece |
Snap points: a flat face offers its corners, edge middles and every hole's centre (#11476) (#11477)
* Snap points: a flat face offers its corners, edge middles and every hole's centre (#11476) A flat face now offers its whole outline as snap points, read from the exact faces and edges: every corner, the middle of every straight edge and the centre of every round edge, holes included, as well as the centre of its area. Corners on a closed circle's seam, or where the kernel split one circle into pieces, are left out. snap_points_from gives each point with where it came from (SnapSource): the face it was picked on, the face's outward normal and a point inside its edge, so a tool can keep the point by name (joint.create's edge, corner and on) and turn a frame to the face. SnapPoint itself does not change, so code that builds one keeps compiling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Snap points: a round face's end centres say which way their end faces (#11476) The centres at a cylinder's or cone's two ends now carry a normal in their SnapSource: the axis pointing out of that end, which is the normal of the face a hole opens onto or of a pin's end. A joint origin taken from one can then lie on that face, as the centres a flat face offers already do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Snap points: a hole centred on its face keeps its own point and rim (#11476) Snap points were one point when they lay at one place, whatever their kind, so a hole centred on its face was lost behind the face's centre, and with it the rim its point keeps. Now only points of one kind are merged: the face's centre and the hole's centre both stay, and only the hole's has its rim. SnapSource::normal's doc now says it is also the axis out of a cylinder's or cone's end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Snap points: a washer's two rims keep a centre each (#11476) Centres at one place are one point only when they are on one circle: the inner and outer rims of a washer face now keep a centre each, with its own rim, while the pieces the kernel split one circle into are still one point. SnapSource::normal's doc now says that at a round face's end it is the axis out of that end of the face, which at a blind hole's bottom points into the material below, not out of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Snap points: rims are told apart by their radii's size, not their place (#11476) Two centres at one place were one circle when their rims' radii differed by less than the place's tolerance, which grows with the distance from the origin: 60 m out, rims of 4 and 4.05 counted as one and one lost its point. The radii are now compared with a tolerance from the radii themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Snap points: nearby points stay apart far from the origin (#11476) Points of one kind at one place were merged within a tolerance of 1e-6 of their distance from the origin, 0.06 mm at 60 m, so two small holes there whose centres are 0.05 apart lost one centre. Places now use 1e-9 of that distance (0.06 µm at 60 m): well above the rounding of coordinates and of a circle fitted to an imported edge, so a point found twice is still one, and far below any feature. The radii keep their own tolerance. The merge is its own function, so its test can give it points directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Alfonso Tamés <mufufu@Mufufu-MacBook-Pro.local> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
dcbedbd805 |
Don't blindly reopen a design that stopped the last session (#5064) (#10443)
A design that crashes or hangs the app while it is being reopened was reopened blindly every launch, bricking the app each time. A launch that reopens designs now marks them in the recovery folder; the marker is cleared as each design finishes opening. A launch that finds the marker left behind skips those designs once and says which one the last session stopped on, so the app starts usable and the loop breaks. Co-authored-by: Dahak Builds <dahakbuilds@users.noreply.github.com> |
||
|
|
6488a540c9 |
Windows: a lost graphics device restarts the app instead of crashing (#10240) (#11109)
* claim: #10240 * Lost GPU: a loss met by a queue write restarts the app instead of crashing (#10240) The per-frame probe (#6528) finds a device the driver reset before the frame's uploads, but the driver resets a device at any moment: a reset that lands after the probe is still met first by a queue write or the present, and wgpu-core unwraps the driver's Lost there (PendingWrites::activate) instead of losing the device. That panic ended the app and wrote a crash report. - egui-wgpu: the painter runs each frame under DeviceLost::survive. A panic the frame meets is taken for the loss once the probe then finds the device lost (the probe's path loses the device and runs its lost callback); the painter draws nothing more and the app restarts as for any lost device, keeping unsaved changes for recovery. Any other panic carries on unwinding. - Crash reports: a panic inside wgpu-core that unwraps Lost is the device loss, not a bug, and is not reported. A command that meets it fails; the next frame's probe restarts the app. --------- Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com> |
||
|
|
3e70ad9876 |
View navigator: right-click to choose Axes, Cube or a Custom body (#10266)
* View navigator: a custom body as the navigator, and a right-click menu to switch types A right-click anywhere on the view navigator opens a menu with its three types: Axes, Cube and Custom. Custom opens the Custom View Navigator panel (a feature panel with OK and Cancel): pick a body in the view, its texture (Themed: the cube's colours; Modeled: the body's own appearance and the view's edge colour), and whether the cube's rotation arrows and Home button go around it. The navigator previews the panel's choices while it is open; Cancel leaves it as it was. The custom navigator draws the body at the cube's size through a small depth-buffered raster, so hidden faces stay hidden; hovering a face highlights it, a click looks straight at it (and frames the model with navigator_fit on), a drag orbits. Until a body is chosen it draws the cube. The body is kept as a packed snapshot (16-bit, base64) with the preferences and in settings profiles, so it stays across runs and designs and travels with an exported profile. Bodies over 10,000 triangles, and long or flat ones (thinnest width under a fifth of the widest), are refused. New command view.navigator (style, body, texture, arrows, home) does the same without opening anything; new preferences navigator_texture, navigator_arrows and navigator_home, and a Custom choice for navigator_style. Defaults are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: a hovered face in Modeled takes the view's selection colours In the Modeled texture the face under the pointer is filled and outlined the way the view selects a face of the model (sel_face, sel_edge), not in the cube's hover blue and accent, which Themed keeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: a hovered face in Modeled lights up as the view's mouse-over does The face under the pointer keeps its own colour, a little lighter (hover_face_lift) and still shaded, with its edges in the view's mouse-over edge colour (hover_edge), as the 3D view shows a face under the pointer; not the selection colours. Themed keeps the cube's hover blue and accent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: rotation arrows and Home on by default navigator_arrows and navigator_home start on, so a new custom navigator has the cube's arrows and Home button around it; the Custom View Navigator panel turns either off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: the strings in every complete language, and test fixes - The new messages in Arabic, Hebrew and Vietnamese (complete catalogs, like Japanese and Chinese). - The navigator's raster goes through one colour helper, listed with its reason among the files allowed colour literals (the design's appearance shaded into pixels). - nav_settings joins the requested-icon manifest (the view.navigator command's icon). - A visible edge piece is kept only when the stretch seen with it, across the edge's segments, is at least two samples long: a hidden edge no longer shows a sliver at a silhouette corner. - The navigator layout test treats Custom without a body as the cube it draws; the panel and size tests no longer assume an empty undo list, the style before opening, or a coarse sphere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: profiles carry its texture, arrows and Home Settings profiles keep a fixed set of preference keys (#9907), which the custom navigator's newer settings are not part of. They travel in the profile's own `view_navigator` entry, next to its body (`view_gizmo`): captured, checked (a value this version can't read is left out) and applied, leaving the fixed key set unchanged. The cube's arrow inversion (#10286) applies to the custom navigator's arrows too, through the shared arrows(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: follow main's Vec3 move and fallible world_state Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: list view.navigator in the rig's EXEMPT, refuse a stored body that can't save again, right-click without a widget over the navigator Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: keep the body unless picked again, save only a profile that reads back, no navigator menu through a popup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: refuse a stored body with a triangle past its points Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: a stored body meets the triangle and aspect limits a picked one does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Custom view navigator: a body at the 5:1 limit stays inside it once packed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4d738cd210 |
Sketch: an ellipse is drawn with its axes, and D measures its half-axes (#9291) (#9292)
* Sketch: an ellipse comes with its axes, and D measures its half-axes An ellipse could only be sized by its minor radius, drawn like a circle's radius, and there was no way to give its full axes. sketch.ellipse now also adds the major and minor axes as construction lines through the centre. The major axis runs from the major end to the point opposite it; the minor one is perpendicular to it, ends on the ellipse, and both are bisected by the centre. That adds six coordinates and six equations, so the ellipse keeps its five degrees of freedom, and it needs no new constraint kind and no format change. With the axes in place every ellipse size is an ordinary dimension. D on an axis line gives its length, the whole axis. D on the outline gives a half- axis, the distance from the centre to an axis end, chosen the way a line chooses horizontal or vertical but in the ellipse's own frame: text pulled across the major axis measures along it (the major half-axis), text pulled out past an end of it measures across it (the minor one). The end on the text's side is used. Near the boundary between the two, a dimension being placed keeps the half-axis it had (sketch.dimension's previous_axis, which the Dimension tool sends), so the preview does not flip. A half-axis and its whole axis determine each other, so the second becomes a driven dimension through the existing redundancy path. Deleting the ellipse leaves its axes, as deleting a Center Rectangle's edges leaves its construction diagonals. Ellipses without axes, from existing designs, keep the minor radius as before, and type radius still gives it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guide: an ellipse's axes and half-axis dimensions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: test that an ellipse's half-axis preview keeps its axis near the boundary The Dimension tool sends the half-axis its last preview chose, so near the boundary between the major and the minor half-axis the preview keeps it. This covers that path from the tool, from both sides of the boundary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's axes select and drag with it, as a rectangle's diagonals do A double-click on a Center Rectangle's edge or diagonal selects its edges and both diagonals, and dragging a diagonal moves the rectangle without changing it, because its lines share corner points. An ellipse's axes are held by constraints instead, so a double-click selected only the ellipse (and Delete then left the axes behind), and dragging the major axis moved the ellipse but stretched its minor half-axis. Sketch::ellipse_axes now finds an ellipse's construction axes (the detection sketch.dimension already used, moved into the sketch crate). Sketch::chain treats an ellipse and its two axes as joined, so a double-click on any of them selects all three. Dragging either axis moves the ellipse and both axes as one, keeping both half-axes. Dragging the outline still sets the minor half-axis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a corner test reads its line's id instead of assuming l1 sketch.ellipse now adds two axis lines, which take the first line ids, so the extend test reads the id of the line it draws from the reply. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's axes cut a trim, as a Center Rectangle's diagonals do Trim, extend and break take every other curve as a cutter, construction lines included, so an ellipse's construction axes stop them as a Center Rectangle's diagonals do. A test now states it for both shapes, and the guide says it. The freeform cutter test keeps the axes it used to delete and asserts the piece a trim removes: from where the major axis crosses the circle to where the ellipse does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: test dragging an ellipse's outline with its axes present Dragging the outline sets the minor half-axis, and the minor axis line, held on the ellipse at one end, follows it; the centre and the major half-axis stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: other dimension types on an ellipse with axes keep the minor radius Only auto, major and minor give a half-axis on an ellipse drawn with its axes. Any other type (radius, diameter, horizontal and the rest) gives what it gives on an ellipse without axes, as the parameter doc says, instead of quietly becoming a half-axis chosen by the text. The arm for a missing text_at is dropped: with no text the rule already picks the minor half-axis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: test an ellipse's half-axis dead zone from the major side too The tests only showed a previous minor half-axis being kept near the boundary; the point they used on the major side is major by geometry alone. A point inside the band where geometry says minor now shows a previous major half-axis kept, in the engine and in the Dimension tool's preview. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a placed ellipse half-axis is the one its preview showed On an ellipse already sized, a half-axis is added as a driven dimension on the click, and that command left out the half-axis the preview kept near the boundary, so the click could place the other one. It now passes it as the preview does. The remembered half-axis also comes only from a draft whose text was placed (one without text is the minor half-axis by default and biased the first placement), is kept per sketch as well as per picks, and is forgotten once a dimension is placed or the picks are cleared. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: say how an ellipse's axes are recognised and what that costs The axes are read from the constraints, with no mark in the design, so the doc comment says which lines count, that deleting the midpoint or point-on-curve constraint leaves an ellipse without axes, and that each lookup scans curves times constraints. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse with one axis deleted still picks its half-axis by the text With one construction axis deleted, D on the ellipse fell back to the minor radius wherever the text was pulled, because the half-axis choice needed both axes. It now reads what is left of them and chooses as before: the major half-axis goes to the major end (also from the far side, when the point opposite is gone with its line), the minor one to its axis end, or as the minor radius when the minor axis is the one deleted. An ellipse with neither axis keeps the minor radius. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: the one-axis half-axis test checks what is measured to The test for an ellipse with one axis deleted checked only the reply's axis and value, which both ends of an axis give alike. It now checks the dimension's kind and end: the axis end on the text's side, the major end from either side once the point opposite is gone, a radius once the minor axis is. With the major axis deleted and no text the reply names the minor axis and measures to its end, where it used to be a radius with no axis named. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's minor radius is drawn as its half-axis, without R A radius on an ellipse is the minor half-axis, and it was drawn as a circle's radius: one leader from the centre towards the text, marked R, which measures nothing a reader can see. It is now drawn as the distance from the centre to the minor axis end on the text's side, the way the half-axis is drawn while the ellipse has its axes, and labelled with the length alone. This is what D gives once the minor axis line is deleted, and on an ellipse with no axes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's half-axis keeps a radius's stored text The half-axis frame read the stored text from the middle of the half-axis, so a radius placed on an ellipse in an existing design would show its text somewhere else. The text is stored from the centre again, as a radius's always was, and the side drawn to follows it. An unplaced one sits where a linear dimension to the minor axis end puts its text, and stacked texts step out from the centre as a radius's do. A view test reads the painted label, so the drawing cannot go back to R unnoticed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse moved, turned or scaled takes its axes along Move, Sketch Transform and Scale moved only the curves picked, so an ellipse moved without its axes left them where they were: its centre no longer halved them, the minor end left the ellipse, and the sketch stayed unsolved. A Center Rectangle's diagonals share its corners and always go along; an ellipse's axes share only the major end. The axes now go with the ellipse, as they do when it is dragged. Copy is unchanged: it copies no constraints, for a rectangle either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a preference draws ellipses without their axes, as before Drawing an ellipse with its construction axes changes what the Ellipse tool makes out of the box, so the old ellipse stays one setting away: Preferences › Sketch › Draw ellipses with their axes, on by default. Off, the tool draws the ellipse alone. sketch.ellipse takes axes: false for the same, and keeps drawing the axes when it is not given. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: sketch.ellipse refuses an axes value that is not true or false A string such as "false" was read as not given, so the axes were drawn; it is now refused as the text commands refuse a non-boolean bold or italic. The move test also covers an ellipse whose minor axis was deleted: the major axis left goes along. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: D picks a half-axis on an ellipse without axes too An ellipse with no axis lines (both deleted, a mirrored copy, one from an older design) gave the minor radius wherever the text was pulled, so its major half-axis could not be dimensioned on it. The half-axis is now chosen by where the text is on every ellipse: the major one to the ellipse's own major end, the minor one as its minor radius. With no text it is the minor radius, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: with one half-axis dimensioned, D on the ellipse gives the other D on an ellipse chose the half-axis by where the text was pulled even when that half-axis was already held by a dimension, so the second D usually guessed the one already there and was refused as over-constrained. With a driving dimension already on one half-axis (to an axis end, the minor radius, or the whole axis along its line or between its ends), D with no type now gives the other, in either order and with or without the axis lines. With both held it chooses as before; an explicit major or minor is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: the held half-axis rule is documented and its cases tested The Dimension command's parameters and the guide now say that with one half-axis held, D on the ellipse gives the other. Tests cover the whole axis held as a distance between its ends and as its line's length with the other axis deleted, and check that a mirrored ellipse has no axes. The placement test undoes its first dimension, so its second half still tests where the text is rather than the held half-axis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: Transform previews an ellipse with its axes OK in Sketch Transform moves, turns and scales an ellipse's axes with it, but the window drew where OK would leave only the picked curves, so the axes stayed put in the preview until OK. An ellipse picked alone is now drawn with the axis lines it has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: the typed-radius ellipse test counts the ellipse's axes Main's #10282 test drew an ellipse with typed radii and expected one curve; with the ellipse_axes preference on by default the tool also draws the two axes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's remaining axis still drags and selects it With one axis deleted, dragging the other axis did not hold the ellipse (with the minor axis left, the drag squashed it), and a double-click on the ellipse or that axis selected only the one curve. The drag and Sketch::chain now read whichever axes are left through ellipse_axis_lines, as Transform and Move already do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: drop the unreachable third arm of the held half-axis check A distance from the centre to the major end or the point opposite it is already matched by the first arm, so the third arm and its major_end closure never ran. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: D on an ellipse's axis line is the whole axis wherever the value is pulled An axis line took the free line's rule, so on a turned ellipse a value pulled beside or above the box the axis spans gave its horizontal or vertical distance. An ellipse's axis is a construction axis, so auto now always gives its length, which the held half-axis check already counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's axis is never a side of a Fillet or Chamfer corner A line drawn from an ellipse's major end shares that point with the major axis, so Fillet or Chamfer there took the two as a corner (two lines skip the construction filter) and rounded the line into the axis. The axes are left out of a corner, picked by its point or as a and b. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: test the move reply, extend and the one-axis Transform preview for ellipse axes The reply of sketch.move, sketch.transform and sketch.scale lists the axis lines, Extend stops at an axis, and Sketch Transform previews an ellipse with the one axis left after the other was deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: with Draw ellipses with their axes off, D on an ellipse is its minor radius as before The preference brought back the old drawing only; D on an ellipse had changed with no way back. sketch.dimension takes half_axes (default true, refused when not true or false); false makes auto on an ellipse the minor radius wherever the text is. The Dimension tool and the context menu's Sketch Dimension pass it from the preference, and with it off a radius on an ellipse is drawn and labelled R as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: read an ellipse's axes in one pass over the constraints ellipse_axis_lines scanned every constraint for every curve, so 500 ellipses with their axes (1500 curves, 2000 constraints) took 1.6 s to read and Move on all of them 2.0 s. It now collects the lines the centre bisects first: 3 ms and 0.36 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: the dimension and corner parameters say how an ellipse's axis lines take part Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Preferences: Draw ellipses with their axes says D gives the minor radius when off Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: ask only the ellipses centred on a line's midpoint whether it is their axis is_ellipse_axis read every ellipse's axes to answer for one line. An axis is bisected by its ellipse's centre, so it now asks only the ellipses centred on a point that bisects the line. The answer is the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a horizontal or vertical dimension across a level major axis holds it for D on the ellipse half_axes_held counted a distance, a length and a radius, but not a horizontal or vertical dimension across the major axis, which is its length when the axis lies that way. D on the outline could then take the held major half-axis and be refused as determined; it now gives the minor one. Across a slanted axis such a dimension is only a projection and does not count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Dimension: a draft on an ellipse is drawn with the axes preference it was made with The frame read the preference as it is now, while the dimension added is the draft's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a horizontal or vertical dimension across an upright minor axis holds it too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: drop the unused Sketch::ellipse_axes; ellipse_axis_lines says how the axes are read Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse's own axes do not cut it, so Trim takes a lone ellipse whole and stops at real crossings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: Fillet and Chamfer offer no corner at an ellipse's axis end, as the engine takes none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a deleted ellipse leaves its centre on its axes, as a Center Rectangle's centre stays Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: ellipse axis docs say what they do, and the corner picker tests a curve's ends before its axis role Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: the trim-at-a-crossing test checks that part of the ellipse is left Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: an ellipse axis moved, turned or scaled on its own takes its ellipse along, as a drag does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: a selection dragged by an ellipse axis takes the ellipse along, as the axis alone does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: the Sketch preferences page lists Draw ellipses with their axes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Sketch: the ellipse axes help text says D gives the minor radius, drawn and labelled R as before, wherever the value is pulled Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2cd54b6af9 |
Agents and scripts: the standard part commands describe their exact parameters and reply (#11003) (#11004)
* claim: #11003 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Standard parts: input and output schemas (#11003) parts.library, parts.insert, parts.fastener and parts.resize get typed contracts and reply types in schema/parts.rs and leave unconverted.txt. Each key reads as the handler reads it, with its message; the replies are built from PartsLibrary, InsertedPart and ResizedPart, with the same JSON as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Standard parts schema: Vec3 comes from solidcore_record Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Standard parts schema: hole picks must start with a list Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * parts.insert schema: the first hole pick must be a point, not any list Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
c9c063620a |
Hole: Bridged option for counterbores (#11103) (#11104)
* claim: #11103 * Hole: Bridge option for counterbores (#11103) A counterbore hole takes an optional `bridge` length: two 3D-printing layers that thick below the counterbore's floor, a slot along X across the counterbore and then a square, both 0.02 mm wider than the hole, so a printer bridges the step instead of sagging into it. Empty (the default) keeps a plain counterbore. The clearance keeps the bore, cut straight through both layers as for a plain counterbore, clear of their sides: at exactly the hole's width it ran tangent along them and broke through. The command and the geometry refuse a layer that is not a positive length, layers that don't fit in the hole below the counterbore, and a bridge on any other hole type. The Hole dialog shows a Bridge field below Drill Point for counterbores. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Hole: translate the Bridge label for the complete catalogs (#11103) Arabic, Hebrew, Japanese, Vietnamese and Chinese carry every English message, so `cargo xtask i18n --check` needs the new label in each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Hole: bridged counterbores refuse layers past a through hole's exit, too narrow a counterbore and a malformed bridge (#11103) - Through all, the second bridge layer must end inside a body (exact point classification), short of the exit face; the tool's reach is no measure of the material. - A bridged counterbore must be at least 0.04 mm wider than the hole, so the slot's ends have room on its wall (no square root of a negative number reaches the extrude). - `solid.hole` refuses a `bridge` that is given but not a length expression (`true`, `[]`, `""`) instead of making a plain counterbore; `null` still leaves it out. - Loop2 and Seg2 now come from solidcore_record (main moved them). - The "nothing saved" check looks for the `"bridge"` key: `format_pending` names `bridged-counterbore` in every design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Unit defaults test: solid.hole has the bridge field too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
bec762fb2b |
Agents and scripts: the render library browsing commands describe their exact parameters and reply (#11443) (#11444)
* claim: #11443 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Render library: input and output schemas for List, Describe, Targets and Preview (#11443) Describe, Targets and Preview read their strict parameter types from schema/render_library.rs, which become their contracts. List keeps its two readers (the physical profiles' takes availability: null, the other catalogs' doesn't); its contract takes what either takes. The handlers build LibraryPage, LibraryResource, LibraryTargets and LibraryPreview instead of json! literals; a catalog resource is read into ResourceSummary through a small Listed reader. The physical profiles' replies keep their JSON, which the schemas describe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Render library schema: the list says which availability each catalog takes render.library.list has two readers: the physical profiles' takes availability all, usable or null; the other catalogs' (and a call without kind, which lists surfaces) take all, usable, specification or blocked, but not null. The schema now says so with an anyOf on kind. The type still takes what either reader takes: the readers check the query and the page before availability, so refusing it in the type would change which message a call with two mistakes gets in strict. A new test checks that the schema takes ten calls exactly when the handler does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
826fce68eb |
Assembly: Move Occurrence says when the part's joints put it back (#11723) (#11791)
* claim: #11723 * Assembly: Move Occurrence says when the part's joints put it back (#11723) A part that rigid joints hold to something grounded was moved, then put back by the joint solve after the command, while occurrence.move still replied with the moved transform. occurrence.move now solves the joints before it replies. When they put the part back, the reply gives where the part is, adds reverted: true and a warning that names the joint holding it and what to change instead. A free chain of parts follows the move as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move Occurrence: the warning names the joint for a part in a repeated assembly too (#11723) A part inside an assembly placed more than once has no path of its own, so the reverted-move warning asked for one instead of naming the joint. It now looks at the placement the caller named, or else the first one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move Occurrence: list the part's joints when no single joint holds it back (#11723) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fabeaa329a |
Desktop app: closing a design stops its kernel work, and designs build the same on any kernel (#11771)
* Desktop: closing a design stops its kernel work; same result on any kernel A design's jobs now run under a stop token that closing or replacing the design fires: an operation under it refuses to start, and one running ends at solidcore's next check. The kernel it ran on is not used again. Calls that answer from a body itself always finish, since a stopped call can leave what it borrows half-changed, and what fills a body's shared cells is not stopped. Every kernel call starts clean (the same random rays, no stations from earlier calls), so a design builds the same on any kernel of the pool, down to its B-rep records. The pool is bounded: at most 8 kernels wait between calls, and at 256 running calls a new call fails rather than grow or wait. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Stop tokens: a copy never stops its design; a stopped job can't decide a refusal A copy replacing its own design stopped the token it shares with the design it came from, so that design's later work would be refused. Only the design itself stops it now. Which face a refusal names no longer depends on whether the job that found it had been stopped: the refusal is kept with the body, and a stopped job's probes were all refused, which named the wrong face. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1cbfb889d5 |
Agents and scripts: Compare Bodies describes its exact parameters and reply (#10994) (#10995)
* claim: #10994 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Compare Bodies: input and output schemas (#10994) inspect.compare gets a typed contract and reply types in schema/compare.rs and leaves unconverted.txt. Each key reads as the handler reads it, with its message; `color` checks each colour with the handler's own color_param, now pub(crate) and re-exported from cmd. The reply is built from Comparison and its parts, with the same JSON. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Compare: drop the json import the typed reply no longer uses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Compare schema: colour strings carry the hex pattern Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
954232cef1 |
AI client setup: preserve configuration files when a write fails (#11363) (#11410)
* claim: #11363 * AI client setup: replace configuration files atomically (#11363) |
||
|
|
0fc4cd2747 |
Agents and scripts: the render stage commands (Ground, Backdrop, Clear) describe their exact parameters and reply (#11455) (#11456)
* claim: #11455 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Render stage: input and output schemas for Ground, Backdrop and Clear (#11455) The three handlers' strict parameter types move to schema/render_stage.rs as GroundParams, BackdropParams and ClearParams, with descriptions and JsonSchema, and become the contracts; the handlers read the same types. The handlers build the shared StageSaved reply instead of json! literals, and the saved setup is serialized with an error instead of json!'s panic path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
6d83f95fba |
Isolate a body: other components are hidden as components, in one step (#7896) (#7951)
* claim: #7896 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Isolate a body: other components are hidden as components, in one step (#7896) Isolating a body hid every other body one by one: browser.visibility with `items` writes only hidden_bodies, so every other component's Browser row kept an open eye and normal text, and its eye could not bring it back (the first click hid an already invisible component). browser.visibility takes `isolate: true` with `items` (bodies), as it does with `paths`. The picked bodies' own placements stay open, their other bodies (and the root's) are hidden one by one, and every other placement is hidden as a placement. Isolate in the Browser and the view runs that one command, so it is also one undo step instead of two. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Isolate a body: a hidden Bodies folder or group it is in shows again (#7896) Isolating a body inside a hidden Bodies folder or group left that folder or group hidden, so the picked body stayed hidden. Isolate now shows the folders and groups (with the groups they are in) that hold the picked bodies; their other bodies are hidden one by one as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Isolate a body: look for hidden folders only when some are hidden, and find body owners once (#7896) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ed3510a91f |
Typed schemas for the design properties commands (part of #2829) (#10920)
document.metadata, document.metadata.set and document.metadata.remove get input and output schemas: contracts in schema/metadata.rs, checked in front of the unchanged handlers, and reply types the handlers now build their replies from. Their lines leave unconverted.txt. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d25f8198fa |
Pieces of a cut keep their names when the design is evaluated again (#11658)
A cut that leaves a body in pieces names them after their faces (`order_lumps`): the piece whose least face name sorts first takes the first name, and so on. It moved the names but left the pieces where the kernel put them. The session then pinned the feature's body names in that state order, and the next full evaluation (opening the design, or editing a parameter upstream) handed them out again in a different order: two pieces swapped names, and a later feature that named one met the other. Found by a local model fuzzer. The pieces now also take the family's places in name order, so the names pinned are the order the next evaluation hands them out in. A design saved before keeps the names a fresh evaluation gave it. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
03b5248dc1 |
Sketch: Line and Construction Line refuse a second point next to the first (#11595)
A through-point 0.0000001 mm from the start made an infinite line whose direction nothing held, and a Line that short had both ends connected to the origin, a line of length zero. Both now refuse points closer than the distance at which a new point is connected to an existing one. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f9dd77e383 |
Configurations: reject invalid suppression values when saving rows (#9088) (#11571)
* claim: #9088 * Configurations: reject invalid suppression values before saving rows (#9088) |
||
|
|
8a74336713 |
Tests: the autosave recovery test no longer fails at random on a busy machine (#11815)
* claim: Recovery: the save test waits for the autosave worker before it checks * Recovery: the save test waits for the autosave worker before it checks saving_drops_the_entry_and_a_clean_close_leaves_nothing marked the session saved right after the tick that started an autosave. Under load the worker was still writing, so the next tick found the write running, took nothing up and dropped nothing; the file landed afterwards and the check that it is gone failed (seen in CI on #9021). The test now ticks, bounded, until the autosave has caught up (Autosaver::caught_up), as the app's own frames would, before it marks the session saved. A small helper in the test module does this. The app's behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5e4c52a7cb |
Sketch Transform: keep the applied rectangle at the previewed rotation and size (#11617) (#11620)
* claim: #11617 * Sketch Transform: preserve dimensioned geometry on apply |
||
|
|
3a23d21795 |
Lip: clearer guidance when the face is not a shelled rim (#10437) (#10871)
* claim: #10437 Co-authored-by: Cursor <cursoragent@cursor.com> * Lip: say Shell first when the face is not a rim (#10437) A solid box top left OK disabled with a vague shelled-body hint. Name Shell and the rim-around-an-opening requirement in the refusal, the dialog tip, and the command help. Co-authored-by: Cursor <cursoragent@cursor.com> * Lip: keep the dialog hint as it was, match the new refusal text in the test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e199f9aeff |
Agents and scripts: Match Surface describes its exact parameters and reply (#10981) (#10982)
* claim: #10981 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Match Surface: input and output schemas (#10981) surface.match gets a typed contract in schema/surface_match.rs and the shared FeatureResult as its output, and leaves unconverted.txt. Each key reads as the handler reads it, with its message; like solid.scale it declares `name` and `participants` itself, since a match makes no body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Follow main's kernel merge: world_state and the shared continuity reader Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Surface match schema: Vec3 comes from solidcore_record now Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
e06d6e36d8 |
Agents and scripts: the material card checks describe their exact parameters and reply (#11036) (#11037)
* claim: #11036 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Physical material property commands: input and output schemas (#11036) material.properties.validate and material.properties.directional get typed contracts and reply types in schema/material_properties.rs and leave unconverted.txt. The card stays the handler's to check; the direction has the handler's messages. The replies mirror the document's Validation and DirectionalModulus, destructured in full. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |