lyon icon indicating copy to clipboard operation
lyon copied to clipboard

Eliminate internal vertices with `FillRule::NonZero`

Open torokati44 opened this issue 2 years ago • 1 comments

Given the following example:

use lyon::math::{point, Point};
use lyon::path::Path;
use lyon::tessellation::*;

fn main() {
    let mut tessellator = FillTessellator::new();

    {
        let mut builder = Path::builder();
        builder.begin(point(0.0, 0.0));
        builder.line_to(point(100.0, 0.0));
        builder.line_to(point(100.0, 100.0));
        builder.line_to(point(20.0, 100.0));
        builder.line_to(point(20.0, 20.0));
        builder.line_to(point(80.0, 20.0));
        builder.line_to(point(80.0, 80.0));
        builder.line_to(point(0.0, 80.0));
        builder.close();

        fun_name(&mut tessellator, builder.build());
    }

    {
        let mut builder = Path::builder();
        builder.begin(point(0.0, 0.0));
        builder.line_to(point(100.0, 0.0));
        builder.line_to(point(100.0, 100.0));
        builder.line_to(point(20.0, 100.0));
        builder.line_to(point(20.0, 80.0));
        builder.line_to(point(0.0, 80.0));
        builder.close();

        fun_name(&mut tessellator, builder.build());
    }
}

fn fun_name(tessellator: &mut FillTessellator, path: Path) {
    let mut geometry: VertexBuffers<Point, u16> = VertexBuffers::new();

    tessellator
        .tessellate_path(
            &path,
            &FillOptions::default().with_fill_rule(FillRule::NonZero),
            &mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| vertex.position()),
        )
        .unwrap();

    println!(
        " -- {} vertices {} indices",
        geometry.vertices.len(),
        geometry.indices.len()
    );

    for tri in geometry.indices.chunks(3) {
        println!(
            "{:?} - {:?} - {:?}",
            geometry.vertices[tri[0] as usize],
            geometry.vertices[tri[1] as usize],
            geometry.vertices[tri[2] as usize],
        );
    }
}

The output is:

 -- 9 vertices 30 indices
(100.0, 0.0) - (0.0, 0.0) - (20.0, 20.0)
(20.0, 20.0) - (0.0, 0.0) - (0.0, 80.0)
(20.0, 20.0) - (0.0, 80.0) - (20.0, 80.0)
(80.0, 20.0) - (20.0, 20.0) - (20.0, 80.0)
(80.0, 20.0) - (20.0, 80.0) - (80.0, 80.0)
(80.0, 80.0) - (20.0, 80.0) - (20.0, 100.0)
(100.0, 0.0) - (20.0, 20.0) - (80.0, 20.0)
(100.0, 0.0) - (80.0, 20.0) - (80.0, 80.0)
(100.0, 0.0) - (80.0, 80.0) - (100.0, 100.0)
(80.0, 80.0) - (20.0, 100.0) - (100.0, 100.0)
 -- 6 vertices 12 indices
(100.0, 0.0) - (0.0, 0.0) - (0.0, 80.0)
(100.0, 0.0) - (0.0, 80.0) - (20.0, 80.0)
(100.0, 0.0) - (20.0, 80.0) - (20.0, 100.0)
(100.0, 0.0) - (20.0, 100.0) - (100.0, 100.0)

The tessellations look like this:

path1

path2

I would expect the first, self-intersecting one, to be comparable to the second one, where only the outline is in the path.

torokati44 avatar Jun 19 '23 10:06 torokati44

Yep, that's sort of by design, or more precisely a byproduct of the way the algorithm works. Changing this would be a pretty major project which I don't have the time to embark on. I don't expect this to change unless you or someone else feels adventurous and implements a different behavior.

nical avatar Jun 19 '23 12:06 nical