-
Notifications
You must be signed in to change notification settings - Fork 238
get geom type from prepared geom #1318
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
Conversation
277417d to
89a5582
Compare
| // by using the bounding_rect from the RTree | ||
| debug_assert_eq!(bounding_rect, geometry_graph.geometry().bounding_rect()); | ||
|
|
||
| impl<F: GeoFloat> From<Point<F>> for PreparedGeometry<'_, F> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These super repetitive implementations still exist, they were just moved to the same macro loop that spits out the impl Relate for each geometry, which is no less generated code, but much less typing.
679606f to
2efea92
Compare
`PreparedGeometry` is fast for some things, but it can't do everything a
Geometry can do. Since it was previously possible to `PreparedGeometry::from(&geometry)` I'd typically do things like:
```
let line_strings: Vec<LineString> = todo!();
let prepared_linestrings: Vec<(LineString, PreparedGeometry)> = line_strings.into_iter().map(|ls| (ls, PreparedGeometry::from(&ls))).collect();
// Then pass the (unprepared, prepared) tuple around - using the
// prepared geometry for things Relate operations and the unprepared
// geometry for everything else:
let (prepared, unprepared) = prepared_polygons.pop().unwrap();
let (other_prepared, other_unprepared) = prepared_polygons.pop().unwrap();
// faster to check if there *is* an intersection, before trying BoolOps the intersection Geometry.
if prepared.relate(&other_prepared).is_intersects() {
unprepared.intersection(&other_unprepared)
}
```
But that's kind of annoying.
Now its:
```
let line_strings: Vec<LineString> = todo!();
let prepared_linestrings: Vec<PreparedGeometry> = line_strings.into_iter().map(PreparedGeometry::from).collect();
let prepared = prepared_polygons.pop().unwrap();
let other_prepared = prepared_polygons.pop().unwrap();
// faster to check if there *is* an intersection, before trying BoolOps the intersection Geometry.
if prepared.relate(&other_prepared).is_intersects() {
prepared.geometry().intersection(&other.geometry())
}
```
Note: that this makes `GeometryCow` public since it's a constraint on
what the inner geometry of PreparedGeometry can be.
GeometryCow was previously private because it's a bit obscure - I'm not
sure that it will be useful to people. But it seems stable, documented,
and unlikely to be "dangerous".
89a5582 to
336ec33
Compare
dabreegster
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a useful API change, will indeed make caller code simpler
| G: Into<GeometryCow<'a, F>>, | ||
| { | ||
| pub(crate) fn geometry(&self) -> &GeometryCow<F> { | ||
| self.geometry_graph.geometry() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just reasoning through part of the diff: there was already a GeometryCow available buried deeper, but the types you're exposing here are a little different... Into<GeometryCow>, not &GeometryCow. So it's indeed necessary to store the new field, not just try and get it from geometry_graph
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. This was probably worth spelling out more in my PR, but I'll do it now:
An alternate approach that doesn't add a new field/generic to PreparedGeometry could use the existing reference from the GeometryGraph's GeometryCow.
The problem is, because GeometryCow is an enum (just like geo::Geometry) holding some geometry type, we don't have a nice way to get the specific geometry type back out. Instead, the api would have to be fallible, and look like:
geometry_cow.as_point() -> Option<Point>
geometry_cow.as_line_string() -> Option<LineString>
geometry_cow.as_polygon() -> Option<Polygon>
// etc.
For a given GeometryCow, exactly one of those would return Some, the rest would return None. As a programmer using this API you'd have to keep track of what kind of geometry is in each PreparedGeometry.
CHANGES.mdif knowledge of this change could be valuable to users.Note this builds on top of #1317, so review that first (draft until then).Merged!PreparedGeometryis fast for some things, but it can't do everything aGeometrycan do.Since you can
PreparedGeometry::from(&geometry), I'd typically follow a pattern where I'd keep the original geometry and the PreparedVersion of that geometry together, like:That works, but it's kind of annoying to shuttle both around as a tuple, when I know internally the PreparedGeometry has a reference to the underlying Geometry. This PR exposes that:
Now you can:
Note: that this makes
GeometryCowpublic since it's a constraint on what the inner geometry of PreparedGeometry can be.GeometryCow was previously private because it's a bit obscure - I'm not sure that it will be useful to people. But it seems stable, documented, and unlikely to be "dangerous", so I'm not worried about making it public.