pub struct EngineState {Show 14 fields
pub scene: RenderScene,
pub camera: ViewCamera,
pub controls: ArcballControls,
pub settings: RenderSettings,
pub emphasis: Emphasis,
pub widgets: WidgetRegistry,
pub history: History,
pub metadata: MetadataStore,
pub settings_generation: u64,
pub dirty: bool,
pub ref_select: Option<RefSelectState>,
pub selection_filter: SelectionFilter,
pub transform_gizmo: TransformArm,
pub component_move: ComponentMoveArm,
/* private fields */
}Fields§
§scene: RenderScene§camera: ViewCamera§controls: ArcballControls§settings: RenderSettings§emphasis: Emphasis§widgets: WidgetRegistryIn-scene overlay widgets: datums/dimensions/curves, transform gizmo, ViewCube — fed as JSON, drawn by the render core’s overlay pass.
history: HistoryThe engine-owned editable model recipe (ordered features + rollback
index) — the SINGLE source of truth for the model. The UI never keeps its
own copy; it mutates/reads this through the history_* / feature methods.
metadata: MetadataStoreThe Properties-panel metadata store: user attributes keyed by OBJECT NAME
(solid / face / edge kernel name), NOT feature id — so a record survives
feature edits as long as the object’s name persists. Persisted with the
model (a top-level metadata field in the history document); see the
crate::metadata module for the store + the object-info/measurement API.
settings_generation: u64Bumped whenever settings change so the renderer re-derives per-solid base styles (a cheap key, not a per-frame diff).
dirty: boolThe engine sets this whenever the camera/scene/emphasis changed; the presentation shell renders only when it is set (R22 on-demand render — the OrthoCameraIdle matrix-compare analogue, made explicit).
ref_select: Option<RefSelectState>The modal reference-selection state (the ref-select widget). Some while
the user is picking references for a feature-dialog field; None
otherwise. The picked-name list here is the SINGLE source of truth while
active (the UI reads it back; the viewport appends to it on a pick).
selection_filter: SelectionFilterWhich entity KINDS a plain viewport click may select (the selection
filter, mirroring the earlier SelectionFilter.allowedSelectionTypes). select_top_at
consults it via pick_filtered; see the appended SelectionFilter impl
block near the end of this file for the state + honoring logic.
transform_gizmo: TransformArmThe transform-controls gizmo controller: which feature (if any) has the move/rotate gizmo armed (via the in-viewport center-sphere toggle), plus the in-flight handle drag. All the arm/drag/apply logic lives in the appended transform-gizmo impl block near the end of this file.
component_move: ComponentMoveArmThe COMPONENT Move gizmo controller (assemblies §8.5): which ACOMP
instance has the bbox-center move/rotate gizmo armed, the translate/
rotate cycle mode, and the commit-on-release drag. Exclusive with
transform_gizmo (shared widget slot). See component_move.rs.
Implementations§
Source§impl EngineState
impl EngineState
Sourcepub fn history_has_assembly(&self) -> bool
pub fn history_has_assembly(&self) -> bool
Whether the current document is an ASSEMBLY document: any ACOMP-typed
feature, or a present assembly constraint block. Componentless
documents skip every main-side sync (zero cost for modeling files).
Sourcepub fn assembly_components(&self) -> &[ComponentRecord]
pub fn assembly_components(&self) -> &[ComponentRecord]
The scene’s component records (deterministic id order) as of the last
[sync_assembly] — the Assembly Structure tree’s projection source.
A VIEW over the scene, never an owning structure.
Sourcepub fn ensure_assembly_synced(&mut self)
pub fn ensure_assembly_synced(&mut self)
Make sure the main-side assembly session + component projection are
current with the last APPLIED display run. Cheap no-op when already
synced (or for componentless documents). Panels call this at frame
start; the post-run tail (finish_apply) also syncs eagerly.
Sourcepub fn assembly_statuses_value(&mut self) -> Value
pub fn assembly_statuses_value(&mut self) -> Value
The per-constraint status rows ([{id, type, enabled, open, status, message, satisfied, error}]) from the main-side session.
Sourcepub fn assembly_state_value(&mut self) -> Value
pub fn assembly_state_value(&mut self) -> Value
The current assembly block (post-solve): {constraints, idCounter}.
Sourcepub fn assembly_dof_value(&mut self) -> Value
pub fn assembly_dof_value(&mut self) -> Value
The last solve’s DOF/diagnostics summary ({ok, dof, rank, redundant, …} — movedSolids may be absent; tolerate it).
Sourcepub fn assembly_overlay_value(&mut self) -> Value
pub fn assembly_overlay_value(&mut self) -> Value
Per-constraint overlay rows (world anchors/directions/status/value) — the constraints panel reads the evaluated value/unit for the distance/angle label suffix; lane G’s viewport graphics read the rest.
Sourcepub fn parts_library_names(&mut self) -> Vec<String>
pub fn parts_library_names(&mut self) -> Vec<String>
The parts-library entry names currently resident (insert-flow “existing
entries first” list). Main-side store — seeded by document ingest on
sync and grown by [insert_component].
Sourcepub fn assembly_add_constraint(
&mut self,
constraint_type: &str,
params_json: &str,
) -> Result<String, String>
pub fn assembly_add_constraint( &mut self, constraint_type: &str, params_json: &str, ) -> Result<String, String>
Add a constraint (params_json = inputParams; the kernel mints the id
from the type’s short name when absent). Returns the minted id.
Sourcepub fn assembly_update_constraint(
&mut self,
id: &str,
params_json: &str,
) -> Result<(), String>
pub fn assembly_update_constraint( &mut self, id: &str, params_json: &str, ) -> Result<(), String>
Replace a constraint’s inputParams (the dialog commit).
Sourcepub fn assembly_remove_constraint(&mut self, id: &str) -> Result<(), String>
pub fn assembly_remove_constraint(&mut self, id: &str) -> Result<(), String>
Delete a constraint.
Sourcepub fn assembly_set_constraint_enabled(
&mut self,
id: &str,
enabled: bool,
) -> Result<(), String>
pub fn assembly_set_constraint_enabled( &mut self, id: &str, enabled: bool, ) -> Result<(), String>
Enable/disable a constraint (the row checkbox).
Sourcepub fn assembly_set_constraint_open(
&mut self,
id: &str,
open: bool,
) -> Result<(), String>
pub fn assembly_set_constraint_open( &mut self, id: &str, open: bool, ) -> Result<(), String>
Persist WHICH constraint has its dialog open (view state — SILENT fold,
no solve, no rerun, no undo entry). ACCORDION: at most ONE constraint is
open — opening one first closes every other inside the same silent fold,
so the panel toggle, the context bar’s add-from-selection, and a viewport
label click all converge on a single open constraint. The constraints
PANEL reads this flag as its mode: open one and its form replaces the
tree (panels::assembly_constraints), which is why every one of those
surfaces opens the dialog without knowing the panel exists.
Sourcepub fn assembly_move_constraint(
&mut self,
id: &str,
index: usize,
) -> Result<(), String>
pub fn assembly_move_constraint( &mut self, id: &str, index: usize, ) -> Result<(), String>
Reorder a constraint to index (drag-reorder).
Sourcepub fn assembly_run_solve(&mut self) -> Result<(), String>
pub fn assembly_run_solve(&mut self) -> Result<(), String>
Manual solve (the panel’s Solve button): solve the session, fold, and ALWAYS re-run the display (that is the point of pressing Solve — it works with auto-solve disabled).
Sourcepub fn insert_component(
&mut self,
insert: ComponentInsert<'_>,
) -> Result<String, String>
pub fn insert_component( &mut self, insert: ComponentInsert<'_>, ) -> Result<String, String>
Insert a component instance (the palette/insert flow): resolve the
parts-library entry (add or reuse), refresh the document’s
partsLibrary block, append an ACOMP feature referencing the RETURNED
effective part name with an identity transform, and re-run. The FIRST
component of the document writes isFixed: true EXPLICITLY (dialog-
visible); later instances write false. Returns the new feature id
(ACOMP<digits> — the history’s global counter mints that exact form).
Sourcepub fn set_component_fixed(
&mut self,
component_id: &str,
fixed: bool,
) -> Result<(), String>
pub fn set_component_fixed( &mut self, component_id: &str, fixed: bool, ) -> Result<(), String>
Fix/Unfix a component: toggles the OWNING ACOMP feature’s
inputParams.isFixed (one truth, one undo lane) and re-runs.
Sourcepub fn select_component(&mut self, component_id: &str)
pub fn select_component(&mut self, component_id: &str)
Select a component in the viewport: emphasis over exactly its member solids (the tree↔viewport sync lane; a viewport pick of any member lights the tree row through the same emphasis set).
Sourcepub fn component_member_solids(&self, component_id: &str) -> Vec<String>
pub fn component_member_solids(&self, component_id: &str) -> Vec<String>
A component’s member SOLID scene names (empty for an unknown id) — the selection/hover unit COMPONENT entries resolve to.
Sourcepub fn toggle_component_selection(&mut self, component_id: &str)
pub fn toggle_component_selection(&mut self, component_id: &str)
TOGGLE a component in the current selection as ONE unit (the additive Ctrl/Cmd+click under COMPONENT promotion): when EVERY member solid is already selected the whole set deselects, otherwise the whole set joins the selection — the rest of the selection stays.
Sourcepub fn select_components(&mut self, component_ids: &[String])
pub fn select_components(&mut self, component_ids: &[String])
Select SEVERAL components at once: emphasis over the union of their member solids (the interference window’s row click highlights both participants of a pair through this).
Sourcepub fn begin_ref_select_for_constraint(
&mut self,
constraint_id: &str,
path: Vec<String>,
label: String,
filter: Vec<String>,
multiple: bool,
seed_names: Vec<String>,
)
pub fn begin_ref_select_for_constraint( &mut self, constraint_id: &str, path: Vec<String>, label: String, filter: Vec<String>, multiple: bool, seed_names: Vec<String>, )
Enter the modal reference picker for an ASSEMBLY CONSTRAINT’s
elements-style field (same widget, different commit target — Finish
routes through Self::assembly_update_constraint_no_rerun instead of
feature params). No roll-to-before: constraints pick against the FULL
assembly.
Source§impl EngineState
impl EngineState
Sourcepub fn refresh_constraint_overlay(&mut self)
pub fn refresh_constraint_overlay(&mut self)
Rebuild the constraint-overlay cache from the LIVE kernel session and re-bake the drawn group. Cleared (empty group) while the Show Constraint Graphics setting is off or a sketch edit is active. A live handle drag’s preview survives the rebuild (re-applied onto the fresh cache).
Sourcepub fn refresh_constraint_overlay_from(
&mut self,
overlay_json: &str,
state_json: &str,
)
pub fn refresh_constraint_overlay_from( &mut self, overlay_json: &str, state_json: &str, )
Self::refresh_constraint_overlay with explicit payloads (the parsed
assembly_overlay_json array + assembly_state_json object) — the
testable seam: canned payloads exercise the whole cache/pick/drag path
without a kernel session.
Sourcepub fn ensure_constraint_overlay_current(&mut self)
pub fn ensure_constraint_overlay_current(&mut self)
Per-frame upkeep (the app viewport calls this once per frame): hide the
group while the setting is off / sketch mode is active, restore it when
they flip back, and re-bake when the camera zoom moved the
world_per_pixel materially (>0.5%) so the screen-constant arc/rod
sizing stays pixel-true. Re-bakes only on actual change, so a quiet
frame stays quiet (no dirty loop).
Sourcepub fn constraint_overlays(&self) -> &[ConstraintOverlay]
pub fn constraint_overlays(&self) -> &[ConstraintOverlay]
The cached overlay records (read-only view for the app’s label pass + tests).
Sourcepub fn constraint_labels_json(&self) -> String
pub fn constraint_labels_json(&self) -> String
The label feed for the app’s chip pass:
[{id, type, icon, text, status, message, color:[r,g,b], world:[x,y,z], draggable, selected}]. text leads with icon (the type’s glyph), so
the chip is a picture plus the measure; id is for the hover tooltip. One row per cached overlay with a resolvable label anchor
(the leader midpoint / arc mid-sweep / anchor midpoint). selected
marks the label-click-selected constraint (thicker chip border). Empty
while hidden.
Sourcepub fn constraint_hover(&mut self, id: &str)
pub fn constraint_hover(&mut self, id: &str)
Hover a constraint LABEL: highlight the referenced elements
(inputParams.elements) through the existing emphasis machinery —
faces/edges by kernel name, a {solid}@x,y,z vertex ref or a bare
component id by its owning solid(s). Deduped by constraint id so a held
hover never re-bumps the emphasis generation. Sets the one-frame
Self::take_constraint_label_hover flag either way so the viewport’s
scene-hover pass yields.
Sourcepub fn constraint_hover_end(&mut self)
pub fn constraint_hover_end(&mut self)
The pointer left the constraint labels: drop the element highlight (only if a label hover set one — never clobbers an unrelated scene hover).
Sourcepub fn take_constraint_label_hover(&mut self) -> bool
pub fn take_constraint_label_hover(&mut self) -> bool
Consume the one-frame “a constraint label is hovering elements” flag —
the viewport’s modeling hover branch skips its scene re-hover while set
(mirrors Self::take_sketch_list_hover) so the label-driven highlight
survives the frame without a per-frame clobber/re-apply dirty loop.
Sourcepub fn constraint_label_clicked(&mut self, id: &str)
pub fn constraint_label_clicked(&mut self, id: &str)
A constraint LABEL was clicked: SELECT that constraint (the chip gains
its selected accent, the context bar offers Delete constraint) and OPEN
it through the ACCORDION open (Self::assembly_set_constraint_open —
every other constraint closes, so the clicked one is the ONE open
constraint, which is what puts the panel into its dialog). Guarded on the
id existing in the live session (the fallible export’s error path would
abort off-wasm).
Sourcepub fn selected_constraint(&self) -> Option<String>
pub fn selected_constraint(&self) -> Option<String>
The constraint SELECTED via its viewport label (or None), pruned
against the live session — a deleted / undone constraint never lingers
as selected.
Sourcepub fn constraint_deselect(&mut self)
pub fn constraint_deselect(&mut self)
Drop the constraint selection (the Clear action, Esc, and the context
bar’s delete all route here — directly or via clear_selection).
Sourcepub fn constraint_arrow_pick(&self, x: f64, y: f64) -> Option<String>
pub fn constraint_arrow_pick(&self, x: f64, y: f64) -> Option<String>
Whether a screen-px pick lands on a draggable constraint handle; returns the grabbed constraint’s id (the NEAREST containing region wins). The viewport routes a drag that starts here into the constraint drag, and swallows a bare click so the solid behind the arrow isn’t selected.
Sourcepub fn constraint_drag_begin(&mut self, x: f64, y: f64) -> bool
pub fn constraint_drag_begin(&mut self, x: f64, y: f64) -> bool
Begin a constraint-handle drag at screen (x, y). Returns whether a
draggable handle was grabbed (the viewport then routes the drag here
instead of orbiting the camera).
Sourcepub fn constraint_drag_to(&mut self, x: f64, y: f64)
pub fn constraint_drag_to(&mut self, x: f64, y: f64)
Drag a grabbed constraint handle to screen (x, y): map the pointer to a
new value (distance: signed offset along the base-face normal for
plane-based rows, magnitude along the leader otherwise; angle: the
shared arc nearest-projection search, folded to the interior 0–180°),
update the PREVIEW (annotation + label track live), and re-bake. No
kernel call — the commit happens on Self::constraint_drag_release.
Sourcepub fn constraint_drag_commit_payload(&self) -> Option<(String, String)>
pub fn constraint_drag_commit_payload(&self) -> Option<(String, String)>
The pending commit (constraint id, inputParams JSON) a release would
send — the drag’s params snapshot with the dragged field set to the
preview value. None when no drag is live. (The pure half of
Self::constraint_drag_release, separated for tests.)
Angle display convention: the drag preview is the INTERIOR arc sweep
(what the arc draws and the kernel’s overlay value measures), but the
stored inputParams.angle is the DISPLAY angle — exterior-remapped when
the constraint’s exteriorAngle toggle is on (map_angle’s contract) —
so the commit remaps interior → 180 − interior for those.
Sourcepub fn constraint_drag_release(&mut self)
pub fn constraint_drag_release(&mut self)
Release the constraint-handle drag: COMMIT the previewed value via
assembly_update_constraint_json (auto-solves), consume the reply’s
movedSolids display seam (re-posed resident solids re-tessellate in
place), fold the solved poses back into the engine’s history document
(pose-authority contract, drag path), and refresh the overlay from the
post-solve session. A commit against a session that no longer has the
constraint (or no session at all — canned-payload tests, the native
thread-runner seam) drops the preview with a notice instead.
Sourcepub fn consume_assembly_moved_solids(&mut self, report_json: &str)
pub fn consume_assembly_moved_solids(&mut self, report_json: &str)
Consume a solve report’s movedSolids: [{name, handle}] display seam:
those resident solids were RE-POSED IN PLACE by the solver (their
producing feature replayed reused, so the run delta kept the stale
mesh) — re-tessellate each from its live resident handle and replace its
display, preserving per-solid view state (visibility, color override).
The key is absent on zero-mate reports; absence is tolerated.
Source§impl EngineState
impl EngineState
Sourcepub fn export_bom_csv(&mut self) -> Result<String, String>
pub fn export_bom_csv(&mut self) -> Result<String, String>
Export the assembly BOM as CSV: the exact partName,sourceKey,quantity
header, one line per parts-library entry, LF endings.
Sourcepub fn export_bom_json(&mut self) -> Result<String, String>
pub fn export_bom_json(&mut self) -> Result<String, String>
Export the assembly BOM as a JSON array of the same records — the CSV
sibling of Self::export_bom_csv.
Sourcepub fn part_attributes(&self, part_name: &str) -> Value
pub fn part_attributes(&self, part_name: &str) -> Value
Read a part’s attribute record ({} when the part has none / is
unknown). Never errs — a BOM row for a part mid-import simply shows
blanks.
Sourcepub fn part_source(&self, part_name: &str) -> Option<(String, String)>
pub fn part_source(&self, part_name: &str) -> Option<(String, String)>
A part’s (sourceKey, sourceSignature) — what the app’s write-through
lane needs to decide whether the file on disk is still the one this
entry was built from. None for an unknown part; the key is returned
even when EMPTY (embedded-only), because “” is exactly what the
write-through lane checks for.
Sourcepub fn part_document_json(&self, part_name: &str) -> Option<String>
pub fn part_document_json(&self, part_name: &str) -> Option<String>
A part’s embedded document as text — the payload the app writes through
to the part’s sourceKey after an attribute edit.
Sourcepub fn set_part_attribute(
&mut self,
part_name: &str,
key: &str,
value: Value,
) -> Result<(), String>
pub fn set_part_attribute( &mut self, part_name: &str, key: &str, value: Value, ) -> Result<(), String>
Write ONE part attribute. Value::Null (or an empty string) REMOVES the
key, so clearing a cell leaves no "" litter in the saved document.
§Why this is not just a document edit
The document’s partsLibrary block is a MIRROR of the kernel’s
main-side store, not the truth: sync_assembly re-serializes the store
over the block after every run, and the per-run request does not carry
the block at all (History::prefix_request omits it). So a change
written only into the block is erased by the next sync. This therefore
writes BOTH: the kernel store (via refresh_library_entry, which is the
same door edit-in-place and update-components use) and the document
block + undo checkpoint. Self::undo re-installs the rewound block
into the store, which is what makes the pair rewind together.
The snapshot is deliberately KEPT: an attribute is not geometry, so
there is nothing to re-evaluate. refresh_library_entry still marks the
entry dirty (its contract), so the ACOMP self-heal re-derives it on the
next run — correct, just not free. That is the price of the attributes
living on the part document, and it is why the panel commits a text cell
on focus-loss rather than per keystroke.
Sourcepub fn occurrence_attributes(&self, component_id: &str) -> Value
pub fn occurrence_attributes(&self, component_id: &str) -> Value
Read ONE occurrence’s attribute record ({} when it has none).
Sourcepub fn set_occurrence_attribute(
&mut self,
component_ids: &[String],
key: &str,
value: Value,
) -> Result<(), String>
pub fn set_occurrence_attribute( &mut self, component_ids: &[String], key: &str, value: Value, ) -> Result<(), String>
Write ONE occurrence attribute across component_ids — ONE undo step
however many ids there are.
The fan-out lane: a PACKED BOM row rolls up every occurrence of a part
whose occurrence data matches, and editing that row’s cell must apply to
all of them. One id (the unpacked case) is the same call with a
one-element slice, so there is no second code path to keep in step.
Value::Null / "" removes the key.
Source§impl EngineState
impl EngineState
Sourcepub fn ensure_overlays_current(&mut self)
pub fn ensure_overlays_current(&mut self)
Per-frame overlay upkeep — the ONE call the app viewport makes each frame
(see BREP_app/src/viewport/interaction.rs).
Everything fed through the general set_overlay channel is pre-expanded
into GPU vertices AT FEED TIME (see the “Why not one uniform feed” note in
crate::widgets), so — unlike the specialized widgets (transform gizmo,
datums, ViewCube), which are rebuilt against the LIVE camera every frame —
a baked overlay group keeps whatever screen-constant sizing it was baked
with. A ZOOM changes world_per_pixel and nothing else re-bakes them, so
the draggable gizmos keep their old pixel size — and where a handle’s world
position is ITSELF px × world_per_pixel (the angular arc), their old
POSITION too, drifting away from the live-computed grab region.
So: re-bake on a MATERIAL world_per_pixel change, keyed on that ONE
quantity rather than on any particular gesture. Every zoom path moves it —
the wheel, Self::zoom_to_fit, Self::standard_view (which fits), a
viewport Self::resize — so they are all covered without a per-path
hook. What does NOT move it needs no re-bake, and correctly gets none:
pan and orbit hold the eye→target distance, the ViewCube (face, corner AND
navigation arrow) is a fixed-pivot reorient, and
Self::toggle_projection preserves apparent size by construction
(ViewCamera::toggle_projection solves for the distance/half-height that
keeps world_per_pixel — see projection_toggle_preserves_apparent_size).
The baked buffers are world-space, so the GPU re-projects them for free.
Re-bakes only on actual change, so a quiet frame stays quiet (no per-frame
dirty loop).
Sourcepub fn zoom_to_fit(&mut self)
pub fn zoom_to_fit(&mut self)
Frame the whole scene (used right after the first history feed).
Sourcepub fn resize(&mut self, css_width: f64, css_height: f64)
pub fn resize(&mut self, css_width: f64, css_height: f64)
Update the CSS viewport size (used by all camera math). The physical framebuffer size + DPR are the presentation shell’s concern.
pub fn pointer_down(&mut self, x: f64, y: f64, button: i32) -> bool
pub fn pointer_move(&mut self, x: f64, y: f64) -> bool
pub fn pointer_up(&mut self) -> bool
pub fn wheel(&mut self, delta_y: f64, cursor: Option<[f64; 2]>) -> bool
pub fn set_controls_enabled(&mut self, enabled: bool)
pub fn toggle_projection(&mut self) -> &'static str
pub fn set_projection(&mut self, kind: &str)
pub fn standard_view(&mut self, name: &str) -> bool
pub fn camera_state_json(&self) -> String
pub fn apply_camera_state_json(&mut self, json: &str) -> Result<(), String>
pub fn world_per_pixel(&self) -> f64
Sourcepub fn world_to_screen_json(&self, points_json: &str) -> Result<String, String>
pub fn world_to_screen_json(&self, points_json: &str) -> Result<String, String>
Project world points to CSS-pixel screen coords for host anchoring. Input
is [[x,y,z], …]; output [[sx, sy, depth, inFront], …] where inFront
is 1 when a LABEL anchored at the point should draw
(crate::view::ViewCamera::label_anchor_visible, THE one label policy:
the point is projectable — ortho always, perspective unless at/behind the
eye plane, near/far NEVER cull — AND its projection lands inside the
viewport, so an off-screen anchor’s chip vanishes instead of clamping to
the viewport edge). Every app label pass (sketch dims, feature dims,
constraint chips, gizmo axis text) keys its skip off THIS flag, so the
policy lives in exactly one place.
Sourcepub fn camera_matrices_json(&self) -> String
pub fn camera_matrices_json(&self) -> String
The camera matrices for the host overlays’ per-frame world→screen /
screen→world hot path: { viewProj:[16], viewProjInverse:[16], viewport:[w,h] }. Both matrices are column-major (index =
col*4 + row); viewProj maps world → wgpu clip
(x,y in −1..1, z in 0..1) and viewport is the CSS-pixel size. This lets
dimensions + sketch drop the compat mirror camera and read the engine’s
own view-projection directly (see world_to_screen_json for one-shots).
Source§impl EngineState
impl EngineState
Sourcepub fn build_widget_overlay(&self) -> Option<WidgetOverlay>
pub fn build_widget_overlay(&self) -> Option<WidgetOverlay>
Build this frame’s overlay-widget geometry, or None when nothing is enabled (skips the overlay passes entirely).
Sourcepub fn fit_camera_and_overlay(&mut self) -> (Camera, Option<WidgetOverlay>)
pub fn fit_camera_and_overlay(&mut self) -> (Camera, Option<WidgetOverlay>)
Fit the per-frame depth window to EVERYTHING drawn, then resolve the GPU
camera — the ONE path both frame loops (wasm Engine::render, desktop
redraw) use so they can’t drift. The overlay is built FIRST, then its
WORLD bounds are folded into the fit: near/far never affect the overlay
geometry (it depends only on view direction + world_per_pixel), so
building it before the fit lets construction geometry — datum planes,
world axes, frames, the transform gizmo — be bracketed by the depth
window instead of clipping against the solids-only bounds. The world
ORIGIN is always folded in too, so the origin triad stays bracketed even
when every geometry channel is momentarily empty (an all-empty frame then
yields a tiny origin-centred window — harmless, re-fit next frame). The
ViewCube is excluded (it draws with its own mini-camera; see
WidgetOverlay::world_bbox). Returns the resolved camera + the built
overlay for the frame to hand to the render core.
pub fn set_datums_json(&mut self, json: &str) -> Result<(), String>
Sourcepub fn set_overlay_json(&mut self, json: &str) -> Result<(), String>
pub fn set_overlay_json(&mut self, json: &str) -> Result<(), String>
Feed the general overlay geometry channel (set_overlay): arbitrary named
tri/line/point groups (feature-dialog previews and other display-only
geometry), drawn in the widget overlay pass.
pub fn set_dimensions_json(&mut self, json: &str) -> Result<(), String>
pub fn set_transform_json(&mut self, json: &str) -> Result<(), String>
pub fn set_viewcube_enabled(&mut self, enabled: bool)
Sourcepub fn viewcube_rect_json(&self) -> String
pub fn viewcube_rect_json(&self) -> String
The ViewCube corner rect {x,y,w,h} (CSS px) so the host can decide
whether to forward a pointer event.
Sourcepub fn viewcube_hover(&mut self, local_x: f64, local_y: f64) -> bool
pub fn viewcube_hover(&mut self, local_x: f64, local_y: f64) -> bool
Update the ViewCube hover from cube-local pixels; returns whether it
changed (a hover-out is (None) with local coords outside).
pub fn viewcube_clear_hover(&mut self) -> bool
Sourcepub fn viewcube_click(&mut self, local_x: f64, local_y: f64) -> bool
pub fn viewcube_click(&mut self, local_x: f64, local_y: f64) -> bool
Click the ViewCube at cube-local pixels: snap the shared camera to the region’s standard view (keeping the current pivot distance). Returns true if a region was hit.
Sourcepub fn datum_pick(&self, x: f64, y: f64) -> String
pub fn datum_pick(&self, x: f64, y: f64) -> String
Pick the datum plane/axis under a screen pixel; returns its name (empty when none).
NOT the selection path any more: construction planes are ordinary pick
candidates (Self::pick_candidates_at → the widget’s datum_plane_hits,
which reports EVERY card the ray crosses rather than the first), so the
viewport click router no longer calls this. It survives as the AXIS-aware
second line of defense inside Self::ref_select_click’s total-miss arm.
Sourcepub fn transform_hover(&mut self, x: f64, y: f64) -> u32
pub fn transform_hover(&mut self, x: f64, y: f64) -> u32
Update the transform-gizmo hover from a screen pixel; returns the handle under the pointer (0 = none). Marks dirty when the highlight changed.
Sourcepub fn transform_pick(&self, x: f64, y: f64) -> u32
pub fn transform_pick(&self, x: f64, y: f64) -> u32
The transform-gizmo handle under a screen pixel (0 = none) — the host echoes it back to start a drag.
Sourcepub fn transform_drag(
&mut self,
handle: u32,
sx: f64,
sy: f64,
cx: f64,
cy: f64,
) -> String
pub fn transform_drag( &mut self, handle: u32, sx: f64, sy: f64, cx: f64, cy: f64, ) -> String
Compute a transform drag (frame-space + world delta) as JSON for the feature-edit commit. Marks the handle active for the highlight.
pub fn transform_drag_end(&mut self)
Sourcepub fn dimension_anchors_json(&self) -> String
pub fn dimension_anchors_json(&self) -> String
Per-dimension label placement: [{id, anchor:[x,y,z], screen:[sx,sy,inFront]}] — the host pins each text label at screen.
Source§impl EngineState
impl EngineState
Sourcepub fn refresh_committed_sketches(&mut self)
pub fn refresh_committed_sketches(&mut self)
(Re)build the persistent committed-sketch SHEET SOLIDS. For every committed
sketch that should show — committed_sketch_ids
minus [hidden_sketches] — synthesize its display from the run’s solved
profile AND its own model segments, and insert it as a scene solid (keyed by
the sketch id, dim-cyan, flagged is_sketch); remove any sheet inserted on
the PREVIOUS refresh but not this one (rolled back, deleted, hidden, or
became the active edit). A sketch that closes a region gets its planar sheet;
one that closes NOTHING (an open chain — the single line of the 2026-09-02
report) still draws its segments as named edges, so it is visible and
pickable instead of vanishing; one holding ONLY points (a hole-placement
sketch) draws them as vertices, so it too is visible, listed and pickable
(a vertex hit carries its owning sketch, which the SKETCH pick lane
admits). Only a sketch with no drawable geometry at all (empty /
construction-only) is skipped. Marks dirty.
Sourcepub fn sketch_visible(&self, id: &str) -> bool
pub fn sketch_visible(&self, id: &str) -> bool
Whether the committed sketch id’s persistent overlay is shown (absent from
[hidden_sketches] = visible).
Sourcepub fn set_sketch_visible(&mut self, id: &str, visible: bool)
pub fn set_sketch_visible(&mut self, id: &str, visible: bool)
Show/hide the committed sketch id’s persistent overlay (the Scene-tree
checkbox). Toggles [hidden_sketches], rebuilds the committed overlays (so the
group is fed or cleared immediately), and marks dirty.
Sourcepub fn committed_sketches(&self) -> Vec<(String, bool)>
pub fn committed_sketches(&self) -> Vec<(String, bool)>
The committed sketches to list in the Scene tree: every "S" feature at the
current rollback (minus the active edit), each with its live visibility — the
ordered (id, visible) list the Scene panel snapshots.
Sourcepub fn sketch_entities_json(&self) -> String
pub fn sketch_entities_json(&self) -> String
The committed sketches as JSON ([{"name":<id>,"visible":<bool>}]) — the
sibling of scene_entities_json the Scene panel
publishes for the headed verifier (kept a SEPARATE method so the solids array’s
shape is unchanged).
Source§impl EngineState
impl EngineState
Sourcepub fn component_move_armed(&self) -> bool
pub fn component_move_armed(&self) -> bool
Whether the component Move gizmo is armed (for any component).
Sourcepub fn component_move_armed_feature(&self) -> String
pub fn component_move_armed_feature(&self) -> String
The armed component feature id (empty when disarmed).
Sourcepub fn component_move_toggle(&mut self, feature_id: &str)
pub fn component_move_toggle(&mut self, feature_id: &str)
The Move toggle (context bar / tree action): ARMS the full gizmo (all
handle sets) for feature_id, or DISARMS when it is already armed
(arming fresh replaces any other armed component). A FIXED component
refuses with a toast and never arms (spec §8.5).
Sourcepub fn component_press(&mut self, x: f64, y: f64) -> bool
pub fn component_press(&mut self, x: f64, y: f64) -> bool
Begin a component-gizmo drag at viewport px (x, y); true when a
handle was grabbed (the viewport routes the drag here, not the camera).
Sourcepub fn component_move_dragging(&self) -> bool
pub fn component_move_dragging(&self) -> bool
Whether a component-gizmo drag is in flight.
Sourcepub fn component_drag_to(&mut self, cx: f64, cy: f64)
pub fn component_drag_to(&mut self, cx: f64, cy: f64)
Continue the drag: resolve the world delta against the FROZEN grab frame, compose the pending pose, and move ONLY the visible gizmo (free move — the mesh follows on release, when the commit re-runs + re-solves).
Sourcepub fn component_release(&mut self)
pub fn component_release(&mut self)
End the drag: COMMIT the pending pose into the ACOMP’s
inputParams.transform (one param write → one undo entry → one rerun
whose constraint tail re-solves; the post-run sync then re-glues the
gizmo to wherever the solve left the component). A grab that never moved
commits nothing.
Sourcepub fn component_move_json(&self) -> String
pub fn component_move_json(&self) -> String
The armed component gizmo’s logical state for the verifier:
{armed, feature, anchor}.
Source§impl EngineState
impl EngineState
Sourcepub fn component_of_solid(&self, solid_name: &str) -> Option<String>
pub fn component_of_solid(&self, solid_name: &str) -> Option<String>
The OWNING component feature id of a scene solid — the OUTERMOST
ACOMP<digits>: namespace segment of its name, verified against the
history (the segment must be an ACOMP feature of THIS document; a nested
chain’s inner segments belong to the sub-assembly’s own document).
None for ordinary modeling solids (no prefix) and for sketch-child
names (S1:G20 — S1 is not an ACOMP segment).
Sourcepub fn component_ids(&self) -> Vec<String>
pub fn component_ids(&self) -> Vec<String>
Every ACOMP feature id in history order (the structure tree’s row order).
Sourcepub fn component_info(&self, feature_id: &str) -> Option<ComponentInfo>
pub fn component_info(&self, feature_id: &str) -> Option<ComponentInfo>
The derived ComponentInfo for an ACOMP feature id (None when the id
is missing or not an ACOMP feature).
Source§impl EngineState
impl EngineState
Sourcepub fn datum_feature_for_name(&self, name: &str) -> Option<(String, String)>
pub fn datum_feature_for_name(&self, name: &str) -> Option<(String, String)>
The producing (feature id, feature type) of a datum/plane frame NAME, but
ONLY when the name is an actually-resolved D/P frame at the current rollback
— the provenance the Properties Info tab reports for a selected datum.
Sourcepub fn refresh_construction_datums(&mut self)
pub fn refresh_construction_datums(&mut self)
(Re)build the persistent construction datum/plane overlays. Feeds every D/P
frame the last run resolved (minus [hidden_datums]) to the datum-plane
widget channel as a screen-constant NAMED plane in the calm datum color — or
the selection accent when it is in emphasis.selected_datums / hovered when
it is in emphasis.hovered_datums (hover wins, the EmphasisState order).
The feed
REPLACES the widget’s datum set wholesale, so a departed/hidden/rolled-back
plane is auto-dropped; shown_datum_names mirrors what was fed. Marks dirty.
The fed set is also exactly what is PICKABLE: plane_candidates_at hit-tests
these cards, so a hidden or rolled-back plane can no more be picked than it
can be seen.
Sourcepub fn datum_visible(&self, name: &str) -> bool
pub fn datum_visible(&self, name: &str) -> bool
Whether the construction datum/plane name’s plane is shown (absent from
[hidden_datums] = visible).
Sourcepub fn set_datum_visible(&mut self, name: &str, visible: bool)
pub fn set_datum_visible(&mut self, name: &str, visible: bool)
Show/hide the construction datum/plane name’s plane (the Scene-tree
checkbox). Toggles [hidden_datums] and re-feeds the datum planes so the
plane appears/disappears immediately.
Sourcepub fn construction_datums(&self) -> Vec<(String, bool)>
pub fn construction_datums(&self) -> Vec<(String, bool)>
The construction datums/planes to list in the Scene tree: every D/P frame at
the current rollback, each with its live visibility (hidden ones included,
like committed_sketches).
Sourcepub fn datum_entities_json(&self) -> String
pub fn datum_entities_json(&self) -> String
The construction datums/planes as JSON ([{"name","visible"}]) — the datum
sibling of sketch_entities_json the Scene
panel publishes (__brepDatums) for the headed verifier.
Sourcepub fn select_datum(&mut self, name: &str) -> bool
pub fn select_datum(&mut self, name: &str) -> bool
Select a construction datum/plane by frame NAME (replacing the whole selection): a Scene-tree row click or a viewport datum pick. Only a name that is an actually-resolved D/P frame at the current rollback selects; others return false without changing the selection. Re-feeds the datum planes so the selected one shows the accent, and bumps the generation.
Source§impl EngineState
impl EngineState
Sourcepub fn expressions_json(&self) -> String
pub fn expressions_json(&self) -> String
The history’s expressions source string (the variable sheet the panel’s
editor binds to). Raw source text — despite the _json suffix it mirrors
the other engine readouts’ naming; the verifier reads it verbatim.
Sourcepub fn set_expressions(&mut self, expressions: &str) -> String
pub fn set_expressions(&mut self, expressions: &str) -> String
Replace the expressions source and re-run the rolled-to prefix so every
feature param referencing a variable (e.g. sizeX = "boxW") rebuilds with
the new value — the panel’s live-update path. Returns the build-report JSON.
Sourcepub fn configurator_json(&self) -> String
pub fn configurator_json(&self) -> String
The history’s configurator object (typed named inputs) as JSON — a
read/display surface for the panel; deeper configurator editing is deferred.
Sourcepub fn expression_variables_json(&self) -> String
pub fn expression_variables_json(&self) -> String
The parsed variable list for the sheet’s name/value view:
[{ "name": "...", "expr": "..." }, …] — one entry per name = rhs;
assignment in the expressions source, in source order. The RHS is shown
verbatim (its DEFINING expression); evaluating it to a live scalar needs the
kernel’s private Env, so a computed value column is deferred — the text
editor + re-run is the source of truth for applied values.
Source§impl EngineState
impl EngineState
Sourcepub fn gizmo_mode(&self) -> &'static str
pub fn gizmo_mode(&self) -> &'static str
The armed ◎ gizmo mode: "none", "transform", or "dimension". Drives
the ◎ highlight + the app’s dimension-overlay draw / input routing.
Sourcepub fn dimension_armed_for(&self, feature_id: &str) -> bool
pub fn dimension_armed_for(&self, feature_id: &str) -> bool
Whether the DIMENSION gizmo is armed for THIS feature (drives the ◎ dimension-mode highlight).
Sourcepub fn dimension_armed_feature(&self) -> String
pub fn dimension_armed_feature(&self) -> String
The dimension-armed feature id (empty unless in dimension mode).
Sourcepub fn arm_dimension(&mut self, feature_id: &str)
pub fn arm_dimension(&mut self, feature_id: &str)
Arm the DIMENSION gizmo for feature_id: hide the transform widget, show
the annotation overlay. Re-arming a different feature moves it.
Sourcepub fn transform_center_pick(&self, x: f64, y: f64) -> bool
pub fn transform_center_pick(&self, x: f64, y: f64) -> bool
Whether a screen-px pick in TRANSFORM mode lands on the orange CENTER
free-move sphere (HANDLE_CENTER). The viewport uses this to make a bare
click on the center TOGGLE to the dimension arrows (via
toggle_to_dimension) instead of swallowing
it as a generic handle click. False in any other gizmo mode.
Sourcepub fn dimension_origin_pick(&self, x: f64, y: f64) -> bool
pub fn dimension_origin_pick(&self, x: f64, y: f64) -> bool
Whether a screen-px pick in DIMENSION mode lands on an orange ORIGIN
sphere of the armed feature’s dimension arrows. Each distinct annotation
draws such a sphere — a LINEAR dim at its point_a (a cube’s three axis
dims share one, a cone/pyramid draw two), an ANGULAR dim at its arc
center (the vertex; its sweep-END sphere is the angle DRAG handle, not a
toggle) — so every one is projected via the camera and hit-tested against
the screen-constant sphere radius. The viewport uses this to TOGGLE back to
the transform gizmo (via toggle_to_transform),
which is the ONLY way an angular-only feature (a revolve) reaches transform.
False in any other gizmo mode. The hit radius mirrors the gizmo center’s own
tolerance (PX_CENTER_RAD + 2.0, transform.rs) so the two toggle targets match.
Sourcepub fn dimension_arrow_pick(&self, x: f64, y: f64) -> Option<String>
pub fn dimension_arrow_pick(&self, x: f64, y: f64) -> Option<String>
Whether a screen-px pick in DIMENSION mode lands on a dimension ARROWHEAD
(a linear leader’s orange cone TIP at point_b, or an angular arc’s orange
sweep-END handle sphere). Returns the grabbed annotation’s field_key — the
viewport routes a DRAG that starts here to [feature_dimension_drag](Self::
feature_dimension_drag), editing that param live (Fix 4). None in any other
gizmo mode / when no arrowhead is under the pointer. Distinct from
dimension_origin_pick: that grabs the SHARED
origin sphere (a mode toggle), this grabs an arrowHEAD (a value edit). The
nearest arrowhead within the screen-constant hit radius wins.
Sourcepub fn dimension_hit_areas_json(&self) -> String
pub fn dimension_hit_areas_json(&self) -> String
DEBUG overlay: the EXACT SCREEN-space (viewport-local px) pickable regions
of the armed feature’s dimension gizmo — the SAME regions
dimension_arrow_pick + dimension_origin_pick 2D-test the cursor against
(dimension_hit_regions) — so the red
outline can NEVER drift from the grabbable area. Each item is a
{ kind:"capsule", a:[x,y], b:[x,y], r } (linear leaders) or
{ kind:"circle", c:[x,y], r } (origin / arc-handle spheres); the app only
offsets by rect.min. [] unless the DIMENSION gizmo is armed.
Sourcepub fn toggle_to_dimension(&mut self)
pub fn toggle_to_dimension(&mut self)
Toggle the armed ◎ gizmo from TRANSFORM to DIMENSION for the currently transform-armed feature (the orange center-sphere click). No-op unless a feature is transform-armed.
Sourcepub fn toggle_to_transform(&mut self)
pub fn toggle_to_transform(&mut self)
Toggle the armed ◎ gizmo from DIMENSION to TRANSFORM for the currently dimension-armed feature (the orange origin-sphere click). No-op unless a feature is dimension-armed.
Sourcepub fn feature_dimension_annotations_json(&self, feature_id: &str) -> String
pub fn feature_dimension_annotations_json(&self, feature_id: &str) -> String
The dimension annotations for feature_id as JSON:
[{ fieldKey, pointA, pointB, value, label, mid }] (world-space points;
mid is the leader midpoint the app anchors the label at). [] when the
feature type has no FD-1 builder.
Sourcepub fn feature_dimension_state_json(&self) -> String
pub fn feature_dimension_state_json(&self) -> String
The { mode, feature, annotations } snapshot the headless verifier reads
(published as __brepFeatureDim).
Sourcepub fn refresh_feature_dimension_overlay(&mut self)
pub fn refresh_feature_dimension_overlay(&mut self)
(Re)project the dimension leaders onto the current geometry. Called on arm
- after every param change (drag / value edit / rerun in dimension mode)
- on a material ZOOM (
Self::ensure_feature_dimension_overlay_current). Remembers theworld_per_pixelit baked at, which is what lets that per-frame ensure fire on change ONLY.
Sourcepub fn feature_dimension_drag(
&mut self,
feature_id: &str,
field_key: &str,
x: f64,
y: f64,
)
pub fn feature_dimension_drag( &mut self, feature_id: &str, field_key: &str, x: f64, y: f64, )
Drag a dimension handle: project the pointer pixel (x, y) onto the
annotation’s world axis (pointA → pointB), take the distance along the
axis from pointA as the new value (correcting for any transform scale so
the PARAM — not the scaled world length — is what changes), set the param,
and re-run the history live. Degenerate projections (parallel ray / zero
axis) no-op.
Sourcepub fn feature_dimension_set_value(
&mut self,
feature_id: &str,
field_key: &str,
input: &str,
)
pub fn feature_dimension_set_value( &mut self, feature_id: &str, field_key: &str, input: &str, )
Edit a dimension value from a label field: a plain numeric literal sets the
param to that number; otherwise the input is treated as an EXPRESSION —
evaluated LIVE against the history’s expressions + configurator (the
kernel eval_expression) and, on success, STORED as the expression string
(the kernel re-evaluates it via ctx.number, so it stays live). A blank /
bad-expression input no-ops (never corrupts the feature). Re-runs live.
Source§impl EngineState
impl EngineState
Sourcepub fn interference_check(&mut self) -> InterferenceReport
pub fn interference_check(&mut self) -> InterferenceReport
Run the interference check over every component instance (hidden ones included — interference is a physical question). Non-destructive: the component solids are only READ; each pairwise INTERSECT result is measured and freed. Returns the full report for the results window.
Source§impl EngineState
impl EngineState
Sourcepub fn run_history_json(&mut self, request_json: &str) -> Result<String, String>
pub fn run_history_json(&mut self, request_json: &str) -> Result<String, String>
Run a whole history and reconcile the display scene (R10 incremental):
reused solids keep their buffers, the rest re-tessellate. Returns the build
report JSON ({featureErrors, unresolved, displayErrors}). Marks dirty.
A SCENE-ONLY one-shot: it does not touch the engine-owned history document
and does not run the Self::finish_apply tail, so it also does not paint
model colours. Callers that need those use Self::set_history_json.
Sourcepub fn pump(&mut self)
pub fn pump(&mut self)
Drain every completed run reply and APPLY it — the POLL/APPLY half of the
M2a seam. Called from rerun_history for the Inline
runner’s immediate apply, and once per frame from the app so a future async
runner’s completed runs land on the main thread. A reply older than
applied_generation (a newer run that finished
first) is dropped.
Sourcepub fn queries_pending(&self) -> bool
pub fn queries_pending(&self) -> bool
Whether a measurement query is still in flight (its reply not yet drained) —
the query analogue of run_pending, so the app keeps the
frame loop alive until a background runner’s measurement lands and displays.
Always false for the synchronous Inline runner.
Sourcepub fn mesh_imports_pending(&self) -> bool
pub fn mesh_imports_pending(&self) -> bool
Whether RANSAC reconstruction is still executing on the native runner thread or browser worker.
Sourcepub fn run_pending(&self) -> bool
pub fn run_pending(&self) -> bool
Whether a submitted run has not yet been applied (run_generation != applied_generation). Always false for the synchronous Inline runner
(submit → immediate pump keeps the two in lockstep); a background runner
uses it to keep the frame loop alive until its reply lands.
Sourcepub fn applied_generation(&self) -> u64
pub fn applied_generation(&self) -> u64
The generation of the last APPLIED run — bumps once per applied history run (document loads, edits, constraint mutations, solves). A cheap staleness key for app-side caches derived from the applied document (the update-components outdated badge keys on it).
Sourcepub fn run_progress(&self) -> Option<&RunProgress>
pub fn run_progress(&self) -> Option<&RunProgress>
What the in-flight run is executing right now, as far as the runner
has reported (see crate::runner::RunProgress); None when nothing
is running or the run has not reached its first executed feature.
Sourcepub fn cancelled_run(&self) -> Option<&str>
pub fn cancelled_run(&self) -> Option<&str>
The feature id the last cancelled run was executing (empty when it was cancelled before any progress arrived), until the next submit.
Sourcepub fn cancel_run(&mut self) -> bool
pub fn cancel_run(&mut self) -> bool
CANCEL the in-flight run. The runner abandons its work and comes back
with an EMPTY resident registry (a fresh thread / a fresh worker — see
crate::runner::HistoryRunner::cancel), so this side forgets
everything that was waiting on it: the run itself (generations are
bumped past it, so a straggling reply from the old runner is dropped
as stale), pending measurement queries, document-bound mesh imports
and a deferred fit. The DISPLAY SCENE is left as the last applied run
built it — the document is ahead of it now, which the notice says; the
next edit re-runs the whole history through the new runner (a cold
run: the warm cache went with the old one). Nothing inside a feature
is interruptible, so the native thread keeps burning CPU until the
feature it is on finishes; the browser worker is terminated outright.
false when nothing was running, or the runner cannot abandon (the
synchronous Inline runner, whose runs are over before anyone can ask).
Sourcepub fn has_solids(&self) -> bool
pub fn has_solids(&self) -> bool
Whether the display scene currently holds at least one solid. Used by the
app’s async-safe first-frame framing: under a background runner (thread /
worker) the seed run lands a frame (or many) after boot, so the shell waits
for has_solids() && !run_pending() before its one-shot zoom_to_fit.
Sourcepub fn set_runner(&mut self, runner: Box<dyn HistoryRunner>)
pub fn set_runner(&mut self, runner: Box<dyn HistoryRunner>)
Swap in a different history runner (the platform injects its own — the native
app installs a ThreadRunner; wasm keeps the
default Inline until M3’s worker). Resets the new runner’s delta baseline so
the next run rebuilds fully. Call BEFORE seeding a document so the seed builds
through the installed runner.
Sourcepub fn set_history_json(&mut self, request_json: &str) -> Result<String, String>
pub fn set_history_json(&mut self, request_json: &str) -> Result<String, String>
Load a whole history document (a saved part file parses as one); the engine now OWNS this recipe. Rolls to the last feature and builds it.
The document’s top-level metadata field (the Properties-panel
name-keyed store) is lifted out into Self::metadata before the feature
list is handed to the kernel — loading a part REPLACES the store wholesale
(a document with no metadata clears it), mirroring the previous metadata
manager’s load semantics. Round-trips with Self::history_request_json.
The top-level workbench field (the ACTIVE-WORKBENCH id the save embedded
— see Self::history_request_json) is lifted off the kernel recipe the
same way and applied through Self::apply_settings_json — the SAME seam
the toolbar’s workbench dropdown writes through — so the palette / context
offers / workbench buttons react to a restored workbench exactly as they
do to a manual switch (settings generation bump included). Tolerances:
- a legacy document WITHOUT the field (or with a non-string value) leaves the current workbench untouched — opening an old file never yanks the user out of their workbench;
- an unknown/stale id is stored RAW (never an error): the settings layer
deliberately doesn’t validate ids, and every consumer resolves through
the app-side registry’s
resolve(), which falls back to the default workbench — so a file saved by a build with a workbench this build doesn’t know still opens cleanly; - the restored id is deliberately NOT persisted to the settings blob — that blob stays the user’s boot preference; a document’s workbench is session-scoped (the next explicit dropdown change persists as usual).
Sourcepub fn history_request_json(&self) -> String
pub fn history_request_json(&self) -> String
The whole history request document (persistence / debugging), with the engine-owned extras folded back in on top of the kernel recipe so save→open round-trips them:
metadata— the Properties-panel store, written only when non-empty so an un-annotated model persists as before;workbench— the CURRENT active-workbench id (self.settings.workbench), ALWAYS written so a saved part reopens in the workbench it was saved from (restored bySelf::set_history_json). Always-embed keeps the invariant simple: the serialized field tracks the LIVE setting, never a stale stored copy — the load lifts it off the kernel recipe entirely, so this is the ONE place it is (re)written. Note the deliberate consequence: switching workbench changes this document, so the file panel’s dirty flag flips — consistent with themetadataprecedent, and semantically true now that the workbench is part of the saved file.
Sourcepub fn history_listing_json(&self) -> String
pub fn history_listing_json(&self) -> String
The tree listing { step, features:[{index,type,id}] } for the UI panel.
Sourcepub fn history_report_json(&self) -> String
pub fn history_report_json(&self) -> String
The last build report JSON.
pub fn history_len(&self) -> usize
Sourcepub fn history_rollback(&self) -> usize
pub fn history_rollback(&self) -> usize
The rolled-to (selected) feature index.
pub fn feature_type_at(&self, index: usize) -> Option<String>
pub fn feature_id_at(&self, index: usize) -> Option<String>
Sourcepub fn feature_params_json(&self, index: usize) -> String
pub fn feature_params_json(&self, index: usize) -> String
The inputParams document of feature index ("null" if none) — the
dialog’s editing-buffer source.
Sourcepub fn next_feature_id(&mut self, base: &str) -> String
pub fn next_feature_id(&mut self, base: &str) -> String
Mint the id for a NEW feature: {base}{N} where base is the feature’s
shortName (crate::features::feature_short_name) and N is the part
history’s persistent GLOBAL counter (monotonic, never reused, round-trips
save/load — see History::next_feature_id). &mut because the counter
advances; if the caller’s add_feature then fails the number is simply
skipped (monotonic-with-gaps is the contract, not an error).
Sourcepub fn roll_to(&mut self, index: usize) -> String
pub fn roll_to(&mut self, index: usize) -> String
Roll the model to feature index: re-run features[0..=index].
Sourcepub fn update_feature_params(
&mut self,
id: &str,
input_params_json: &str,
) -> Result<String, String>
pub fn update_feature_params( &mut self, id: &str, input_params_json: &str, ) -> Result<String, String>
Replace feature id’s input params and re-run at the current rollback →
the viewport updates live.
Sourcepub fn update_many_feature_params(
&mut self,
edits: &[(String, Value)],
) -> Result<String, String>
pub fn update_many_feature_params( &mut self, edits: &[(String, Value)], ) -> Result<String, String>
Replace the inputParams of MANY features as ONE model edit — the
Self::update_feature_params batch sibling (Self::add_features is
the append-only one). ONE undo checkpoint and ONE history re-run for the
whole set.
The lane that needs it: a PACKED BOM row rolls up every occurrence whose
occurrence data matches, so editing one of its cells writes the same key
into N ACOMP features. Looping update_feature_params would cost N
re-runs and — worse — N undo entries, so taking back one visible edit
would need N presses of undo.
Unknown ids are reported (the whole batch is refused before anything is written, so a typo can never half-apply); an empty batch is a no-op that neither checkpoints nor runs.
Sourcepub fn add_feature(&mut self, feature_json: &str) -> Result<String, String>
pub fn add_feature(&mut self, feature_json: &str) -> Result<String, String>
Append a feature (a full {type, inputParams, …} descriptor) and roll to
it. The caller assigns a unique id (see Self::next_feature_id).
Sourcepub fn add_features(&mut self, features: &[Value]) -> String
pub fn add_features(&mut self, features: &[Value]) -> String
Append MANY features and roll to the last — Self::add_feature’s batch
sibling, and the reason it exists: add_feature re-runs the WHOLE history
per call, so a lane that appends N features by looping it costs N rebuilds
(O(N²) work on an N-part STEP-assembly import). This pushes all of them,
then re-runs ONCE — one rebuild, one undo checkpoint, one
applied_generation bump.
Deliberately NOT Self::set_history_json: that is the document-SWITCH
path (it clears the kernel history cache and resets the runner’s delta
baseline, forcing a full cold rebuild), which is the wrong mechanism for an
append onto the live document.
An empty batch is a no-op — no checkpoint, no run, no generation bump —
and returns the standing report. The caller assigns each feature’s unique
id (see Self::next_feature_id).
Sourcepub fn delete_feature(&mut self, id: &str) -> String
pub fn delete_feature(&mut self, id: &str) -> String
Delete the feature with id id (no-op if absent) and re-run, clamping the
rolled-to step.
Sourcepub fn reorder_feature(&mut self, index: usize, up: bool) -> String
pub fn reorder_feature(&mut self, index: usize, up: bool) -> String
Move feature index one slot up/down (reorder), keeping it selected.
Source§impl EngineState
impl EngineState
Sourcepub fn can_undo(&self) -> bool
pub fn can_undo(&self) -> bool
Whether an undo step is available (to enable the toolbar’s Undo button).
Sourcepub fn undo(&mut self) -> String
pub fn undo(&mut self) -> String
Undo the last model mutation: restore the previous document + rolled-to step, then re-run + reconcile the scene. Returns the build report; a no-op (empty undo stack) returns the last report unchanged.
Sourcepub fn redo(&mut self) -> String
pub fn redo(&mut self) -> String
Redo the last undone model mutation (symmetric with Self::undo).
Source§impl EngineState
impl EngineState
Sourcepub fn load_model_and_fit(
&mut self,
request_json: &str,
) -> Result<String, String>
pub fn load_model_and_fit( &mut self, request_json: &str, ) -> Result<String, String>
Load a whole model document (a saved .BREP.json recipe) and FRAME it:
set_history_json (which rolls to the last
feature) followed by zoom_to_fit. The one call the
file panel’s Open needs — the model IS the engine-owned history, so
opening a file is loading its request JSON and reframing. Returns the
build-report JSON.
Source§impl EngineState
impl EngineState
Sourcepub fn import_stl_feature(&mut self, bytes: &[u8]) -> Result<String, String>
pub fn import_stl_feature(&mut self, bytes: &[u8]) -> Result<String, String>
Import an STL triangle mesh through topology-aware RANSAC recognition. Unsupported regions remain as validated facets, so every repairable source triangle reaches the resulting CAD body.
Sourcepub fn import_obj_feature(&mut self, text: &str) -> Result<String, String>
pub fn import_obj_feature(&mut self, text: &str) -> Result<String, String>
Import a Wavefront OBJ mesh through the same RANSAC reconstruction path.
Sourcepub fn import_obj_bytes_feature(
&mut self,
bytes: &[u8],
) -> Result<String, String>
pub fn import_obj_bytes_feature( &mut self, bytes: &[u8], ) -> Result<String, String>
Byte-oriented OBJ entry used by the picker so decoding also stays on the background runner with parsing and reconstruction.
Sourcepub fn reconstruct_mesh_preview(
&mut self,
format: MeshImportFormat,
bytes: Vec<u8>,
options: StlConversionOptions,
) -> Result<u64, String>
pub fn reconstruct_mesh_preview( &mut self, format: MeshImportFormat, bytes: Vec<u8>, options: StlConversionOptions, ) -> Result<u64, String>
Reconstruct without editing history. The caller owns confirmation and
can inspect the exact STEP and diagnostics returned by take_mesh_preview.
pub fn take_mesh_preview(&mut self) -> Option<MeshImportReply>
Sourcepub fn import_step_feature(&mut self, step_text: &str) -> Result<String, String>
pub fn import_step_feature(&mut self, step_text: &str) -> Result<String, String>
Import a STEP document into the model: append an IMPORT3D feature whose
inputParams.stepText is the raw ISO-10303-21 text (the exact headless
source the kernel importer reads — no fileToImport data-URL marshaling
needed), mint it a persistent-counter id, roll to it, and rebuild. Returns the
build report JSON (imported bodies + any per-feature error). A non-STEP
payload is refused up front so a bad upload never leaves a dead feature.
Sourcepub fn export_step_text(&self) -> Result<String, String>
pub fn export_step_text(&self) -> Result<String, String>
Export the CURRENT model’s resident solids to an ISO-10303-21 STEP
document. Collects the resident handles of the rolled-to model (a warm
re-run of the same prefix the display scene was built from — see
crate::pipeline::resident_solid_handles) and hands them to the kernel’s
brep_kernel::export_step_handles, so the exact NURBS topology is
serialized (never the display mesh). Errs clearly when the model is empty.
Sourcepub fn export_flat_pattern_dxf(&self) -> Result<String, String>
pub fn export_flat_pattern_dxf(&self) -> Result<String, String>
Export the part’s sheet-metal FLAT PATTERN (the unfold) as a DXF (R12
ASCII) 2D vector document. Runs the unfold TRANSIENTLY off the target
body’s resident tree — no feature is added and history is not mutated. Errs
("no sheet-metal body in the part") when the part carries no sheet metal.
Sourcepub fn export_flat_pattern_svg(&self) -> Result<String, String>
pub fn export_flat_pattern_svg(&self) -> Result<String, String>
Export the part’s sheet-metal flat pattern as an SVG — the DXF sibling of
Self::export_flat_pattern_dxf.
Sourcepub fn import_iges_feature(&mut self, iges_text: &str) -> Result<String, String>
pub fn import_iges_feature(&mut self, iges_text: &str) -> Result<String, String>
Import an IGES document into the model: append an IMPORT3D feature whose
inputParams.igesText is the raw IGES text (the kernel importer reads it
via brep_kernel::import_iges), mint an id, roll to it, and rebuild.
Refuses a non-IGES payload up front so a bad upload never leaves a dead
feature.
Sourcepub fn export_iges_text(&self) -> Result<String, String>
pub fn export_iges_text(&self) -> Result<String, String>
Export the CURRENT model’s resident solids to an IGES 5.3 document of
trimmed NURBS surfaces — the IGES analogue of Self::export_step_text,
handing the resident handles to brep_kernel::export_iges_handles.
Sourcepub fn export_stl_text(&self) -> Result<String, String>
pub fn export_stl_text(&self) -> Result<String, String>
Export the CURRENT display scene to an ASCII STL string (one solid with a
per-triangle geometric normal for every mesh triangle of every displayed
solid). STL is a triangle-soup format with no multi-body concept, so all
solids fold into a single solid brep … endsolid brep. String-shaped so it
crosses the same string ModelStore seam the STEP lane uses. Errs when the
scene has no triangles.
Source§impl EngineState
impl EngineState
Sourcepub fn probe_step_assembly(
&mut self,
step_text: &str,
) -> Result<Option<StepAssemblyProbe>, String>
pub fn probe_step_assembly( &mut self, step_text: &str, ) -> Result<Option<StepAssemblyProbe>, String>
Read a STEP file’s product structure — THE parse of a structured import.
Stashes the parsed assembly (with every product’s solids) for
Self::import_probed_step_assembly and returns the dialog’s counts.
Ok(None) = no usable structure (no NAUO edges, or none reaching built
geometry): the caller imports through the flat
Self::import_step_feature lane with the text it already holds, which
is byte-for-byte today’s behaviour. Err only for text that is not a
Part 21 file at all — a BROKEN assembly degrades, it does not fail.
Replaces any previously stashed assembly on EVERY outcome, Ok(None)
included: a stale stash surviving a probe of a different file is how a
consume silently imports the wrong one.
Sourcepub fn submit_step_probe(&mut self, step_text: &str) -> u64
pub fn submit_step_probe(&mut self, step_text: &str) -> u64
SUBMIT a STEP text to be probed for product structure on the runner
(the parse builds every product’s bodies: seconds for a real assembly,
which is why it leaves the UI thread). The answer arrives through
Self::take_step_probe under the returned id, after a later pump;
a found structure is stashed for Self::import_probed_step_assembly.
Any earlier stash is dropped now — the probe REPLACES it on every
outcome, so a stale parse can never be consumed for the wrong file.
The structure test the parse would make is “any NEXT_ASSEMBLY_USAGE_
OCCURRENCE entity” (assembly_edges), so a text with none cannot have
structure and is answered Flat without a trip to the runner: a part
file — the common upload — no longer pays a full parse only to be told
to take the flat lane, where the worker parses it anyway. (The text
test is a superset of the entity test: a stray mention in a comment
merely runs the parse.)
Sourcepub fn take_step_probe(&mut self) -> Option<(u64, StepProbeOutcome)>
pub fn take_step_probe(&mut self) -> Option<(u64, StepProbeOutcome)>
The oldest answered probe, if any: its submission id and what it found.
Sourcepub fn step_probes_pending(&self) -> bool
pub fn step_probes_pending(&self) -> bool
Whether a submitted probe has not been answered yet — the app keeps the frame loop alive (and the panel its “reading…” status) while it is.
Sourcepub fn import_probed_step_assembly(
&mut self,
doc_name: &str,
opts: StepAssemblyImport,
sink: &mut dyn PartSink,
) -> Result<StepAssemblyReport, String>
pub fn import_probed_step_assembly( &mut self, doc_name: &str, opts: StepAssemblyImport, sink: &mut dyn PartSink, ) -> Result<StepAssemblyReport, String>
Import the assembly Self::probe_step_assembly stashed: one
parts-library entry per unique product, one ACOMP instance per
occurrence, ONE rebuild. TAKES the stash, so a double-import is an error
rather than a double-insert.
doc_name names products the file left unnamed ({doc_name}-part-{id}).
opts.nested chooses between the flat and nested shapes — see
StepAssemblyImport::nested. Errs when nothing is stashed, and when
every product failed to encode — the latter being the caller’s cue to
re-run the flat import with the file text it holds.
sink receives every unique part document so the app can write it to
the model store and hand back a real sourceKey; pass EmbeddedOnly
to keep the parts embedded (what a caller with no store does).
Sourcepub fn discard_probed_step_assembly(&mut self)
pub fn discard_probed_step_assembly(&mut self)
Drop a probed assembly and the solids it holds resident — the dialog’s Cancel. Idempotent.
Sourcepub fn import_step_assembly(
&mut self,
step_text: &str,
doc_name: &str,
opts: StepAssemblyImport,
) -> Result<StepAssemblyReport, String>
pub fn import_step_assembly( &mut self, step_text: &str, doc_name: &str, opts: StepAssemblyImport, ) -> Result<StepAssemblyReport, String>
Probe + consume in one call, falling back to the flat lane by itself — the HEADLESS/test entry point. The app uses the probe/consume pair instead, because it has a dialog between the two halves.
Still exactly one parse: this is probe_step_assembly followed by the
consume of what it stashed.
Parts stay EMBEDDED here (EmbeddedOnly): this entry point has no
store handle and no way to ask for a destination. The app uses the
probe/consume pair with a real sink.
Source§impl EngineState
impl EngineState
Sourcepub fn pick_candidates_at(&self, x: f64, y: f64) -> Vec<PickCandidate>
pub fn pick_candidates_at(&self, x: f64, y: f64) -> Vec<PickCandidate>
EVERY pick candidate under CSS-pixel (x, y): the scene’s
vertices/edges/faces/solids (pick::pick) PLUS the construction PLANE
cards the pointer ray crosses, ranked together category-major
(VERTEX > EDGE > FACE > PLANE > SOLID > COMPONENT), nearest first within a
category.
This is the RAW list (no selection filter); the filter-honoring callers are
Self::candidates_filtered_at (the pick-list popup) and
Self::pick_top_at (every single-hit pick).
Sourcepub fn candidate_kind_label(&self, candidate: &PickCandidate) -> &'static str
pub fn candidate_kind_label(&self, candidate: &PickCandidate) -> &'static str
The kind LABEL a candidate should present under — PickKind::as_str,
except that a committed-sketch sheet reads "SKETCH" rather than the
"SOLID" its PickKind carries. The pick-list popup and the published
candidate JSON both use it, so what a row calls itself matches the filter
lane that admitted it.
Source§impl EngineState
impl EngineState
Sourcepub fn pick_json(&self, x: f64, y: f64) -> String
pub fn pick_json(&self, x: f64, y: f64) -> String
Ranked candidate list under CSS-pixel (x, y), kernel names, priority
VERTEX > EDGE > FACE > … > SOLID.
SCENE ONLY, deliberately: this R3-boundary accessor (and its
hover_json sibling) reports kernel-named GEOMETRY, and
its in-tree consumer is the sketch’s external-edge picker, which wants
edges. The construction PLANE cards join the pick list one level up, in
pick_candidates_at — that is what the
selection paths and the app’s pick-list popup consume.
Sourcepub fn hover_json(&self, x: f64, y: f64) -> String
pub fn hover_json(&self, x: f64, y: f64) -> String
The single best candidate under (x, y) (hover), or null.
pub fn apply_settings_json(&mut self, json: &str) -> Result<(), String>
Sourcepub fn settings_json(&self) -> String
pub fn settings_json(&self) -> String
The FULL current settings as JSON (the round-trip counterpart of
[apply_settings_json]): the schema-driven form seeds its widgets from
this and the storage seam persists it.
Sourcepub fn solid_color_overrides_json(&self) -> String
pub fn solid_color_overrides_json(&self) -> String
The current per-solid metadata color overrides as JSON —
[{"name": "...", "override": "#rrggbb" | null}, …]. Lets a UI list the
scene’s solids with their current override so the picker reflects state.
pub fn apply_emphasis_json(&mut self, json: &str) -> Result<(), String>
pub fn set_visible(&mut self, name: &str, visible: bool) -> bool
pub fn scene_listing_json(&self) -> String
Sourcepub fn depth_range_bbox(&self) -> Aabb
pub fn depth_range_bbox(&self) -> Aabb
The BASE bbox the camera depth-range fit starts from: the visible SOLIDS
unioned with the pushed OVERLAY groups (sketch curves/points, dimension
leaders, constraint glyphs — the set_overlay channel). Folding in the
groups stops orbiting an editing sketch from clipping it against the
solids-only bounds (the reported clipping when “Lock to sketch” is off).
The render path (Self::fit_camera_and_overlay) unions the FULL widget
overlay’s world bounds (datum planes, world axes, frames, transform
gizmo — NOT in this bbox’s channels) and the world origin on top of this
before fitting, so construction geometry never clips. Callers must bind
this to a local before camera.fit_depth_range (which needs
&mut self.camera).
Source§impl EngineState
impl EngineState
Sourcepub fn scene_entities_json(&self) -> String
pub fn scene_entities_json(&self) -> String
A RICHER scene listing than scene_listing_json
(which is counts only): per solid the individual face + edge kernel NAMES
and vertex refs (topo id + world position), plus visibility — the shape the
engine-native Scene tree lists entities from and the headed verifier asserts
against. Vertices carry no kernel name, so they are keyed by topo id + world
position (the same shape the emphasis vertex-ref selection uses).
Sourcepub fn select_by_name(&mut self, kind: &str, name: &str) -> bool
pub fn select_by_name(&mut self, kind: &str, name: &str) -> bool
Drive the engine SELECTION by kernel NAME from a UI tree (the name-based
analogue of select_top_at, which picks under the
cursor). Replaces the current selection with the single named solid /
face / edge so clicking a Scene-tree row highlights that entity in the
viewport (the render pass reads emphasis). Vertices have no kernel name —
use select_vertex_by_position. Returns
false for an unknown kind or an empty name.
Sourcepub fn select_vertex_by_position(
&mut self,
solid: &str,
position: [f64; 3],
) -> bool
pub fn select_vertex_by_position( &mut self, solid: &str, position: [f64; 3], ) -> bool
Select a single vertex by its owning solid + world position — vertices have no kernel name, so emphasis keys them by solid + position (matched with a tolerance in the render pass). Replaces the current selection. Returns false for an empty solid name.
Source§impl EngineState
impl EngineState
Sourcepub fn mass_properties_json(&self, name: Option<&str>, density: f64) -> String
pub fn mass_properties_json(&self, name: Option<&str>, density: f64) -> String
Mass properties for the Inspector panel, from the kernel’s exact
(divergence-theorem) integrator. name = Some(solid) reports that resident
solid; None reports the whole model. density (mass units per mm³; the
kernel length convention is millimetres) scales mass and the inertia
tensor — the centroid and principal axes are density-independent.
Returns JSON:
{ "ok": true, "target": "Box", "solidCount": 1, "density": 1.0,
"volume": 5738.05, "surfaceArea": 2927.79, "mass": 5738.05,
"centroid": [10.0, 10.0, 10.0],
"inertia": [[..],[..],[..]] | null,
"principalMoments": [a,b,c] | null,
"principalAxes": [[..],[..],[..]] | null }A single resolved solid carries the full centroidal inertia tensor +
principal axes/moments; a multi-solid aggregate reports summed volume /
area / mass and the volume-weighted centroid, with the tensor fields
null (select one solid for its inertia). ok:false with a message on
no solids / an unknown name / an integrator failure.
Source§impl EngineState
impl EngineState
Sourcepub fn selection_filter(&self) -> SelectionFilter
pub fn selection_filter(&self) -> SelectionFilter
The current selection filter (a cheap Copy) — a panel reads it to seed
its toggles, edits the copy, and writes back via [set_selection_filter].
Sourcepub fn set_selection_filter(&mut self, filter: SelectionFilter)
pub fn set_selection_filter(&mut self, filter: SelectionFilter)
Replace the whole selection filter. Purely a policy change (no geometry or camera moves), so it does NOT mark the scene dirty; the NEXT click honors it.
Sourcepub fn set_kind_pickable(&mut self, kind: &str, on: bool)
pub fn set_kind_pickable(&mut self, kind: &str, on: bool)
Toggle one kind’s pickability by name ("SOLID"/"FACE"/"EDGE"/"VERTEX").
Sourcepub fn selection_filter_json(&self) -> String
pub fn selection_filter_json(&self) -> String
The filter as JSON ({"SOLID":true,…,"PLANE":true,"COMPONENT":true}) —
lets a UI / the headed verifier read the pickable-kind state.
Sourcepub fn apply_selection_filter_json(&mut self, json: &str) -> Result<(), String>
pub fn apply_selection_filter_json(&mut self, json: &str) -> Result<(), String>
Apply a partial filter JSON (any subset of the keys); absent keys keep
their current value. The round-trip counterpart of [selection_filter_json].
Sourcepub fn select_filtered_at(&mut self, x: f64, y: f64) -> bool
pub fn select_filtered_at(&mut self, x: f64, y: f64) -> bool
The filter-honoring plain-click selection (what [select_top_at] delegates
to): resolve the TOP-priority candidate under (x, y) whose kind the filter
admits (via pick_top_at with the enabled kinds —
scene entities AND construction plane cards) and select THAT kind, replacing
the current selection. A miss — or a click while the filter
admits nothing — clears the selection. Returns whether something selected.
Sourcepub fn has_selection(&self) -> bool
pub fn has_selection(&self) -> bool
Whether ANYTHING is currently selected (solids/faces/edges/vertices OR a
construction datum/plane) — distinct from emphasis.is_empty() (which also
counts hover). Drives the selection action bar’s visibility: a datum-only
selection must show the bar so the plane can offer “Sketch”.
Sourcepub fn hide_selected(&mut self) -> usize
pub fn hide_selected(&mut self) -> usize
Toggle the visibility of EXACTLY what is selected (the action bar’s
Hide/Show): each selected SOLID flips its whole-solid visibility
(set_visible); each selected FACE / EDGE / VERTEX
flips only that sub-entity (set_entity_visible,
the same per-entity mask the Scene-tree checkboxes use — a hidden face’s
triangles are simply not drawn). Every target toggles INDEPENDENTLY off its
own live state (hide if visible, show if hidden), so a mixed / repeat click
flips each item. Returns how many targets were toggled. Leaves the selection
as-is, so a second click toggles the same items back.
Source§impl EngineState
impl EngineState
Sourcepub fn clear_selection(&mut self) -> bool
pub fn clear_selection(&mut self) -> bool
Clear the current SELECTION (Esc): drop all selected solids/faces/edges/ vertices (hover is left untouched). Bumps the emphasis generation + marks dirty only when something was actually cleared. Returns whether it changed.
Sourcepub fn select_top_at(&mut self, x: f64, y: f64) -> bool
pub fn select_top_at(&mut self, x: f64, y: f64) -> bool
Select the top-priority pick under CSS-pixel (x, y) that the SELECTION
FILTER admits — replacing the current selection (a plain viewport click).
A miss (or a click when the filter admits nothing) clears the selection.
Marks dirty when the selection changed; returns whether something was
selected. The by-kind honoring lives in [select_filtered_at] in the
appended selection-filter impl block (kept separate so concurrent edits to
this primary block don’t conflict).
Sourcepub fn selection_json(&self) -> String
pub fn selection_json(&self) -> String
The current SELECTION (not hover) as JSON
{ solids:[..], faces:[..], edges:[..], vertices: n } — lets a UI / the
headed verifier read selection state (e.g. assert Esc cleared it).
Sourcepub fn ref_select_active(&self) -> bool
pub fn ref_select_active(&self) -> bool
True while the reference-selection modal is active (the shell hides the rest of the UI and the viewport routes clicks to picking).
Sourcepub fn begin_ref_select(
&mut self,
feature_id: &str,
path: Vec<String>,
label: String,
filter: Vec<String>,
multiple: bool,
seed_names: Vec<String>,
)
pub fn begin_ref_select( &mut self, feature_id: &str, path: Vec<String>, label: String, filter: Vec<String>, multiple: bool, seed_names: Vec<String>, )
Enter reference-selection mode for feature feature_id’s param at path.
Seeds the running list from seed_names (the field’s current value), rolls
the model to the pre-feature “before” state (the step just before the
edited feature ran), and highlights the seeded names. filter constrains
the pick kind (["SOLID"], ["FACE"], …); multiple allows a list.
Sourcepub fn ref_select_names(&self) -> Vec<String>
pub fn ref_select_names(&self) -> Vec<String>
The running list of picked names (empty when not active) — the modal UI reads this back to draw its one-per-line list.
Sourcepub fn ref_select_label(&self) -> String
pub fn ref_select_label(&self) -> String
The active field’s label (for the modal heading), or empty.
Sourcepub fn ref_select_prompt(&self) -> String
pub fn ref_select_prompt(&self) -> String
A one-line summary of the active field for the modal heading:
"Tool solids (SOLID, multiple)".
Sourcepub fn ref_select_click(&mut self, x: f64, y: f64)
pub fn ref_select_click(&mut self, x: f64, y: f64)
A viewport click while active: type-constrained-pick the nearest allowed
hit under CSS-pixel (x, y) and add its name to the running list (single
fields replace; multiple fields append, de-duplicated). Re-lights the
highlight. No-op on a miss / an empty (unnamed) hit.
Sourcepub fn ref_select_remove(&mut self, index: usize)
pub fn ref_select_remove(&mut self, index: usize)
Remove the name at index from the running list (the modal’s per-line X).
Sourcepub fn finish_ref_select(&mut self)
pub fn finish_ref_select(&mut self)
Finish: write the running names into the edited feature’s params at the field path, restore the rolled-to step, clear the highlight, and re-run so the feature rebuilds with the chosen references.
Sourcepub fn cancel_ref_select(&mut self)
pub fn cancel_ref_select(&mut self)
Cancel: discard the running selection, clear the highlight, restore the rolled-to step, and re-run (no param change).
Source§impl EngineState
impl EngineState
Sourcepub fn hover_at(&mut self, x: f64, y: f64) -> bool
pub fn hover_at(&mut self, x: f64, y: f64) -> bool
Hover-highlight the TOP-priority pick under CSS-pixel (x, y) whose kind
the selection filter admits, setting it HOVERED in emphasis (the
renderer tints it). A miss — or a filter admitting nothing — clears the
hover. No-ops (returns false, no dirty) when the hovered entity is
unchanged, so a stationary pointer over the same face doesn’t re-render
every frame (the k === prevK early-out). Returns
whether the hover state changed.
Sourcepub fn clear_hover(&mut self) -> bool
pub fn clear_hover(&mut self) -> bool
Clear the hover highlight (pointer moved to empty space / off the
viewport). Bumps the emphasis generation + marks dirty only when a hover
was actually lit. Returns whether it changed. (Distinct from
clear_selection, which leaves hover alone.)
Sourcepub fn hovered_json(&self) -> String
pub fn hovered_json(&self) -> String
The current HOVER (not selection) as JSON
{ solids:[..], faces:[..], edges:[..], vertices: n } — the hover twin of
selection_json so a UI / the headed verifier can
assert that moving the pointer over a face lit the hover emphasis.
Sourcepub fn select_toggle_at(&mut self, x: f64, y: f64) -> bool
pub fn select_toggle_at(&mut self, x: f64, y: f64) -> bool
TOGGLE the top admitted pick under CSS-pixel (x, y) in the current
selection (a Ctrl/Cmd+click): add it if absent, remove it if present,
leaving the rest of the selection intact (unlike [select_top_at], which
REPLACES). With the COMPONENT filter on, a hit on component geometry
toggles the whole component (all member solids as one unit). A miss — or
a filter admitting nothing — leaves the selection untouched (additive
mode never clears). Returns whether a hit was toggled.
Sourcepub fn candidates_at(&self, x: f64, y: f64) -> String
pub fn candidates_at(&self, x: f64, y: f64) -> String
The RANKED, filter-respecting candidates under CSS-pixel (x, y) as JSON
[{kind, name, solid, depth}] — the “candidates under the cursor” list
(feeds the pick-list popup + the headed verifier).
Sorted category-major in the pick-list order (VERTEX > EDGE > FACE >
PLANE > SOLID > COMPONENT), nearest (smallest depth) first within each
category — see candidates_filtered_at.
Sourcepub fn candidates_filtered_at(&self, x: f64, y: f64) -> Vec<PickCandidate>
pub fn candidates_filtered_at(&self, x: f64, y: f64) -> Vec<PickCandidate>
The same ranked, filter-respecting candidate list as typed values (the
in-process egui pick-list popup consumes these directly, then re-hovers /
selects a chosen one via hover_candidate /
select_candidate /
toggle_candidate). EMPTY when the filter admits
nothing (not the pick_filtered “empty filter = any” case).
The raw list is pick_candidates_at, so
construction PLANE cards are ordinary entries here — a plane under other
geometry is listed (right after the faces) instead of being reachable only
on a geometry miss.
With the filter’s COMPONENT lane on, one COMPONENT entry per owning
assembly component of ANY raw hit is appended (name = component id, depth
= the component’s nearest hit) — a raw hit of a filtered-OFF kind still
reaches its owning component, mirroring select_filtered_at’s
component-only promotion (a PLANE hit owns no component). The final list is
sorted category-major in the pick-list order
(VERTEX > EDGE > FACE > PLANE > SOLID > COMPONENT), nearest first within
each category.
Sourcepub fn candidate_is_selected(&self, candidate: &PickCandidate) -> bool
pub fn candidate_is_selected(&self, candidate: &PickCandidate) -> bool
Whether a candidate is CURRENTLY selected (drives the pick-list popup’s per-row selected state so click-toggling reads back visually).
Sourcepub fn hover_candidate(&mut self, candidate: &PickCandidate)
pub fn hover_candidate(&mut self, candidate: &PickCandidate)
Hover a SPECIFIC candidate (the popup entry the pointer is over) — sets it
HOVERED in emphasis, replacing any prior hover.
Sourcepub fn select_candidate(&mut self, candidate: &PickCandidate)
pub fn select_candidate(&mut self, candidate: &PickCandidate)
REPLACE the selection with a specific candidate (a plain click on a popup entry) — reuses the same bucketing as a plain viewport click.
Sourcepub fn toggle_candidate(&mut self, candidate: &PickCandidate) -> bool
pub fn toggle_candidate(&mut self, candidate: &PickCandidate) -> bool
TOGGLE a specific candidate in the selection (a Ctrl/Cmd+click on a popup
entry, or the select_toggle_at hit): add if
absent, remove if present. Returns whether it is NOW selected (true =
added, false = removed). Bumps the emphasis generation + marks dirty.
Source§impl EngineState
impl EngineState
Sourcepub fn set_sketch_overlay(&mut self, session: &SketchSession)
pub fn set_sketch_overlay(&mut self, session: &SketchSession)
Display a solved crate::sketch::SketchSession as a read-only overlay.
The plane geometry is tessellated to world space and pushed via
set_overlay_json; construction dashes are sized
against the LIVE camera so they stay screen-constant.
Sourcepub fn clear_sketch_overlay(&mut self)
pub fn clear_sketch_overlay(&mut self)
Remove the sketch overlay groups (feeding empty same-named groups upserts them to empty, which the overlay channel treats as a removal — other overlay groups are left untouched).
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_dimension_labels_json(&self) -> String
pub fn sketch_dimension_labels_json(&self) -> String
The dimension labels for the active sketch (S5): one entry per dimensional
constraint — [{ id, text, world:[x,y,z], value, valueExpr, mode }]. world
is the label anchor in world space; brep-app projects it via
world_to_screen_json and draws editable text
there. [] when not in sketch mode.
Sourcepub fn sketch_dimension_value_json(&self, constraint_id: &Value) -> String
pub fn sketch_dimension_value_json(&self, constraint_id: &Value) -> String
The current {value, valueExpr, mode} for a dimensional constraint (S5) — the
seed for the inline edit field. {} when the constraint is absent / not in
sketch mode. mode is "distance" | "radius" | "diameter" | "angle". For a
diameter dim value is the DISPLAYED diameter (twice the stored radius), so
the edit field round-trips what the user sees.
Sourcepub fn sketch_set_dimension_value(
&mut self,
constraint_id: &Value,
input: &str,
) -> bool
pub fn sketch_set_dimension_value( &mut self, constraint_id: &Value, input: &str, ) -> bool
Edit a dimensional constraint’s value (S5), a port of the previous double-click edit:
- A PLAIN NUMBER (
^-?\d*\.?\d+$, optional exponent) → setvalueand REMOVEvalueExpr/valueExprMode(a literal dimension). - Otherwise → an EXPRESSION: set
valueExpr, evaluate it LIVE against the history’sexpressions+configurator(the kernel’seval_expression). On eval success setvalue; on FAILURE keep the old value and returnfalse(never corrupt the doc). A diameter dim stores half the entered/ evaluated diameter as the solver radius and tagsvalueExprMode:"diameter".
Sets valueNeedsSetup:false once a real value lands, re-solves (swallowing
errors), refreshes the overlay + marks dirty. Returns whether the value was
applied. No-op returning false when the constraint is absent / not in
sketch mode.
Sourcepub fn sketch_dimension_drag_to(
&mut self,
constraint_id: &Value,
x: f64,
y: f64,
)
pub fn sketch_dimension_drag_to( &mut self, constraint_id: &Value, x: f64, y: f64, )
Drag a dimension label to CSS-pixel (x, y) (S5): map the pixel to plane
(u, v) (the S2 pixel→plane math), compute the label offset {du, dv} =
(label uv) − (the dimension’s anchor uv), and store it in session.dim_offsets
keyed by the constraint id. Refreshes the overlay (leaders + labels follow the
cursor). No-op when not in sketch mode / the ray misses the plane / the
constraint is not dimensional.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_undo(&mut self) -> bool
pub fn sketch_undo(&mut self) -> bool
Undo the last sketch edit (S6a) — pop the undo stack, stash the current state on redo, restore. Returns whether anything was undone. A no-op (false) when not in sketch mode or the stack is empty.
Sourcepub fn sketch_redo(&mut self) -> bool
pub fn sketch_redo(&mut self) -> bool
Redo the last undone sketch edit (S6a) — the inverse of [sketch_undo].
Returns whether anything was redone.
Sourcepub fn sketch_can_undo(&self) -> bool
pub fn sketch_can_undo(&self) -> bool
Whether a sketch undo is available (drives the mode-bar Undo button).
Sourcepub fn sketch_can_redo(&self) -> bool
pub fn sketch_can_redo(&self) -> bool
Whether a sketch redo is available (drives the mode-bar Redo button).
Sourcepub fn sketch_dimension_drag_end(&mut self)
pub fn sketch_dimension_drag_end(&mut self)
End a dimension-label drag gesture (S6a): reset the first-move snapshot guard so the NEXT drag records its own single undo step. No-op when not in sketch mode. Called from the viewport when the label drag stops.
Sourcepub fn sketch_diagnostics_dump_json(&self, feature_id: &str) -> String
pub fn sketch_diagnostics_dump_json(&self, feature_id: &str) -> String
A debug dump of a SKETCH feature’s document + solved diagnostics (S6a — the
dumpSketchDiagnostics button). Uses the LIVE session when that feature is
being edited, else reads the persisted sketch/basis off the history and
solves a throwaway session. Returns { error } when the feature is absent /
not a sketch / unparseable.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_trim_at(&mut self, x: f64, y: f64) -> bool
pub fn sketch_trim_at(&mut self, x: f64, y: f64) -> bool
Trim the geometry under CSS-pixel (x, y) (S6b): map to plane uv (the S2
pixel→plane math) and trim the geometry there. Returns whether the doc
changed. A no-op returning false when not in sketch mode, the ray misses the
plane, or no geometry is under the cursor.
Sourcepub fn sketch_trim_uv(&mut self, u: f64, v: f64) -> bool
pub fn sketch_trim_uv(&mut self, u: f64, v: f64) -> bool
The plane-space trim core (sketch_trim_at delegates here; so does the tool
state machine, which already has uv). Picks the nearest geometry within the
grab radius, snapshots undo, trims it (split or delete), re-solves + refreshes.
Returns whether the doc changed; a no-op pops its own undo snapshot so it never
leaves a dead step.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_pick_edge_at(&mut self, x: f64, y: f64) -> bool
pub fn sketch_pick_edge_at(&mut self, x: f64, y: f64) -> bool
Link (as a construction reference) the 3D solid edge under CSS-pixel (x, y)
into the active sketch (S6b-2). Ranks the pixel through the modeling picker,
takes the top EDGE candidate, and delegates to [sketch_link_edge]. Returns
whether a link was made / updated. A no-op returning false when not in sketch
mode or no scene edge is under the cursor.
Sourcepub fn sketch_link_edge(&mut self, edge_name: &str) -> bool
pub fn sketch_link_edge(&mut self, edge_name: &str) -> bool
Link a scene edge by kernel NAME into the active sketch as an external
reference (the headless-testable core sketch_pick_edge_at delegates to).
Fetches the edge’s world polyline from the scene, projects it into the sketch
plane, classifies + materializes (or updates) the reference, records one undo
snapshot (popped on a no-op), re-solves, and refreshes. Returns whether the doc
changed. A no-op returning false when not in sketch mode or the edge is
absent / degenerate.
Sourcepub fn sketch_external_ref_count(&self) -> usize
pub fn sketch_external_ref_count(&self) -> usize
The number of external-reference edge links in the active sketch (0 when not in
sketch mode) — the __brepSketch verifier readout.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_handdraw_begin(&mut self, x: f64, y: f64)
pub fn sketch_handdraw_begin(&mut self, x: f64, y: f64)
Begin a freehand stroke at CSS-pixel (x, y) (a handdraw drag start): map to
plane uv and delegate. No-op when not in sketch mode or the ray misses the plane.
Sourcepub fn sketch_handdraw_move(&mut self, x: f64, y: f64)
pub fn sketch_handdraw_move(&mut self, x: f64, y: f64)
Extend the freehand stroke toward CSS-pixel (x, y) (a handdraw drag move).
Sourcepub fn sketch_handdraw_begin_uv(&mut self, u: f64, v: f64)
pub fn sketch_handdraw_begin_uv(&mut self, u: f64, v: f64)
Begin a freehand stroke at plane (u, v) (the headless-testable core): snapshot
for undo (S6a), clear any prior stroke, and seed it with the start sample. The
undo snapshot is popped in [sketch_handdraw_end] if the stroke produces nothing.
No-op when not in sketch mode.
Sourcepub fn sketch_handdraw_move_uv(&mut self, u: f64, v: f64)
pub fn sketch_handdraw_move_uv(&mut self, u: f64, v: f64)
Append plane (u, v) to the live stroke (the headless-testable core), throttled
so a sample nearer than ~2px world to the last is skipped. No-op when not in
sketch mode or no stroke is live.
Sourcepub fn sketch_handdraw_end(&mut self) -> bool
pub fn sketch_handdraw_end(&mut self) -> bool
End the freehand stroke (a handdraw drag stop): recognize it into one shape and
materialize the geometry, re-solve, and clear the stroke + preview. A stroke that
is too short (fewer than 3 samples) or too tiny (extent below the grab radius) is
discarded, popping the undo snapshot recorded at begin so no dead step remains.
Returns whether geometry was created. No-op returning false when not in sketch
mode / no stroke is live.
Sourcepub fn sketch_handdraw_len(&self) -> usize
pub fn sketch_handdraw_len(&self) -> usize
The number of samples in the live handdraw stroke (0 when none / not in sketch
mode) — the __brepSketch verifier readout.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_uv_at(&self, x: f64, y: f64) -> Option<(f64, f64)>
pub fn sketch_uv_at(&self, x: f64, y: f64) -> Option<(f64, f64)>
Map CSS-pixel (x, y) to the active sketch plane’s (u, v) via the camera
pick ray ∩ the sketch plane. None when not in sketch mode or the ray misses
the plane (parallel / behind).
Sourcepub fn sketch_hover_at(&mut self, x: f64, y: f64) -> bool
pub fn sketch_hover_at(&mut self, x: f64, y: f64) -> bool
Update the sketch hover to the entity under CSS-pixel (x, y) (S2). Returns
whether the hover changed. A no-op returning false when not in sketch mode.
Sourcepub fn sketch_clear_hover(&mut self) -> bool
pub fn sketch_clear_hover(&mut self) -> bool
Clear the sketch hover (pointer left the viewport / moved over the ViewCube). Returns whether a hover was cleared.
Sourcepub fn sketch_click_at(&mut self, x: f64, y: f64, additive: bool)
pub fn sketch_click_at(&mut self, x: f64, y: f64, additive: bool)
Click-select in sketch mode: pick the entity under (x, y); nothing → clear
the selection. Otherwise honor the SAME “Multi-select” setting the 3D viewport
reads (settings.multi_select): under ClickToggles a plain click toggles the
hit in the set (no modifier needed for a multi-selection); under
CtrlClick a plain click replaces the set with just the hit and additive
(Ctrl/Cmd) toggles. Re-pushes the overlay + marks dirty.
Sourcepub fn sketch_drag_begin(&mut self, x: f64, y: f64) -> bool
pub fn sketch_drag_begin(&mut self, x: f64, y: f64) -> bool
Begin a point drag if a DRAGGABLE point is under (x, y) (S2): remember it
(id + original fixed flag). Returns true iff a point was grabbed (the
viewport routes the drag to the sketch; otherwise it orbits the camera). A
locked / fully-constrained point is not draggable, so an empty-space or
locked-point drag falls through to a camera orbit.
Sourcepub fn sketch_drag_to(&mut self, x: f64, y: f64)
pub fn sketch_drag_to(&mut self, x: f64, y: f64)
Drag the grabbed target to (x, y) (S2): pin every grabbed point at its
ORIGINAL position plus the cursor delta (fixed = true) so the solver anchors
the whole shape there, re-solve, then restore each point’s ORIGINAL fixed
flag. Absolute-from-anchor (never incremental), so a rigid geometry translate
tracks the cursor 1:1 without drifting as the solver nudges points between
frames. A resolve error rolls every grabbed point back to its pre-drag coords
(the last good state). No-op when nothing is grabbed / not in sketch mode / the
ray misses the plane.
Sourcepub fn sketch_drag_end(&mut self)
pub fn sketch_drag_end(&mut self)
End a point drag (S2): clear the grab, then one final re-solve + overlay refresh. No-op when no drag is live.
Sourcepub fn sketch_selection_count(&self) -> usize
pub fn sketch_selection_count(&self) -> usize
The number of selected sketch entities (0 when not in sketch mode) — the mode bar / verifier readout.
Sourcepub fn sketch_selected_constraint_count(&self) -> usize
pub fn sketch_selected_constraint_count(&self) -> usize
The number of selected CONSTRAINTS (refs whose kind is "constraint"; 0 when
not in sketch mode) — the __brepSketch verifier readout for constraint
selection + delete.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_set_tool(&mut self, tool: Option<&str>)
pub fn sketch_set_tool(&mut self, tool: Option<&str>)
Set (or clear) the active draw tool: "select"/None → selection mode (S2);
"point"|"line"|"rect"|"circle"|"arc"|"bezier" arm the corresponding draw
tool; "handdraw" arms the freehand stroke tool (S6b-3); "trim" arms the
trim tool (S6b); "pickEdges" arms the external-edge link tool (S6b-2). Clears
any in-progress click buffer + preview and refreshes the overlay. No-op when not
in sketch mode.
Sourcepub fn sketch_active_tool(&self) -> Option<&str>
pub fn sketch_active_tool(&self) -> Option<&str>
The active draw tool ("point"|"line"|"rect"|"circle"|"arc"), or None in
selection mode / when not in sketch mode.
Sourcepub fn sketch_pending_len(&self) -> usize
pub fn sketch_pending_len(&self) -> usize
The number of in-progress draw-tool clicks buffered (0 in selection mode / when not in sketch mode) — the UI/preview + verifier readout.
Sourcepub fn sketch_tool_click_at(&mut self, x: f64, y: f64)
pub fn sketch_tool_click_at(&mut self, x: f64, y: f64)
A draw-tool click at CSS-pixel (x, y): map to plane uv (the S2 pixel→plane
math) and drive the tool state machine. No-op when not in sketch mode, in
selection mode, or the ray misses the plane.
Sourcepub fn sketch_tool_place_uv(&mut self, u: f64, v: f64)
pub fn sketch_tool_place_uv(&mut self, u: f64, v: f64)
The per-tool placement logic, in plane (u, v) (the headless-testable core
sketch_tool_click_at delegates to). Snaps to existing points within the grab
radius so shared vertices coincide; appends geometry and re-solves when a
primitive completes; carries the line chain via pending.
Sourcepub fn sketch_tool_cancel(&mut self)
pub fn sketch_tool_cancel(&mut self)
Abort the in-progress draw geometry (Escape / right-click): clear the pending clicks + preview and refresh. No-op when not in sketch mode.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_auto_constrain(&mut self) -> usize
pub fn sketch_auto_constrain(&mut self) -> usize
Auto-constrain the active sketch (the toolbar’s one-click “constrain what I
roughed in”): infer ━/│ on nearly-axis-aligned lines and ≡ between
near-coincident points, then re-solve. Records ONE undo step, popped when the
pass adds nothing so a dead click neither pollutes undo nor clobbers redo.
Returns the number of constraints added; a no-op (0) when not in sketch mode.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_delete_selection(&mut self) -> bool
pub fn sketch_delete_selection(&mut self) -> bool
Delete the selected sketch entities (S3b): the selected geometries + points,
plus any geometry orphaned by a deleted vertex, plus orphaned points and the
constraints referencing any removed point. Re-solves + refreshes the overlay.
Returns true when something was deleted; false when not in sketch mode or
the selection is empty.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_mode(&self) -> bool
pub fn sketch_mode(&self) -> bool
True while a sketch is being edited (the shell hides the normal side panel and shows the sketch-mode bar).
Sourcepub fn sketch_edit_session(&self) -> Option<&SketchSession>
pub fn sketch_edit_session(&self) -> Option<&SketchSession>
The live sketch session while in sketch mode (for the DOF readout / overlay
/ the headless verifier), else None.
Sourcepub fn sketch_edit_feature_id(&self) -> Option<&str>
pub fn sketch_edit_feature_id(&self) -> Option<&str>
The id of the feature being edited while in sketch mode, else None.
Sourcepub fn sketch_camera_locked(&self) -> bool
pub fn sketch_camera_locked(&self) -> bool
Whether the sketch camera is locked flat to the plane (only panning). On by default every sketch entry; the sketch-mode bar’s checkbox reflects this.
Sourcepub fn toggle_sketch_camera_lock(&mut self)
pub fn toggle_sketch_camera_lock(&mut self)
Toggle the sketch camera lock. Turning it ON re-faces the camera to the current sketch plane (so “off → spin around → on” snaps back flat); turning it OFF just frees orbiting. No-op outside sketch mode.
Sourcepub fn enter_sketch_mode(&mut self, feature_id: &str) -> Result<String, String>
pub fn enter_sketch_mode(&mut self, feature_id: &str) -> Result<String, String>
Enter sketch mode for the "S" feature with id feature_id: snapshot the
camera + rolled-to step, roll to the step BEFORE the sketch (its backdrop),
read the persisted plane basis + sketch doc off the history JSON, solve
a live session, orient the camera onto the plane, and push the read-only
overlay. Returns the session’s diagnostics JSON. Errors when the feature is
absent or is not a sketch.
Sourcepub fn exit_sketch_mode(&mut self, commit: bool) -> String
pub fn exit_sketch_mode(&mut self, commit: bool) -> String
Exit sketch mode. commit writes the edited doc back to the feature’s
persistentData.sketch; a non-commit exit of a brand-new sketch DELETES the
feature (a fresh sketch nobody kept). Restores the snapshotted camera +
rolled-to step, clears the overlay, re-runs the history, and returns the
build report. A no-op (returns "{}") when not in sketch mode.
Sourcepub fn new_sketch(&mut self, plane: &str) -> Result<String, String>
pub fn new_sketch(&mut self, plane: &str) -> Result<String, String>
Create a NEW engine-native sketch on a base plane ("XY" | "XZ" | "YZ") and
enter sketch mode on it. The feature persists an analytic basis (computed
via crate::sketch::PlaneFrame) and an empty sketch doc; a cancel exit
deletes it. Returns the new session’s diagnostics JSON. Errors on an unknown
plane name.
Source§impl EngineState
impl EngineState
Sourcepub fn push_notice(&mut self, message: impl Into<String>)
pub fn push_notice(&mut self, message: impl Into<String>)
Queue a transient user-facing notice (shown as a toast by the shell) and, on native, also log it. Bounded so a pathological loop can’t grow it.
Sourcepub fn take_notices(&mut self) -> Vec<String>
pub fn take_notices(&mut self) -> Vec<String>
Drain the queued notices (the shell calls this once per frame and shows each as a toast).
Sourcepub fn sketch_point_rows(&self) -> Vec<SketchEntityRow>
pub fn sketch_point_rows(&self) -> Vec<SketchEntityRow>
The Points list: P{id} (x, y) plus ⛓ external / ◐ construction / ⏚ ground
markers, mirroring the previous Points rows.
Sourcepub fn sketch_geometry_rows(&self) -> Vec<SketchEntityRow>
pub fn sketch_geometry_rows(&self) -> Vec<SketchEntityRow>
The Curves list: {type}:{id} [p0,p1,…] (◐ for construction), mirroring the
previous Curves rows.
Sourcepub fn sketch_constraint_rows(&self) -> Vec<SketchEntityRow>
pub fn sketch_constraint_rows(&self) -> Vec<SketchEntityRow>
The Constraints list: {id} {type} {value} [points], mirroring the previous
Constraints rows.
Sourcepub fn sketch_select_entity(&mut self, kind: &str, id: Value, additive: bool)
pub fn sketch_select_entity(&mut self, kind: &str, id: Value, additive: bool)
Select an entity BY ref from a list row (mirrors [sketch_click_at]): honors the
SAME “Multi-select” setting — under ClickToggles a plain click toggles the row
(no modifier needed); under CtrlClick a plain click replaces the
selection and an additive (Ctrl/Cmd) click toggles.
Sourcepub fn sketch_hover_entity(&mut self, kind: &str, id: Value)
pub fn sketch_hover_entity(&mut self, kind: &str, id: Value)
Hover an entity BY ref from a list row (list→canvas highlight). Sets the one-frame guard so the viewport — which draws after the panel and would otherwise clear the hover because the pointer is off the viewport — keeps it.
Sourcepub fn take_sketch_list_hover(&mut self) -> bool
pub fn take_sketch_list_hover(&mut self) -> bool
Consume the “list panel set the hover this frame” guard (read + reset). The
viewport calls this before its off-viewport sketch_clear_hover so a
panel-set hover survives the frame.
Sourcepub fn sketch_solver_settings(&self) -> Option<SketchSolverSettings>
pub fn sketch_solver_settings(&self) -> Option<SketchSolverSettings>
The active sketch’s solver settings (the Solver Settings panel reads this).
None when not editing a sketch.
Sourcepub fn sketch_set_solver_settings(&mut self, settings: SketchSolverSettings)
pub fn sketch_set_solver_settings(&mut self, settings: SketchSolverSettings)
Replace the active sketch’s solver settings and re-solve so the change takes effect immediately. No-op when not editing a sketch.
Source§impl EngineState
impl EngineState
Sourcepub fn sketch_applicable_constraints(&self) -> Vec<SketchConstraintAction>
pub fn sketch_applicable_constraints(&self) -> Vec<SketchConstraintAction>
The ordered palette of constraints applicable to the active sketch selection
(a faithful port of #refreshContextBar). Empty when not in sketch mode or
the selection surfaces no constraint. The Fix/Unfix + construction + cleanup
affordances are exposed separately (see sketch_selection_all_grounded /
sketch_selection_all_construction / sketch_cleanup_unused_points).
Sourcepub fn sketch_add_constraint(&mut self, symbol: &str) -> bool
pub fn sketch_add_constraint(&mut self, symbol: &str) -> bool
Add the constraint named by symbol from the current selection (a port of
createConstraint): build the ordered point-id list, dedup on
type + sorted-points, append (dimensional → value:null), then re-solve +
refresh (keeping the selection). Returns whether a constraint was added.
Sourcepub fn sketch_toggle_ground(&mut self) -> bool
pub fn sketch_toggle_ground(&mut self) -> bool
Toggle the ground (⏚) constraint on the selected points: if ALL selected
points are already grounded → remove those grounds (and clear their fixed
flag); else add a ⏚ for each ungrounded selected point (and set fixed).
Re-solves + refreshes. Returns whether anything changed. No-op with no point
selected / not in sketch mode.
Sourcepub fn sketch_toggle_construction(&mut self) -> bool
pub fn sketch_toggle_construction(&mut self) -> bool
Flip the construction flag on ALL selected points AND geometries: if every
selected entity is already construction → make them regular, else make them
all construction. Re-solves + refreshes. Returns whether anything was
selected. No-op with nothing selected / not in sketch mode.
Sourcepub fn sketch_cleanup_unused_points(&mut self) -> bool
pub fn sketch_cleanup_unused_points(&mut self) -> bool
Remove points referenced by NO geometry AND no constraint (the 🧹 action). Re-solves + refreshes only when something was dropped. Returns whether a point was removed. No-op when not in sketch mode.
Sourcepub fn sketch_constraint_count(&self) -> usize
pub fn sketch_constraint_count(&self) -> usize
The number of constraints in the active sketch (0 when not in sketch mode) — the verifier / palette readout.
Sourcepub fn sketch_selection_all_grounded(&self) -> Option<bool>
pub fn sketch_selection_all_grounded(&self) -> Option<bool>
Whether the selected points are ALL grounded (Some(true)), NOT all grounded
(Some(false)), or no point is selected (None) — labels the Fix vs Unfix
button.
Sourcepub fn sketch_selection_all_construction(&self) -> Option<bool>
pub fn sketch_selection_all_construction(&self) -> Option<bool>
Whether the selected points + geometries are ALL construction (Some(true)),
NOT all construction (Some(false)), or nothing is selected (None) — labels
the ◐ construction-toggle button’s direction.
Source§impl EngineState
impl EngineState
Sourcepub fn transform_armed(&self) -> bool
pub fn transform_armed(&self) -> bool
Whether the TRANSFORM gizmo (move/rotate) is armed for ANY feature. False in dimension mode — the two ◎ modes are exclusive, so the transform gizmo arms/handles never render while dimensions are shown.
Sourcepub fn transform_armed_feature(&self) -> String
pub fn transform_armed_feature(&self) -> String
The transform-gizmo-armed feature id (empty unless in transform mode).
Sourcepub fn transform_armed_for(&self, feature_id: &str) -> bool
pub fn transform_armed_for(&self, feature_id: &str) -> bool
Whether the TRANSFORM gizmo is armed for THIS feature.
Sourcepub fn arm_transform(&mut self, feature_id: &str)
pub fn arm_transform(&mut self, feature_id: &str)
Arm the TRANSFORM gizmo for feature_id and feed it at the feature’s
transform frame. Re-arming a different feature moves the gizmo to it.
Clears any dimension overlay (the modes are exclusive).
An ACOMP (assembly component) feature ROUTES to the component Move gizmo
instead: its transform is the component pose ({translate, rotateEulerDeg}, a different shape), its gizmo attaches at the member
bbox center, commits on release, and refuses fixed instances — the
generic position/rotationEuler gizmo must never write its keys into an
ACOMP’s params. This covers the history panel’s arm-on-expand path too.
Sourcepub fn disarm_transform(&mut self)
pub fn disarm_transform(&mut self)
Disarm: hide BOTH gizmos + drop any in-flight drag. Also resets the component Move gizmo (the widget slot is shared, so a disarm clears whichever controller was feeding it).
Sourcepub fn sync_transform_gizmo(&mut self)
pub fn sync_transform_gizmo(&mut self)
(Re)feed the widget gizmo at the armed feature’s frame: origin =
position, axes = the feature’s rotated basis (intrinsic XYZ Euler order, matching
the kernel bake). Auto-disarms if the feature vanished. Called every drag
frame from transform_drag_to so the widget tracks the moving pose live
(Fix 3); the drag delta resolves against the frozen grab frame, so this
re-sync never feeds back into the drag math.
Sourcepub fn feature_has_transform(&self, feature_id: &str) -> bool
pub fn feature_has_transform(&self, feature_id: &str) -> bool
Whether the feature schema exposes the shared Transform controls. Capability belongs to the schema, not to which default-valued fields happen to have been serialized in the model.
Sourcepub fn transform_gizmo_anchor(&self) -> Option<(f64, f64)>
pub fn transform_gizmo_anchor(&self) -> Option<(f64, f64)>
The armed gizmo origin projected to VIEWPORT-LOCAL px (the center handle
sits here). The history panel publishes it so the headed verifier can
locate + drag the gizmo. None when disarmed / not projectable (the ONE
crate::view::ViewCamera::projectable policy — ortho always projects).
Sourcepub fn transform_axis_labels_json(&self) -> String
pub fn transform_axis_labels_json(&self) -> String
The transform gizmo’s axis-end labels as JSON:
[{ text:"XC"|"YC"|"ZC", rgb:[r,g,b], world:[x,y,z] }]. The app projects
each world point and draws the colored egui label just past the matching
cone tip (X=red, Y=green, Z=blue). [] unless the TRANSFORM gizmo is armed.
Sourcepub fn transform_hit_areas_json(&self) -> String
pub fn transform_hit_areas_json(&self) -> String
DEBUG overlay: the EXACT SCREEN-space (viewport-local px) pickable regions
of the transform gizmo — the SAME [hit_regions](brep_gizmos::transform::
TransformGizmo::hit_regions) the hit test 2D-tests the cursor against — so
the red outline can NEVER drift from the grabbable area. Each item is a
{ kind:"capsule", a:[x,y], b:[x,y], r } (axis arrows) or
{ kind:"circle", c:[x,y], r } (center + rotation grab spheres); the app
only offsets by rect.min to draw. Projection + the perspective front-clip
already happened in the region builder. The WIDGET FEED is authoritative —
exactly like transform_pick, which has no mode
gate — so this emits for EVERY controller of the shared widget gizmo (the
feature TRANSFORM mode and the assembly component Move gizmo alike) and is
[] precisely when the widget is hidden (nothing is grabbable).
Sourcepub fn transform_press(&mut self, x: f64, y: f64) -> bool
pub fn transform_press(&mut self, x: f64, y: f64) -> bool
Begin a gizmo drag at viewport px (x, y) when the gizmo is armed AND a
handle is under the pointer. Returns whether a handle was grabbed — the
viewport routes the drag to the gizmo (not the camera) when true; a press
on empty space returns false and still orbits.
Sourcepub fn transform_dragging(&self) -> bool
pub fn transform_dragging(&self) -> bool
Whether a gizmo handle drag is in flight.
Sourcepub fn transform_drag_to(&mut self, cx: f64, cy: f64)
pub fn transform_drag_to(&mut self, cx: f64, cy: f64)
Continue the in-flight gizmo drag to viewport px (cx, cy): resolve the
world delta from the grab (against the frozen grab-time frame), apply it to
the grab pose, write it back into the feature’s transform, and re-run so
the model follows live. Then re-sync the VISIBLE gizmo to the moved pose so
the widget tracks the pointer in real time (Fix 3) — the delta stays
anchored to drag.start, so this visual sync never feeds back on itself.
Sourcepub fn transform_release(&mut self)
pub fn transform_release(&mut self)
End the drag: clear the active-handle highlight + re-sync the gizmo to the feature’s final (moved) pose (unpin the frame).
Source§impl EngineState
impl EngineState
Source§impl EngineState
impl EngineState
Sourcepub fn object_metadata_json(&self, name: &str) -> String
pub fn object_metadata_json(&self, name: &str) -> String
One object’s metadata record as JSON { key: value, ... } ({} if none).
Sourcepub fn set_metadata_attribute(&mut self, name: &str, key: &str, value: &str)
pub fn set_metadata_attribute(&mut self, name: &str, key: &str, value: &str)
Set (or overwrite) one metadata attribute of an object by NAME. String
value; the well-known density key drives the object’s weight and the
well-known color key drives its shaded colour.
Sourcepub fn remove_metadata_attribute(&mut self, name: &str, key: &str) -> bool
pub fn remove_metadata_attribute(&mut self, name: &str, key: &str) -> bool
Remove one metadata attribute of an object. Returns whether it existed.
Sourcepub fn sync_colors_from_metadata(&mut self) -> bool
pub fn sync_colors_from_metadata(&mut self) -> bool
Re-derive the display scene’s colours from the metadata store — the ONE
call that connects the durable color attribute to the renderer.
Every colour the viewport shows comes from here: a STEP import’s stamped
body/face colours, a colour typed or picked in the Info window, a colour
restored from a saved document. The store is the authority; the display’s
color_override fields are a derived cache of it, rebuilt after every
history apply (EngineState::finish_apply), on every document load, on
a metadata edit, and whenever the display setting flips.
crate::style::RenderSettings::override_model_colors is honoured HERE
rather than in the renderer, and it is deliberately a READ of the store,
never a write: ticking the box resolves every colour to None so the
viewport falls back to faceColorMode, while the stored attributes stay
exactly as they were. Unticking restores them from the same records.
Returns whether anything changed, and marks the engine dirty only then — the no-op case must stay free, since this runs after every single run.
Sourcepub fn metadata_json(&self) -> String
pub fn metadata_json(&self) -> String
The whole metadata store as JSON { name: { key: value } }.
Source§impl EngineState
impl EngineState
Sourcepub fn creating_feature(&self, name: &str) -> Option<(String, String)>
pub fn creating_feature(&self, name: &str) -> Option<(String, String)>
The feature that an object ORIGINATES from, as (feature id, feature type).
For a FACE/EDGE this is the feature that first gave it its name (its true
origin, from the eager entity_origin first-writer map) — NOT the owning
solid’s last producer — so “Edit owning feature” rolls back to where the
entity was born. For a SOLID it’s the solid’s producer (last writer, the
eager provenance map). None if the name is unknown or has no known
producer. Reads only the eager maps the last run shipped, so it never re-runs
the history — the freeze side-door context_bar hit every selected frame is
now O(1).
Sourcepub fn is_sheet_metal_object(&self, name: &str) -> bool
pub fn is_sheet_metal_object(&self, name: &str) -> bool
Whether the object name (a solid, or a face/edge owned by a solid) sits
on a SHEET-METAL body — its owning display solid carries the sheet-metal
marker the pipeline stamped from the resident handle’s SheetTree. Reads
only the display scene, so it is O(1) and thread-safe (no SheetTree
thread-local touched on the UI thread — [crate::scene::SolidDisplay:: is_sheet_metal]). The gate for the sheet-metal edit features (SM Flange /
Fillet / Chamfer). false for an unknown name or a synthesized sketch
sheet (no resident handle, no tree).
Sourcepub fn object_info_json(&mut self, name: &str) -> String
pub fn object_info_json(&mut self, name: &str) -> String
The full Properties-panel info for an object by NAME: its resolved kind, the right measurements, and provenance. Units are millimetres.
- Solid —
{ ok, name, kind:"solid", volume, surfaceArea, edgeLengthTotal, density, weight, creatingFeature }, whereweight = density · volumeanddensitycomes from the object’s metadata (defaultDEFAULT_DENSITY). - Face —
{ ok, name, kind:"face", solid, surfaceType, area, edgeLengthTotal, creatingFeature }(edgeLengthTotal= its boundary edges;surfaceType= the carrier-surface classification, e.g."Plane"/"Cylinder"/"Cone"/"Sphere"/"Torus"/"NURBS"). - Edge —
{ ok, name, kind:"edge", solid, length, creatingFeature }.
{ ok:false, name, message } for an empty/unknown name, a non-resident
solid, or a kernel measurement failure.
The real solid/face/edge MEASUREMENT is routed to the HistoryRunner (so
the warm-registry runner answers it, never the potentially-cold main side)
and CACHED here keyed by name — fired once per selection, served from the
cache every subsequent frame. For the synchronous
InlineRunner the submit → pump_queries
resolves same-call, so this returns the merged JSON immediately and stays
byte-identical to the pre-seam in-process result; a background
ThreadRunner returns a pending placeholder
for the frame(s) until its reply lands (drained by pump_queries). The cache
is invalidated on any geometry change (apply_run_output) or metadata edit
(set_metadata_attribute).
Sourcepub fn pump_queries(&mut self)
pub fn pump_queries(&mut self)
Drain every completed measurement reply from the runner and fold it into the
name-keyed info cache — the query counterpart of EngineState::pump. Called
once per frame from pump AND synchronously from
Self::object_info_json (so the Inline runner resolves same-call). Each
reply is MERGED with the main-injected name + creatingFeature (from the
eager provenance) into the final object-info JSON.
Source§impl EngineState
impl EngineState
Sourcepub fn set_entity_visible(
&mut self,
solid: &str,
kind: EntityKind,
index: usize,
visible: bool,
) -> bool
pub fn set_entity_visible( &mut self, solid: &str, kind: EntityKind, index: usize, visible: bool, ) -> bool
Show/hide ONE face/edge/vertex of a solid, by its index in the solid’s face/edge/vertex list — the same index the Scene tree enumerates. Marks dirty. Returns false if the solid is unknown.
Sourcepub fn set_group_visible(
&mut self,
solid: &str,
kind: EntityKind,
visible: bool,
) -> bool
pub fn set_group_visible( &mut self, solid: &str, kind: EntityKind, visible: bool, ) -> bool
Show/hide a WHOLE group (all faces / all edges / all vertices of a solid). Marks dirty. Returns false if the solid is unknown.
Sourcepub fn entity_visible(
&self,
solid: &str,
kind: EntityKind,
index: usize,
) -> Option<bool>
pub fn entity_visible( &self, solid: &str, kind: EntityKind, index: usize, ) -> Option<bool>
Whether entity index of kind on solid is shown (None if unknown).
Sourcepub fn group_visibility(
&self,
solid: &str,
kind: EntityKind,
) -> Option<GroupState>
pub fn group_visibility( &self, solid: &str, kind: EntityKind, ) -> Option<GroupState>
The group tristate for solid’s kind (None if the solid is unknown).
Sourcepub fn scene_visibility_json(&self) -> String
pub fn scene_visibility_json(&self) -> String
Per-entity + group visibility as JSON — the readout the headed verifier
asserts against (a companion to
scene_entities_json, which lists the
entities but not their per-entity visibility):
[{name, visible, faces:{group, states:[bool;n]}, edges:{…}, vertices:{…}}]
where states[i] is entity i’s visibility and group is
"all"|"partial"|"none".
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for EngineState
impl !Send for EngineState
impl !Sync for EngineState
impl !UnwindSafe for EngineState
impl Freeze for EngineState
impl Unpin for EngineState
impl UnsafeUnpin for EngineState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more