High-precision seam placement using modifiers (algorithm) #1809

Open
opened 2026-04-05 20:08:00 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @DImagine on 10/27/2025

Is there an existing issue for this feature request?

  • I have searched the existing issues

Precisely positioning the seam can be quite a tedious and time-consuming task. Moreover, any change to the model usually requires repeating this work from scratch.

In CAD systems, however, it’s very easy to create additional bodies that exactly match the desired seam position. You can also use built-in primitives for that purpose.

A simple seam-positioning feature based on such helper bodies would be really handy (a similar feature exists in PrusaSlicer).

Image 1 Image 2

Test Objects 3MF.zip

Which printers will be beneficial to this feature?

All

Describe the solution you'd like

At the moment, Orca Slicer allows adding arbitrary bodies as modifiers, but it’s not possible to explicitly control seam placement using them.

Proposed solution
I suggest a seam-positioning algorithm that’s very easy to implement:

  1. Add a property for modifiers: “Easy seam”.
  2. During slicing, for each layer, obtain the outer perimeter polygons of both the main object and the modifiers.
  3. Check each object polygon for intersections with the modifier polygons — using ClipperLib’s ctIntersection operation (via Clipper::Execute()), which returns the intersection paths. Stop at the first intersection found.
  4. If an intersection exists, override all existing seam-placement mechanisms.
  5. Take the first intersection path (ignore the rest, if any).
  6. Find the points of this path that belong to the object’s polygon — the midpoint of that segment becomes the seam point (see the function description below).

That’s it.

Later we can add more options if needed.

Image

Describe alternatives you've considered

No response

Additional context

🧮 Function description: Finding the seam point from the intersection path

The goal is to find the segment of the intersection path that belongs to the object polygon (not the modifier polygon), thus defining the segment whose midpoint becomes the target seam point.

I’m not sure in which order ctIntersection returns the points along the intersection path. If the first point is always the intersection of the two original polygons, that would greatly simplify the task.

In the general case, the function could work as follows:

  1. Sequentially iterate through the points on the intersection path and look for one that matches a point from the object polygon.
  2. If such a point is found, continue searching to find the last matching point. If the first found one was the first point of the path — search the same way in the opposite direction.
  3. For the found point(s), inspect the two adjacent points to determine whether their connecting segments belong to the object polygon. This gives two points that define the boundaries of the target segment.
  4. If no matching points are found, it means the modifier polygon intersected a single edge of the object polygon without including any of its vertices. In that case, check each segment of the intersection path to see if it lies within an edge of the object polygon. The overlapping segment is the one we need.

Finally, compute the midpoint of the identified segment — that’s the desired seam point.

I could implement this as a C++ function that takes two polylines (for the object and the modifier) and returns the resulting seam point. This mainly requires some basic computational geometry.

*Originally created by @DImagine on 10/27/2025* ### Is there an existing issue for this feature request? - [x] I have searched the existing issues ### Is your feature request related to a problem? Precisely positioning the seam can be quite a tedious and time-consuming task. Moreover, any change to the model usually requires repeating this work from scratch. In CAD systems, however, it’s very easy to create additional bodies that exactly match the desired seam position. You can also use built-in primitives for that purpose. A simple seam-positioning feature based on such helper bodies would be really handy (a similar feature exists in PrusaSlicer). <p align="center"> <img src="https://github.com/user-attachments/assets/140b65db-373b-43be-8700-063ee2151a67" alt="Image 1" height="200"> <img src="https://github.com/user-attachments/assets/54f231d0-2793-4f05-9772-44f847096bf8" alt="Image 2" height="200"> </p> [Test Objects 3MF.zip](https://github.com/user-attachments/files/23162512/Test.Objects.3MF.zip) ### Which printers will be beneficial to this feature? All ### Describe the solution you'd like At the moment, Orca Slicer allows adding arbitrary bodies as modifiers, but it’s not possible to explicitly control seam placement using them. **Proposed solution** I suggest a seam-positioning algorithm that’s very easy to implement: 1. Add a property for modifiers: **“Easy seam”**. 2. During slicing, for each layer, obtain the **outer perimeter polygons** of both the main object and the modifiers. 3. Check each object polygon for intersections with the modifier polygons — using **ClipperLib’s `ctIntersection`** operation (via `Clipper::Execute()`), which returns the intersection **paths**. Stop at the first intersection found. 4. If an intersection exists, override all existing seam-placement mechanisms. 5. Take the first intersection path (ignore the rest, if any). 6. Find the points of this path that belong to the object’s polygon — the midpoint of that segment becomes the seam point (see the function description below). **That’s it.** *Later we can add more options if needed.* <img width="1524" height="546" alt="Image" src="https://github.com/user-attachments/assets/95c4cef6-561b-4148-90b6-1583372ae672" /> ### Describe alternatives you've considered _No response_ ### Additional context ### 🧮 Function description: Finding the seam point from the intersection path The goal is to find the **segment of the intersection path** that belongs to the **object polygon** (not the modifier polygon), thus defining the segment whose midpoint becomes the target seam point. I’m not sure in which order `ctIntersection` returns the points along the intersection path. If the first point is always the intersection of the two original polygons, that would greatly simplify the task. In the general case, the function could work as follows: 1. Sequentially iterate through the points on the intersection path and look for one that matches a point from the object polygon. 2. If such a point is found, continue searching to find the **last matching point**. If the first found one was the first point of the path — search the same way in the opposite direction. 3. For the found point(s), inspect the two adjacent points to determine whether their connecting segments belong to the object polygon. This gives two points that define the boundaries of the target segment. 4. If no matching points are found, it means the modifier polygon intersected a single edge of the object polygon without including any of its vertices. In that case, check each segment of the intersection path to see if it lies within an edge of the object polygon. The overlapping segment is the one we need. Finally, compute the **midpoint of the identified segment** — that’s the desired seam point. I could implement this as a C++ function that takes two polylines (for the object and the modifier) and returns the resulting seam point. This mainly requires some basic computational geometry.
MrUnknownDE added the enhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancementenhancement labels 2026-04-05 20:08:24 +02:00
Sign in to join this conversation.
No Label enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement enhancement
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/OrcaSlicer#1809