geo icon indicating copy to clipboard operation
geo copied to clipboard

Point boundaries

Open tsturzl opened this issue 5 years ago • 5 comments

I've been using this crate recently for some robotics path planning experiments. I've done similar work using python and shapely, and the fact that this crate offers a lot of the features shapely does I felt like it was a great fit(thanks for making this crate). One thing I haven't figure out how to do is create a circle with a radius. In shapely you do this by adding a boundary to a circle(see here for example), and then if you intersect a line with this point it intersects this boundary. I don't see any way to do this in geo currently. It would be nice to be able to either have a Circle geo-type, or similar to shapely have a point that can have a defined boundary of a given radius which can be intersected and used for Contains trait. I'm not sure if this is implemented, or a proper way of doing this exists. If not I can see if I can create a PR if anyone would offer a little guidance on getting started.

For anyone else with this same issue my current workaround is to create a polygon which represents the circle. I do this by plotting points around the circumference radius length from the center like so(code isn't tested):

use std::f64::consts::PI;

fn create_circle(center: Coordinate<f64>, radius: f64) -> Polygon<f64> {
    let (cx, cy) = center.x_y();
    let circum = 2.0 * PI * radius;
    // this controls how many points to create by dividing circum by 10 units of measurement
    let n = (circum / 10.0).ceil();
    let mut points = Vec::<(f64, f64)>::new();
    for _x in 0..n as usize + 1 {
        let x = _x as f64;
        
        points.push( (((2.0 * PI / n * x).cos() * radius) + cx, ((2.0 * PI / n *x).sin() * radius) + cy) )
    }

    Polygon::new(LineString::from(points), vec![])
}

tsturzl avatar Jan 17 '20 22:01 tsturzl

The issue for us is that we don't yet have a way of buffering geometries (which is what creates the boundary, in the case of a circle). It's a fairly complex algorithm and implementation (do we include different end cap styles in the public API etc). I know that https://github.com/lelongg/geo-offset provides some (or all? I haven't had a chance to look at it properly) of the functionality using the Martinez-Rueda algorithm, and uses geo-types for primitives, so it may be useful to you…

urschrei avatar Jan 18 '20 12:01 urschrei

(I should also note thatgeo-offset makes use of geo-clipper for its boolean operations, which in turn requires the use of Clipper, which may or may not be a deal-breaker for you)

urschrei avatar Jan 18 '20 12:01 urschrei

I appreciate the quick response. I had no idea the complexity was so high on this. My work around is working. I'm just making "circles" from Polygons. I thought with a lot of circles this wouldn't scale well, but I'm happy to report that's not the case.

tsturzl avatar Jan 20 '20 19:01 tsturzl

Let me share my implementation for creating a circle with a radius in meter:

pub fn generate_geo_circle(location: &geo::Point<f64>, radius: f64) -> geo::Polygon<f64> {
    // generate a point in distance in every 10 degree bearing
    let points: Vec<geo::Point<f64>> = (0..=36)
        .map(|i| location.haversine_destination(i as f64 * 10_f64, radius))
        .collect();

    geo::Polygon::new(geo::LineString::from(points), Vec::new())
}

schoenenberg avatar Dec 15 '20 16:12 schoenenberg

See also https://github.com/georust/geo/pull/935

frewsxcv avatar Jan 24 '23 01:01 frewsxcv