Skip to content

Non-destructive, partial surface extrudes/revolves/sweeps etc#1130

Open
adamchalmers wants to merge 6 commits intomainfrom
achalmers/extrude-segments
Open

Non-destructive, partial surface extrudes/revolves/sweeps etc#1130
adamchalmers wants to merge 6 commits intomainfrom
achalmers/extrude-segments

Conversation

@adamchalmers
Copy link
Collaborator

@adamchalmers adamchalmers commented Mar 12, 2026

This proposes a new way to surface extrude/revolve/sweep for sketch 2. Part of KittyCAD/modeling-app#10386

Background

Currently, the engine extrude/revolve/sweep/etc endpoints take an entire sketch as their target. That worked fine for sketch 1 solid extrudes (where the sketch is a closed profile) and for surface extrudes (where the sketch could be closed or open, either way, it extrudes each segment separately).

Problem

In sketch 2, the user might want to surface extrude only some segments in the sketch. Like in the below example, only k of the n segments are selected for extrusion.

Screenshot 2026-03-12 at 10 32 39 AM

Right now the API doesn't allow for this. Clients send the ID of the overall sketch, and the server extrudes the whole thing. There's no way to only surface extrude k of the n segments.

Solution

Instead of extruding an entire sketch (solid2D) at once, we instead take a list of segments and extrude each of those separately.

Here's a motivating example:

new_extrude_system

In this example, after extruding:

  • C becomes a single-surface body
  • D and E become a polysurface (D is extruded into one surface, E into another)
  • A and B become a single-body surface by default (because they're collinear) unless the user opts out by setting a keepSeams flag in KCL.

We want to:

  • Keep the old path segments A-E existing, unchanged (same IDs).
  • Create new bodies (Solid3Ds) from them.
    • Frontend cannot predict the number of bodies in advance (because frontend doesn't know which segments intersect, or are collinear).
    • So engine will need to tell the frontend how many bodies were created, and what their IDs are.
  • Get a mapping between segments and surfaces, so that tags can transfer.
    • e.g. frontend must know that:
    • segment A and B were absorbed into body 1 face 0
    • segment C became body 2 face 0
    • segment D became body 0 face 0
    • segment E became body 0 face 1

Ideally we would not need any follow-up calls to query these bodies. Let's just send back all relevant information in the Extrude response.

Here's my proposed return for Extrude. I'm using YAML because it's more concise, but we'd actually be sending JSON. See the attachment for syntax highlighting, or copypastable here:

bodies:
  - id: body0
    surfaces:
      - faceIndex: 0
        faceId: <uuid>
        fromSegments: [d0000000-0000-0000-0000-000000000000]
      - faceIndex: 1
        faceId: <uuid>
        fromSegments: [e0000000-0000-0000-0000-000000000000]
  - id: body1
    surfaces:
      - faceIndex: 0
        faceId: <uuid>
        fromSegments: [a0000000-0000-0000-0000-000000000000, b0000000-0000-0000-0000-000000000000]
  - id: body2
    surfaces:
      - faceIndex: 0
        faceId: <uuid>
        fromSegments: [c0000000-0000-0000-0000-000000000000]

@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@1f137ce). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1130   +/-   ##
=======================================
  Coverage        ?   30.22%           
=======================================
  Files           ?       34           
  Lines           ?     1588           
  Branches        ?        0           
=======================================
  Hits            ?      480           
  Misses          ?     1108           
  Partials        ?        0           
Flag Coverage Δ
unittests 30.22% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@davreev davreev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me. If two consecutive segments are selected, would we still get two separate bodies or would they be merged into a single one?

@adamchalmers
Copy link
Collaborator Author

Sounds good to me. If two consecutive segments are selected, would we still get two separate bodies or would they be merged into a single one?

Good question. I'll ask @max-mrgrsk and @nicboone8. Perhaps it should be configurable.

@nicboone8
Copy link

I would expect them merged by default, but making it configurable is a good idea

Comment on lines 265 to 304
@@ -265,6 +302,15 @@ define_modeling_cmd_enum! {
/// Which sketch to revolve.
/// Must be a closed 2D solid.
pub target: ModelingCmdId,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation inconsistency: Revolve.target still says "Must be a closed 2D solid" but should be updated to "Must be a 2D sketch" to match the Extrude operation and reflect support for partial surface revolves via the new segments field.

Suggested change
/// Which sketch to sweep.
/// Must be a closed 2D solid.
pub target: ModelingCmdId,
/// If given, extrude each of these segments into a separate body with the given ID.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub segments: Option<Vec<IdPair>>,
/// When two collinear segments are extruded, what should happen?
/// If true, creates a body with two surfaces.
/// If false, creates a body with one surface, spanning both collinear segments.
#[serde(default)]
#[builder(default)]
pub keep_seams: bool,
/// Path along which to sweep.
pub trajectory: ModelingCmdId,
/// If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components.
/// Which sketch to revolve.
/// Must be a 2D sketch.
pub target: ModelingCmdId,

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

adamchalmers and others added 5 commits March 18, 2026 14:12
This proposes a new way to surface extrude/revolve/sweep for sketch 2.

Instead of extruding an entire sketch (solid2D) at once, we instead
take a list of segments and extrude each of those separately.

Each segment has a (segment ID, new body ID) pair, so the segment IDs
are NOT absorbed into new body IDs. The sketch and all its segments are
not modified.
@adamchalmers adamchalmers force-pushed the achalmers/extrude-segments branch from 485f01e to 06477d1 Compare March 18, 2026 19:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants