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

Reimplement coord_pos_relative_to_ring using wn algo #972

Merged
merged 9 commits into from
Jan 24, 2023

Conversation

bjornharrtell
Copy link
Contributor

@bjornharrtell bjornharrtell commented Jan 23, 2023

Doing this mostly for fun but AFAIK the winding number algo is superior to the ray-intersection algo.

@bjornharrtell bjornharrtell marked this pull request as draft January 23, 2023 12:21
@bjornharrtell
Copy link
Contributor Author

Getting 6 test failures which I'm as of yet mystified about.

@bjornharrtell bjornharrtell marked this pull request as ready for review January 23, 2023 15:51
@bjornharrtell
Copy link
Contributor Author

Found the problem, was porting error. Then I found that I could use some preexisting bits of code instead.

@bjornharrtell
Copy link
Contributor Author

bjornharrtell commented Jan 23, 2023

Looks like this improves performance significantly (~40% !) at least for the intersection bench. My results:

1. time:   [1.4524 s 1.4671 s 1.4823 s]
2. time:   [625.52 ms 626.94 ms 628.31 ms]
3. time:   [896.23 ms 899.61 ms 902.87 ms]

1. before this PR
2. after this PR
3. attempt to rewrite with pattern matching to reduce redundant code (not commited or pushed)

Copy link
Member

@urschrei urschrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor query from me

@@ -100,7 +100,7 @@ where
// Helper function to check point lies inside rect given by
// bounds. The first bound need not be min.
#[inline]
fn point_in_rect<T>(value: Coord<T>, bound_1: Coord<T>, bound_2: Coord<T>) -> bool
pub fn point_in_rect<T>(value: Coord<T>, bound_1: Coord<T>, bound_2: Coord<T>) -> bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be made pub crate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't appear so on naive try

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@michaelkirk michaelkirk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really exciting, thanks @bjornhartell!

I'm running some benches locally, because I want to see how it affects other algorithms, like the GeometryGraph stuff, which has a pretty comprehensive test suite (lifted from JTS) and uses Intersects under the hood.

}
}
if crossings % 2 == 1 {
if wn != 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarity nit: it's a tiny bit easier to read this without the negation:

if wn == 0 {
 CoordPos::Outside
} else {
 CoordPos::Inside
}

let mut crossings = 0;
// Use winding number algorithm with on boundary short-cicuit
// See: https://en.wikipedia.org/wiki/Point_in_polygon#Winding_number_algorithm
let mut wn = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please prefer more explicable names, unless it's extremely local (like a one line closure):

Suggested change
let mut wn = 0;
let mut winding_number = 0;

@michaelkirk
Copy link
Member

michaelkirk commented Jan 24, 2023

I'm running some benches locally, because I want to see how it affects other algorithms, like the GeometryGraph stuff, which has a pretty comprehensive test suite (lifted from JTS) and uses Intersects under the hood.

As well as a 40-50% improvement for our intersection bench, this has a big speedup for our contains bench!

I did see some regressions across the boolean-ops benches. Is anyone else able to reproduce?:

bench snippet
Circular polygon boolean-ops/bops::intersection/4096
                        time:   [26.771 ms 27.050 ms 27.435 ms]
                        change: [+10.853% +12.476% +14.037%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/rgbops::union/4096
                        time:   [13.865 ms 14.073 ms 14.379 ms]
                        change: [+7.4215% +9.4913% +11.382%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/rgbops::intersection/4096
                        time:   [18.950 ms 19.027 ms 19.137 ms]
                        change: [+9.4979% +10.451% +11.338%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/geo::relate/4096
                        time:   [21.060 ms 21.496 ms 21.757 ms]
                        change: [+5.0324% +7.0601% +8.6649%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 1 outliers among 10 measurements (10.00%)
  1 (10.00%) low mild
Circular polygon boolean-ops/bops::union/8192
                        time:   [29.972 ms 30.165 ms 30.379 ms]
                        change: [+18.804% +20.426% +22.553%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 1 outliers among 10 measurements (10.00%)
  1 (10.00%) high severe
Circular polygon boolean-ops/bops::intersection/8192
                        time:   [57.669 ms 59.629 ms 61.267 ms]
                        change: [+11.755% +14.677% +17.924%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/rgbops::union/8192
                        time:   [30.960 ms 31.284 ms 31.638 ms]
                        change: [+4.4674% +6.2686% +8.1893%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/rgbops::intersection/8192
                        time:   [37.538 ms 38.036 ms 39.204 ms]
                        change: [+4.2654% +7.4364% +11.293%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/geo::relate/8192
                        time:   [67.582 ms 67.820 ms 68.166 ms]
                        change: [+9.9190% +10.866% +11.935%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 1 outliers among 10 measurements (10.00%)
  1 (10.00%) high mild

I'm not sure what accounts for it. Note the bops benchs are currently mislabled and includes some redundancies (edit: no redundancies, just my own confusion). I just now opened #973 to address that and another unrelated fix for the relate bench.

@urschrei
Copy link
Member

Those regressions are very surprising – I can't think of any obvious explanation. @rmanoka any ideas about what could be going on?

@michaelkirk
Copy link
Member

 Circular polygon boolean-ops/rgbops::union/8192
                        time:   [30.960 ms 31.284 ms 31.638 ms]
                        change: [+4.4674% +6.2686% +8.1893%] (p = 0.00 < 0.05)
                        Performance has regressed.
Circular polygon boolean-ops/rgbops::intersection/8192
                        time:   [37.538 ms 38.036 ms 39.204 ms]
                        change: [+4.2654% +7.4364% +11.293%] (p = 0.00 < 0.05)
                        Performance has regressed.

I'm actually really skeptical of my results on that bops bench. For example, I think these "regressed" benches are actually testing an old unchanged version of geo-types (via the boolean_ops crates). So I don't even think it should be possible that we could affect that behavior.

Maybe it's just ghosts in the machine... 👻

@michaelkirk
Copy link
Member

Yeah actually, I don't have any concerns about the boolean ops "regressions" relating to this PR. I think it's just spurious.

I did:

pub fn coord_pos_relative_to_ring<T>(coord: Coord<T>, linestring: &LineString<T>) -> CoordPos
where
    T: GeoNum,
{
+    panic!("in coord_pos_relative_to_ring");

coord_pos_relative_to_ring isn't even called in BoolOps code path from what I can tell.

@urschrei
Copy link
Member

bors r+

@bors
Copy link
Contributor

bors bot commented Jan 24, 2023

Build succeeded:

@bors bors bot merged commit 923ba6a into georust:main Jan 24, 2023
@urschrei
Copy link
Member

Ugh I saw the approve and didn't pay attention to the nits. I'll clean those up in the morning.

@michaelkirk
Copy link
Member

No worries! If it was anything I felt strongly about I wouldn't have marked it as "approved".

michaelkirk added a commit that referenced this pull request Jan 24, 2023
@michaelkirk
Copy link
Member

Ugh I saw the approve and didn't pay attention to the nits. I'll clean those up in the morning.

I did this in #975.

bors bot added a commit that referenced this pull request Jan 24, 2023
975: fix nits from #972 r=urschrei a=michaelkirk

- [x] I agree to follow the project's [code of conduct](https://github.com/georust/geo/blob/main/CODE_OF_CONDUCT.md).
- [x] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users.
---



Co-authored-by: Michael Kirk <michael.code@endoftheworl.de>
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

Successfully merging this pull request may close these issues.

3 participants