mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-08 04:52:10 +00:00
e4844753cb9a836cda170d2a416412b3ca875ff1
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5fc160732e |
Main's new callers of the placing calls that now return their error
Code main added since the last rebase reads the placed model, a camera or a scene as values; on this branch they return Result. Picks and the edit dialogs read the session's placed model through open_meshing::session_world, as the others do; the revolve and circular-pattern axes, the model axis of a command and the warming of a computed edit pass the error on; tests unwrap. A test meshing bodies uses Body::mesh, the one mesher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HoZgkCdAVrscuw2kjQTWDs |
||
|
|
cfc393d68f |
Main's new callers of the placing calls that now return their error
The branch's placement change (placing the model returns its error) made world_state, home_camera, bounds, open_sketch_plane, the scene builders, to_local and auto_operation return a Result. Main added callers of them since the branch left it; they now take the error as the branch's own callers do: - engine: commands pass it on (`?`); helpers answering yes/no or "found" (snap points, a face's normal, the DXF export check) answer no for a model that cannot be placed. Frames keep the session for main's lazy body frames (#6356) beside the placed model the picks are on; a library apply maps its targets on that placed model. Before an extract or a link is replaced, the placed model is taken or the command fails. - ui: panels, picks, dialogs and previews read the placed model through open_meshing::session_world (none when it cannot be placed: the viewport says why); Home and Fit frame nothing then. - cli: the usage table is main's, with kernel-cases in it (a resolution of the rig's commit had kept the branch's whole file). - tests read the Results with unwrap, and main's tests of Body::tessellate mesh through Body::mesh. Main's test of saved boolean retries goes (the branch saves none), as does the thread half of its dialog rendering test (the branch's thread dialog has its own); the tapped hole half stays. - What no caller uses after the merge goes: a mesh body's span, the metric thread refusal text, and the revolve's targets-as-shown model (main used it for the coplanar run-on the branch removed). Main's SolidWorks Y-up test reads the exporting system's name (the branch's STEP header has no preprocessor or description fields). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9a79588575 |
doc, engine, ui: placing the model returns its error; placements are checked where they are set
doc: world_state, world_state_reusing, state_in_frame_at, state_in_frame, face_point_state, face_point_names and construction_state return Result. A body that could not be placed, a frame that could not be inverted, a sketch plane or thread axis that did not survive the placement, or a failed placing worker used to leave things where they were without a word; now the call fails with what could not be placed. is_placement is the one test of an occurrence's placement (finite, a rotation that does not mirror, a translation within 1e9 mm). Opening a design names every occurrence that fails it; add_occurrence refuses one; a joint solution that would place an occurrence outside one is not applied and the joints placing it report it. engine: Session::world_state returns Result and keeps a failure in its cache as it keeps a placed model. bounds, home_camera, open_sketch_plane, the scene builders, the world previews, frames::to_local and auto_operation pass the error on; helpers answering "not found" take the placed model from their caller. Commands setting a placement check it (valid_position, exploded view, fastener at a point, STEP insert matrix). ui: panels, picks and hovers read the session's placed model through open_meshing::session_world; a model that cannot be placed shows no placed bodies, and the viewport says why across its bottom. Pictures and the control channel report the error. cli, mcp: snapshots, renders, benches and the oracle report the error; the kernel-case rig records it as the case's failure. Tests read the new Results with unwrap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt |
||
|
|
efa2cae0b4 |
Viewport: draw faded and see-through bodies from their plans with OIT (#7423)
* Viewport: palette-indexed scene and incremental appearance updates - Move triangle, line and instance colours and opacity into a per-scene palette (an R32Uint texture, WebGL2-safe); appearance edits update palette entries instead of vertex bytes. - Build CPU body triangles as one canonical vertex stream per block with opaque/glass/faded index lists; an opacity class change rewrites only the index list. - Cache resolved body appearances by a per-body key, so an edit resolves only the bodies whose look changed. - Split the model scene key from the session revision: selection and view-only commands no longer rebuild or upload the model scene. - Replace the O(n^2) section-index lookup and per-placement instance scan with hash lookups. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: skip unchanged palette work when rebuilding - Reuse each body's appearance key while the document is unchanged. - Leave a palette slot alone when its value did not change, and allocate every body's slots once before the build loop. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: measure scene rebuild cost by edit kind An ignored scale test times the scene build after selection, appearance, theme and one-body geometry edits at 200, 1,000 and 5,000 bodies. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: read faded grid alphas through the scene palette The grid-fade tests now resolve line palette indices instead of reading the line record's old colour byte. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: measure rebuild cost on few large meshes Adds the 20/100-torus case where a block rebuild used to re-emit a large part of the model. Co-Authored-By: Claude Code <noreply@anthropic.com> * Viewport: measure rebuild cost on an assembly Unique detailed parts plus one component placed many times, timed for selection, part and component colour, opacity, theme, hide and move. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw block classes as vertex runs, not index lists A body's vertices are three per triangle in mesh order, so each draw class is a few runs of the block's vertex buffer: all-opaque blocks need no index buffer, and an opacity class change uploads nothing. A fragmented class (more than 64 runs) falls back to one index buffer. Each triangle is written as one record into a block reserved up front, which takes the cold scene build of a 7.1M-triangle assembly from 97 ms to 55 ms (main: 83 ms). Also fix reindexing a block whose bodies are drawn elsewhere: it walked the mesh's triangles from that body's start, past its own vertices. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw the highlight's own block, and light faded bodies without copies The highlight scene keeps its feedback (a hovered face, a body copied on the CPU) in a block of its own; since blocks became vertex runs, only the model's blocks were drawn, so that feedback was uploaded and never shown. Draw the highlight's blocks with its triangles. Whole faded and see-through bodies (another component active, or an appearance below full opacity) were lit by copying every triangle on the CPU at each hover change: 85 ms for a design row of 812 bodies. They are now drawn again from the model's own block vertices, in the highlight palette with their slots set to the highlight colour, or as placements of the model's shared triangles. The picture is the same as the copy's. Adds a GPU frame benchmark for document-tree hover (ignored test). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: count scene uploads, and keep the sorted glass stream across colour edits Renderer::uploads reports the bytes the model scene's last change uploaded (geometry, placements, palette rows, planned colours, re-evaluated vertices). Without order-independent transparency the global glass stream is kept while the blocks' see-through triangles are the same, so a colour edit on a glass body uploads palette rows only. Tests assert both on a GPU. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: keep palette slots and looks without rehashing every body A rebuild found every body's palette slots by name and wrote them back, allocating and hashing a new key per body, and copied every shown name into a set to check the arena still belongs to the design. Slots are written back only when a body's faces grew, and the looks cache is pruned only when it holds more bodies than are shown. Adds the STEP-file benchmark (SOLIDCRAFT_SCALE_STEP) and the colour command's own time to the assembly benchmark. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: round-pick construction lines through the scene palette The axis and centre feedback for round picks (#4610) drew with a raw colour; on the palette scene it is interned once like the other construction geometry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Viewport: draw faded and see-through bodies from their plans with OIT A body faded outside the active component, or see-through, left the GPU tessellation path and was built triangle by triangle on the CPU, so working in a component of a large assembly rebuilt every other body. Where the renderer blends see-through surfaces order-independently (GpuTarget::oit, set by the renderer), a body whose faces share one class is drawn from its plan: chunks are split by class, opaque passes, AO and the section draw only opaque chunks, and the OIT pass draws the rest. The sorted fallback keeps them on the CPU. The model and its highlights decide through one rule (model_plan_class). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com> |
||
|
|
c6d361347f |
Section Analysis: the cap is marked by true depth, so far edges no longer take a cap band (#6328) (#6332)
With a section shown, the marking pass decided where the cap shows (the stencil) and wrote the depth everything after it tests against. #1768 gave it the faces' FACE_BIAS for the second job, so edges draw over their own faces (#1434). For the first job its slope part is unfair: next to an edge where a back face seen through the cut meets a front face, the front face won a band about a pixel wide although the back face is nearer. The cap skipped that band, and the edge line showed through the cut. #6363 marked those samples again from the back faces, pulled toward the eye as far as FACE_BIAS pushes. That closes the gaps beside the edges, but the pull also lets back faces win wherever they lie within the push of a front face, along every body's far silhouettes, and the cap hatches that band. On bherbruck's block, the band away from the cut went from 58 px orthographic and 534 px perspective before #6363 to 618 and 780 with it. In the app, his filleted hub showed it in every frame of a 36-step orbit in both projections. This replaces that pass. While a section is shown the opaque model now draws in four steps (`Cut`): 1. mark: the faces by their true depth (no push): colour, the stencil and depth; 2. a triangle over the viewport sets the depth back to the far plane, colour and stencil kept; 3. push: the faces again with FACE_BIAS, depth only, so the depth is what unsectioned frames have and edges draw over their faces as before; 4. cap: depth only, as #6728 made it; the mark pass has drawn the cap's colour and hatch, as fs_solid draws a back face seen through the cut. The window pass's depth reset and this one are one helper, `depth_reset_pipeline`, for either depth direction, and its passes are built by #6728's `solid_writes`. Unsectioned frames are unchanged. The CPU rasterizer already chose the cap by true depth. Tests (crates/gpu/tests/depth.rs), with the device's float depth and the 24-bit fallback: - a_cut_hides_the_edges_behind_it (new): bherbruck's block cut at y = -16, home view, orthographic and perspective. No edge shows through the cap, and away from the cut the picture is a box of just the kept part's: 0 px orthographic and 1 perspective (main: 618 and 780). - bherbruck's pocket and hub tests from #6363 are kept and pass (pocket 0 px; hub 1 and 2 px over its twelve views, as with #6363's pass). - an_edge_on_a_face_draws_whole_at_any_angle and an_edge_just_behind_a_face_stays_hidden_on_a_large_design also run with a section shown. In the app (safe mode, WARP), with 625 patterned cylinders cut by a section, the frame time is that of main (#6363): 33.5 against 34.3 ms at the home view, 34.1 against 35.2 ms with the model filling the view. Co-authored-by: bherbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4ced1d7bcf |
Viewport: the grid fades with the distance instead of cutting off (#4214) (#4629)
* claim: #4214 * Viewport: the grid fades with the distance instead of cutting off (#4214) The ground grid stopped at a fixed distance from the view, so its edge showed as a cut across the picture. It now fades out with the distance from the middle of the view, and it is gone before either of the two lines that used to cut it: its own edge, and the picture's far plane. Each grid line is drawn in pieces, and each piece is as faint as the fade makes it at the distance where it lies. The 'under' batch is drawn by the overlay pipeline with alpha blending, so the colour's alpha reaches the frame. * The headless grid fades with the distance too (#4214) The headless path (solidcraft-cli snapshot, the home-page thumbnail, the MCP screenshot) drew the grid from the engine's palette, where a line had no alpha: the grid still ended in a cut, and at a low camera angle the cut was in the picture. A SceneLine now carries an alpha, the CPU rasterizer blends with it and the GPU capture passes it on, so the engine's grid can fade. The fade itself moves to the engine, next to the grid's other geometry, and both paths use it: the headless grid now reaches as far on the ground as the view is wide (the ground stretches as it is seen at a slant) and dissolves into the distance instead of ending in a line. * Fix the headless/viewport grid fade divergence (#4214) The engine stretched the grid's size with the slant of the plane it is seen at, the viewport stretched it only on the ground, so on a sketch's plane the picture's grid reached further than the window's (153.42 mm against 120.00 mm). Both now share one grid_ext, which the picture and the window draw the same grid from. * The grid fades out before the picture's far plane cuts the ground (#4214) The window's grid faded against a far plane of its own: the scene's radius clipped by the projection's camera (260 mm away at 400 mm of distance), while the picture itself cuts the ground at the far plane of its own projection (223.7 mm at the same distance, because the projection frames the scene's bounds and not its radius). The grid was still a third of its strength where the picture cut the ground, so the cut showed as a straight line across the view. The fade now ends at the far plane the picture's projection uses, and the grid is gone before that plane cuts the ground. The test that watched the fade now measures the ink of each row of the picture, and checks that the grid is already gone in the ten rows above the row where the far plane cuts the ground: the point it compared before lay beyond that plane, where both renders draw nothing at all, so the comparison was always true. |
||
|
|
13b4f6e98c |
Viewport: a selected edge's highlight no longer shows as a wedge on a grazing face (#3544)
* Viewport: lift selected and hovered edge highlights toward the eye A selected edge's highlight (3 px core, 6 px halo) is a screen-space band that was depth-tested at the edge's own depth. A face next to the edge seen at a grazing angle is pushed back by only about a pixel of its slope, so it buried part of the band, unevenly along the edge: the highlight showed as a thin wedge instead of a line. The band is now drawn like a thin cylinder around the edge: its depth is pulled toward the eye by half its width plus a pixel, measured on screen so it holds at every zoom. Plain model edges keep their depth (#1434 still holds); the part of a highlighted edge the model really hides stays dimmed through hidden_line. Not yet compiled or tested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Viewport: lift an edge highlight by how steeply its faces are seen The first lift (half the band's width plus a pixel, the same on every edge) was not tied to the faces beside the edge. Each highlight segment now carries the normals of the two faces it borders (octahedral, packed with its width in the line's width slot, read as u32 by vs_line): the band is pulled toward the eye by its half width times how steeply those faces are seen, so a grazing face no longer buries it, and an edge seen square to its faces is not lifted at all. Test: a_selected_edge_on_a_grazing_face_draws_whole (tilts 60 to 88 degrees, small and large designs, orthographic and perspective; the band 5 mm behind a face stays hidden). Capturer::rgba_highlighted draws a highlight scene as the viewport does, for that test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2741cd9a8b |
Section Analysis: edges behind the cut no longer show through the cap (#6328) (#6363)
Since #1768 the section's stencil marking draws every face with FACE_BIAS. Where a back face seen through the cut meets a front face along an edge (a pocket's wall and its side wall or floor, a fillet and the face it runs into), the slope push decided which was nearer beside that edge; a front face winning left those samples unmarked, the cap skipped them, and the edge, drawn at its own depth, showed through the hatch. In perspective, and while orbiting in orthographic too, edges popped in and out from frame to frame. A second marking pass draws the back faces only (front faces culled, depth test <=, no depth write), pulled toward the eye as far as FACE_BIAS pushes faces back, before the cap. The depth buffer keeps FACE_BIAS, so edges on visible faces still draw whole (#1434). Tests in crates/gpu/tests/depth.rs: a pocket 2 mm behind the cut, and a filleted hub with a bore and a cross hole seen from twelve directions, both depths, orthographic and perspective. On main the pocket shows 45 px of edges through the cap in perspective and the hub 25 px over the views; with this change 0 and at most 2. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
26f42ae09b |
Snapshot: draw a see-through appearance see-through, and show a tool body inside its target (#2329) (#2330)
* Snapshot: draw a see-through appearance see-through, and give the CLI --body, --tool and --section A headless picture dropped a body's opacity: the scene carried only a colour, so a design with a translucent appearance was drawn opaque by `solidcraft-cli snapshot`, by MCP screenshots and in a design's thumbnail, although the window has always drawn it as glass. There was then no way to look at the body a cut would remove inside the material it meets: only a volume to measure and reason about, which hides exactly the errors a picture makes obvious (a tool that stops short, or lands in the wrong place). - `SceneMesh` carries the body's opacity; `view::build_scene` takes it from the design (`model_body_opacity`), and a selected body stays solid so the selection colour reads. - The GPU capture routes a see-through body into the scene's glass at its own alpha, as the viewport does; the CPU rasterizer draws the solid bodies first (they own the depth buffer), then the see-through ones blended over them, far sides before near sides and without writing depth, so what lies inside shows and a line between the two is not hidden. - `snapshot --body NAME:opacity=0.3,color=#rrggbb`, `--tool NAME` (that body solid in the tool colour, the rest see-through) and `--section z=27` run the commands the app itself runs (`appearance.assign`, `inspect.section`): the options are shortcuts, not a second renderer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tests: measure the tool colour as it is drawn through a see-through target The tool-colour filter was derived on paper and demanded a red more than twice either other channel, which the target in front of it tints away (measured: (200, 108, 85) through opacity 0.3); and the colour check painted the tool, which a solid target hides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fmt * Snapshot options: strip the colour's # rather than slicing it; README Slicing `value[1..]` on an input-derived string is what the house rules ask us not to write, even where a length check has already made it safe. The error a failed assignment reports now names the body rather than claiming it came from --body, since --tool reaches it too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * --tool: assign the bodies around the tool in groups, not one command at a time Each appearance.assign is an undo step with a document snapshot behind it, so one per body made --tool cost grow with the size of the design for no reason: the bodies around the tool all get the same opacity, and the ones that share a colour can be named in one call. A design whose bodies all wear the default grey now costs two commands whatever its size. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Rasterizer: say where its glass and the GPU's differ Splitting each see-through body by facing orders its own two layers; it does not sort across bodies, which the GPU does. Worth stating rather than leaving a reader to find it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: bherbruck <brennen.herbruck@gmail.com> |
||
|
|
c5f3515073 |
Viewport: hidden edges no longer show through faces, and thin or coplanar faces stop z-fighting (#1434, #1739) (#1768)
Thanks @CamWight. |