Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide basic operations for geometry types #9

Closed
frewsxcv opened this issue May 1, 2015 · 12 comments
Closed

Provide basic operations for geometry types #9

frewsxcv opened this issue May 1, 2015 · 12 comments

Comments

@frewsxcv
Copy link
Member

frewsxcv commented May 1, 2015

http://turfjs.org/static/docs/ has a nice list of operations. Might be good to have a discussion about whether to have these in a separate library is more appropriate

@calvinmetcalf
Copy link
Member

the postgis list is also a good base http://postgis.net/docs/manual-2.1/reference.html

@sunng87
Copy link
Member

sunng87 commented May 2, 2015

I used to divide these operations into a few categories:

  1. Relationship test:
    • equals?
    • disjoint?
    • intersects?
    • touches?
    • crosses?
    • within?
    • covers?
    • contains?
    • overlaps?
    • generic DE-9IM test
  2. Geometry properties
    • area
    • length
    • centeroid
    • coordinates
    • dimension
    • envelope
    • boundary
  3. Analysis
    • buffer
    • distance
    • convex-hull
    • intersection
    • union
    • difference

@calvinmetcalf
Copy link
Member

I'd more differentiate about whether they create new geometry

  1. Compare
    • equals
    • disjoint
    • intersects
    • touches
    • crosses
    • within
    • covers
    • contains
    • overlaps
    • generic DE-9IM test
    • distance
    • max distance
  2. Transforms
    • buffer
    • convex-hull
    • intersection
    • union
    • difference
    • centeroid
    • envelope
    • boundary
    • transform
  3. Analysis
    • area
    • length
    • dimension

@kinnou02
Copy link
Member

kinnou02 commented May 4, 2016

Before doing a PR I would like to view with you how to organize the code

For operation that define a properties, like area or centroid we want to define a trait.

trait HasCentroid {
    fn centroid(&self) -> Point;
}

I am a lot less inspired about relationship operation, the easy way would be a free function taking Geometry

fn within(left: &Geometry, rigth: &Geometry) -> bool;

It's the approach of postgis and boost geometry, but I would like an operation to fail at compilation time if it isn't possible for the current geometries. Of course we could define a function for every possible combination, but there is probably a better way.
I am open to any suggestion (that include you @TeXitoi! )

@kinnou02
Copy link
Member

kinnou02 commented May 4, 2016

There is another way with generic trait, it will result in something like that:

pub trait Contains<RHS = Self> {
    fn within(&self, rhs: &RHS) -> bool;
}

impl Contains<Point> for LineString{
    fn within(&self, other: &Point) -> bool{
        true
    }
}

impl Contains<LineString> for LineString{
    fn within(&self, other: &LineString) -> bool{
        false
    }
}

#[test]
fn within_test(){
    let c = Coordinate {
        x: 40.02f64,
        y: 116.34
    };

    let p = Point(c);
    let mut vecp = Vec::new();
    vecp.push(p);
    let l = LineString(vecp);

    assert!(l.within(&p));
    assert!(!l.within(&l));

}

@TeXitoi
Copy link
Contributor

TeXitoi commented May 4, 2016

This last one is the preferred way: same pattern that Add and friends to overload operators.

One method traits should have the same name as the method.

@TeXitoi
Copy link
Contributor

TeXitoi commented May 4, 2016

For centroid, the result should be an associated type.

@frewsxcv
Copy link
Member Author

frewsxcv commented May 5, 2016

There is another way with generic trait, it will result in something like that:

I agree with @TeXitoi; I also prefer the last way.

One method traits should have the same name as the method.

I agree, it should probably be trait Contains with fn contains.

I think for now, all these operations can go here in rust-geo. In the future, it might make sense to extract them out into a separate crate, but I don't think that's necessary right now.

@michaelkirk
Copy link
Member

I'd more differentiate about whether they create new geometry

I put some time towards this today. I'm brand new to rust (😱 ) , and looking for feedback on the approach before I go down the road too far.

https://github.com/michaelkirk/rust-geo/blob/intersection-operation/src/operation/intersection.rs

In particular, the way I'm using the type system starts to get pretty heavy.

On the one hand, it would be nice if we could leverage the compiler and assert that point.intersection(other_point), point.intersection(line_string), and line_string.intersection(point) all return an Option<Point>, but then this gets pretty tricky when we get to more complex structures.

e.g. A line_string.intersection(other_line_string) could return something like Vec<Point|LineSegment|LineString> (which is not real rust AFAIK 😉).

Is there a way to be this precise with our type system? Or do we just call it a day and have all operations return a GeometryCollection?

Also, I'm open to the possibility that I'm completely off base with the entire approach, but wanted to get the ball rolling on a discussion.

@frewsxcv
Copy link
Member Author

frewsxcv commented Jun 4, 2016

Welcome @michaelkirk! 🎉

looking for feedback on the approach before I go down the road too far.

I like your approach so far. In opinion, HasIntersection sounds like it should return a bool because of the Has qualifier, but that's a minor detail.

could return something like Vec<Point|LineSegment|LineString> (which is not real rust AFAIK 😉).

One way to do this would be an enum. As an example:

enum LineStringIntersection {
    Point(Point),
    LineString(Point),
}

pub trait Intersection {
    type Other;
    type Return;
    fn intersection(&self, other: &Self::Other) -> Vec<Self::Return>;
}

impl Intersection for LineString {
    type Other = LineString;
    type Return = LineStringIntersection;
    fn intersection(&self, other: &Self::Other) -> Vec<Self::Return> {
        ...
    }
}

Using associated types here; haven't thought too hard about this design, so take it with a grain of salt.

I'm half-awake right now, but thought I'd give you some quick feedback before I go to sleep. I'll revisit this tomorrow.

@frewsxcv
Copy link
Member Author

Sorry I have responded to your question @michaelkirk; I've been distracted by other things going on in my life so I haven't put much mental thought into this. I'm still very interested in the work you've done so far, but it might be some time before I can take a closer look. If anyone else in the community wants to give their thoughts, it'd be much appreciated.

@frewsxcv
Copy link
Member Author

We have basic operations now, so I'm going to close this!

nyurik pushed a commit to nyurik/geo that referenced this issue Mar 19, 2022
Reduce repetitive 'comma' implementations
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants