Skip to content

Non-Planar controls

Status: PROPOSED

The control set and workflows come from docs/ui/ui-plan.md:181–195,223–227,277–285. Only Enable reaches generation today. Every other non-planar field, region operation, and non-planar overlay on this page is PROPOSED.

The panel is deliberately first in Prepare: it states the product decision before conventional Process values. It is expanded by default.

Control-by-control honesty

Control User-facing meaning Range / choices Engine or host hook Honesty
Enable Turn non-planar variation on for generation Off / On Existing NpsGcodeGenParams.enableNonPlanar HOW IT IS — the current checkbox binds EnableNonPlanar (src/SlicerApp/MainWindow.axaml:47–50), and the host packs it as 0 / 1 (src/Nps.EngineHost/EngineSession.cs:336–352)
Maximum surface angle Limit surfaces eligible for non-planar finishing 0–75° New SetNonPlanarParams.maxSurfaceAngleDeg PROPOSED
Maximum amplitude Cap toolpath Z deviation millimetres New SetNonPlanarParams.maxAmplitudeMm PROPOSED
Thickness envelope Blend the non-planar transition through adjacent layers millimetres New SetNonPlanarParams.thicknessEnvelopeMm PROPOSED
Nozzle clearance radius Radial collision envelope around the nozzle millimetres New collisionRadiusMm PROPOSED
Gantry clearance height Vertical collision envelope millimetres New collisionHeightMm PROPOSED
Detection mode Choose how candidate regions originate Auto / Paint / Full New detectionMode PROPOSED
Seam policy Choose seam placement policy Aligned / Nearest / Random / Painted New seamPolicy PROPOSED
Detect regions Compute automatic candidates Button New DetectNonPlanarRegions + GetNonPlanarRegions PROPOSED
Paint regions Enter viewport brush mode Button / toolbar toggle / B Host paint state; commit through new ApplyRegionPaintStrokes PROPOSED
Region list Show each region and its source Auto / Painted badges New GetNonPlanarRegions PROPOSED
Per-region override Change amplitude/policy for one region Field-level deltas New SetNonPlanarRegionOverride PROPOSED
Remove region Delete a selected region Action in Regions tab New RemoveNonPlanarRegion PROPOSED

What Enable means today

The current route calls GenerateGcode, whose host facade is explicitly named GenerateDemoToolpath and documented as not a production slice (src/Nps.EngineHost/EngineSession.cs:330–336,363–389). Enable proves the parameter path; it does not make the proposed angle, amplitude, clearance, detection, or region controls real.

When Enable is off, all dependent controls are disabled with the visible reason Enable Non-Planar first. Values may remain displayed, but they do not imply that the engine consumed them.

Planned parameter object

PROPOSED — the new numeric/policy fields travel together in an additive POD:

NpsNonPlanarParams
  maxSurfaceAngleDeg
  maxAmplitudeMm
  thicknessEnvelopeMm
  collisionRadiusMm
  collisionHeightMm
  detectionMode
  seamPolicy
  reserved[8]

The reserved tail follows the additive ABI policy. The exact binary layout is a developer contract; users see units, ranges, and disabled reasons rather than ABI field names.

Region detection and painting

flowchart TD
  E["Enable Non-Planar"] --> M{"Detection mode"}
  M -->|Auto / Full| D["Detect regions"]
  M -->|Paint| P["Enter paint mode"]
  D --> L["Region list: auto badge"]
  P --> B["LMB paint · Shift+LMB erase · Esc exit"]
  B --> C["Commit strokes"]
  C --> L2["Region list: painted badge"]
  L --> O["Optional per-region override"]
  L2 --> O
  O --> R["Re-slice"]

Detect

PROPOSED — Detect is enabled only when a model is loaded and Non-Planar is on. It runs detection with the panel parameters, then replaces/updates the region list. Every row shows:

  • region name/id;
  • auto or painted source badge;
  • affected plate/object;
  • inherited versus overridden values;
  • a focus action that opens the Regions inspector.

