21re / rust-geo-booleanop

Rust implementation of the Martinez-Rueda Polygon Clipping Algorithm
MIT License
95 stars 28 forks source link

Intersection of closed polygons can be non-closed. #3

Open rtavenner opened 5 years ago

rtavenner commented 5 years ago

As far as I can tell, the geo_types::LineString in a geo_types::Polygon is supposed to have its first and last coordinates be the same. (I believe this is what the docs mean by "closed". Is that correct?) I have found a case where poly1 and poly2 both satisfy that condition, but poly1.intersection(&poly2) does not.

Is this a bug? Or am I just doing something wrong?

Cargo.toml

...
[dependencies]
geo-types = "0.3.0"
geo-booleanop = { git = "https://github.com/21re/rust-geo-booleanop.git" }

main.rs

#![forbid(unsafe_code)]

extern crate geo_types;
extern crate geo_booleanop;

use geo_types::*;
use geo_booleanop::boolean::BooleanOp;

fn is_closed(p: &Polygon<f64>) -> bool {
    &p.exterior.0[0] == p.exterior.0.last().unwrap()
}

fn main() {
    let poly1: Polygon<f64> = 
        Polygon {
            exterior: LineString(
                vec![
                    Coordinate {
                        x: -530.,
                        y: -530.
                    },
                    Coordinate {
                        x: -530.,
                        y: 530.
                    },
                    Coordinate {
                        x: 530.,
                        y: 530.
                    },
                    Coordinate {
                        x: 530.,
                        y: -530.
                    },
                    Coordinate {
                        x: -530.,
                        y: -530.
                    }
                ]
            ),
            interiors: vec![]
        };
    let poly2: Polygon<f64> =
        Polygon {
            exterior: LineString(
                vec![
                    Coordinate {
                        x: 1.2500125250252,
                        y: -531.
                    },
                    Coordinate {
                        x: -98.,
                        y: -531.
                    },
                    Coordinate {
                        x: -98.,
                        y: 531.
                    },
                    Coordinate {
                        x: 1.250012525025,
                        y: 531.
                    },
                    Coordinate {
                        x: 1.2500125250252,
                        y: -531.
                    }
                ]
            ),
            interiors: vec![]
        };

    println!("{}", is_closed(&poly1));
    println!("{}", is_closed(&poly2));
    println!("{}", is_closed(&poly1.intersection(&poly2).0[0]));

}

Output:

true
true
false
untoldwind commented 5 years ago

To my knowledge the first and last point of a polygon has to be the same. I can try to take a look why this is not the case in this example. Chances are though, that it might be a bug with the algorithm itself. Have just checked this with the original version as well?

rtavenner commented 5 years ago

I cannot figure out how to test the Javascript version. Sorry.

untoldwind commented 5 years ago

FYI: https://github.com/w8r/martinez/issues/99

The intersection points in the result are correct, there are just in the wrong order. This seems to be a rounding issue (i.e. 631 instead of 531 works correctly).