iShape-Rust / iOverlay

Boolean Operations for 2D Polygons: Supports intersection, union, difference, xor, and self-intersections for all polygon varieties.
https://ishape-rust.github.io/iShape-js/
MIT License
32 stars 3 forks source link

feature request: Strict unions #9

Open cuppachino opened 1 week ago

cuppachino commented 1 week ago

I would like to request the addition of a Strict Union overlay rule. The goal of this feature is to allow for unions where shapes that merely share an edge or vertex are not combined into a single shape. Currently, it appears that shapes sharing an edge are unioned, but for certain use cases, I would like to enforce that only shapes with overlapping areas are unioned.

Use Case:

In applications where maintaining distinct shapes is important, shared boundaries between shapes should not result in a union of those shapes. This feature would be useful for scenarios such as:

Proposed Solution:

Introduce an OverlayRule::UnionStrict that when passed to extract_shapes, for all Overlay variants (such as F64Overlay):

  1. Shapes that share edges or vertices should remain distinct and not be unioned.
  2. Union operations should only combine polygons with overlapping regions.
  3. It is easy to distinguish whether a union was performed (perhaps an Option or Result)

image

NailxSharipov commented 1 week ago

Thanks for the detailed description! Implementing this as an extension might be a more flexible approach. The current FillRule doesn’t modify the OverlayGraph, which allows multiple shapes to be extracted using different rules sequentially.

However, as we discussed before, achieving Strict Union would require additional steps to convert the original graph into a StringGraph. Because of these extra manipulations, it would be better to implement this feature as a separate API, allowing it to function independently while keeping the core graph structure unmodified.

NailxSharipov commented 1 week ago

About 3. All we need to do is check is any link (yellow), as shown in the picture, present in the overlay graph. This link must be at once a part of A and B from one side. string_union

for link in self.links.iter() {
    let subj_top = link.fill & SUBJ_TOP;
    let clip_top = link.fill & CLIP_TOP;
    let subj_bottom = link.fill & SUBJ_BOTTOM;
    let clip_bottom = link.fill & CLIP_BOTTOM;
    let is_common_top = subj_top != 0 && clip_top != 0;
    let is_common_bottom = subj_bottom != 0 && clip_bottom != 0;
    if is_common_top || is_common_bottom {
        return true;
    }
}

false