Detection failure keeps the prior list and reports the engine error in status and Activity. The UI does not show a fake successful empty list.

Paint

PROPOSED — Paint can be entered from the panel, toolbar, or B:

Gesture / control Effect
Left-drag on mesh Add eligible faces to the active region
Shift + left-drag Erase faces from the region
Radius slider Change brush footprint
Esc Exit paint mode without triggering another bare-key action
Commit Send accumulated strokes through ApplyRegionPaintStrokes

The viewport uses existing mesh geometry queries for hit geometry (GetVertexPositions / GetTriangleIndices exist at src/Nps.EngineHost/NpsAbi.cs:309–316). The paint-stroke commit and region-mask overlay are PROPOSED.

Regions inspector

PROPOSED — the Regions tab is the full editor. It mirrors the compact Prepare list and adds focus, override, delete, and re-detect actions. Edits mark the current generated path dirty; they do not recolor an old path as if it had been regenerated.

Planned non-planar overlays

Color-by id Shows Source Honesty
region-mask Planar bulk versus non-planar finish regions New region data, applied through the existing overlay pipeline PROPOSED
nonplanar-amplitude Per-move Z deviation / amplitude New ComputeNonPlanarFields, then existing heatmap application PROPOSED
collision-risk Clearance margin and violations New ComputeCollisionField PROPOSED

The three ids must enter the engine overlay registry and surface through the existing GetSupportedOverlayIds export before the dropdown presents them. GetSupportedOverlayIds exists today (src/Nps.EngineHost/NpsAbi.cs:467–474), but the non-planar ids do not.

Collision-critical colors come from the existing severity palette; the heatmap remains viewport content rather than a new chrome theme.

Collision finding → fix loop

PROPOSED — collision risk is actionable rather than decorative:

flowchart LR
  C["Collision-risk critical band"] --> F["Select collision finding"]
  F --> Z["Focus layer / move"]
  Z --> Q{"Fix scope"}
  Q -->|Global| G["Raise radius / height clearance"]
  Q -->|Local| P["Paint region + override"]
  G --> R["Re-slice"]
  P --> R
  R --> V["Replay and verify band / count"]
  1. Select collision-risk in Preview or Simulate.
  2. Click the critical marker/finding to focus its layer and move.
  3. Return to Prepare.
  4. Raise global clearance, or paint a local region and set an override.
  5. Re-slice; the dirty banner clears only after successful generation.
  6. Confirm the band downgrades and the Critical count falls.

HOW IT IS — selecting a current finding already focuses simulation state (src/SlicerApp/MainWindow.axaml.cs:679–738; src/SimulatorApp/MainWindow.axaml.cs:665–727). Collision fields, non-planar category, fix controls, and severity-count feedback are PROPOSED.

Stair-step verification

PROPOSED — Ghost Compare verifies the visual result against a planar baseline:

  1. Preview the non-planar result with nonplanar-amplitude active.
  2. Turn on Ghost Compare.
  3. The host snapshots the active path, regenerates a baseline with enableNonPlanar=0, and snapshots that baseline before another generation.
  4. The baseline renders dimly beneath the non-planar path.
  5. Restrict the layer band and scrub curved surfaces.
  6. Confirm the non-planar path reduces the visible stair-step transition.

The snapshot order is mandatory because engine move pointers remain valid only until the next load/generate/parse operation (src/Nps.EngineHost/EngineSession.cs:392–400). Ghost Compare is visual verification, not dimensional proof or collision certification.

Honest empty and disabled states

State Planned response
No model Panel visible; controls disabled; Import a 3MF model to begin
Enable off Detect/Paint/region edits disabled; reason shown
No detected/painted regions Empty list explains how to Detect or Paint
Collision field unavailable collision-risk absent from Color by, not a zero-valued fake map
Generated settings changed Dirty banner + Re-slice; old visualization remains visibly stale

See also