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

Debug and add to IntersectingPolygons #107

Merged
merged 2 commits into from
Apr 14, 2024

Conversation

skygering
Copy link
Collaborator

There was a bug in the IntersectingPolygons fix. Unfortunately, union depends on the mutipolygon being valid, so using union to make a multipolygon valid just doesn't work and it requires a lot more cross-comparison.

I also added a difference fix and found a bug in my polygon tracing.

I think that this could be much improved with the edge sorting and other tricks as mentioned in #65 (even sorting the sub-polygons by extent would probably decrease computation for really large multipolygons) but at least it is a naive start.

@skygering skygering requested review from rafaqz and asinghvi17 April 12, 2024 23:32
Copy link
Member

@rafaqz rafaqz left a comment

Choose a reason for hiding this comment

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

LGTM. We could improve performance by precalculating extents so intersects can be skipped most of the time.

@@ -59,13 +59,78 @@ struct UnionIntersectingPolygons <: GeometryCorrection end
application_level(::UnionIntersectingPolygons) = GI.MultiPolygonTrait

function (::UnionIntersectingPolygons)(::GI.MultiPolygonTrait, multipoly)
union_multipoly = if GI.npolygon(multipoly) > 1
union_multipoly = tuples(multipoly)
Copy link
Member

Choose a reason for hiding this comment

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

Here your could do:

Suggested change
union_multipoly = tuples(multipoly)
union_multipoly = tuples(multipoly; calc_extent=true)

And use the extent in intersects.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Amazing @rafaqz ! Yeah, I was wondering if it was that easy to get the extent, so that is great to know. However, what do you think about it being a user input? I think we might need to dispatch off of the Bools as Types stuff @asinghvi17 implemented. With calc_extent = true we have the following:

mp6 = GI.MultiPolygon([[[(-5.0, 10.0), (-5.0, 15.0), (15.0, 15.0), (15.0, 10.0), (-5.0, 10.0)]], [[(-5.0, -5.0), (-5.0, 0.0), (15.0, 0.0), (15.0, -5.0), (-5.0, -5.0)]], [[(10.0, -5.0), (10.0, 15.0), (15.0, 15.0), (15.0, -5.0), (10.0, -5.0)]], [[(-5.0, -5.0), (-5.0, 15.0), (0.0, 15.0), (0.0, -5.0), (-5.0, -5.0)]]])
typeof(GO.tuples(mp6; calc_extent = true))

which returns
GeoInterface.Wrappers.MultiPolygon{false, false, Vector{GeoInterface.Wrappers.Polygon{false, false, Vector{GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Float64, Float64}}, Extents.Extent{(:X, :Y), Tuple{Tuple{Float64, Float64}, Tuple{Float64, Float64}}}, Nothing}}, Extents.Extent{(:X, :Y), Tuple{Tuple{Float64, Float64}, Tuple{Float64, Float64}}}, Nothing}}, Extents.Extent{(:X, :Y), Tuple{Tuple{Float64, Float64}, Tuple{Float64, Float64}}}, Nothing}

while

typeof(GO.tuples(mp6; calc_extent = false))

returns
GeoInterface.Wrappers.MultiPolygon{false, false, Vector{GeoInterface.Wrappers.Polygon{false, false, Vector{GeoInterface.Wrappers.LinearRing{false, false, Vector{Tuple{Float64, Float64}}, Nothing, Nothing}}, Nothing, Nothing}}, Nothing, Nothing}

Seems like that will cause type instability if we don't dispatch off of user input.

And if that is the case, I would rather have that be its own PR where I add extents to all of the polygon functions I. have written because I don't think I took advantage of it as much as I should have.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a part of the problems listed in #97

Copy link
Member

Choose a reason for hiding this comment

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

Yeah use BoolAsTypes! its just easier to use true for demonstration purposes

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Are you okay with this being in a different PR? If so, I might just merge and then work on that when I have a bit more time (and once I am done with #106 😆).

Copy link
Member

@rafaqz rafaqz Apr 14, 2024

Choose a reason for hiding this comment

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

For sure :)

Otherwise its all good so I jumped ahead to optimizing

Copy link
Member

Choose a reason for hiding this comment

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

ok maybe I can PR with the extent stuff too if you have other priorities, seeing its mostly building on my code in other packages. Unfortunately I've been stuck with a lot of DD/Rasters work the last month and havent had time for looking at clipping performance here yet

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am also happy to take a stab at it. It just isn't a priority like getting these bugs fixed or getting the points swapped over for me right now. But I am excited for one of us to work on it in the near future haha

application_level(::DiffIntersectingPolygons) = GI.MultiPolygonTrait

function (::DiffIntersectingPolygons)(::GI.MultiPolygonTrait, multipoly)
diff_multipoly = tuples(multipoly)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
diff_multipoly = tuples(multipoly)
diff_multipoly = tuples(multipoly; calc_extent=true)

Copy link
Member

Choose a reason for hiding this comment

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

In here we should also add an efficiency step - if the extents are known already they should not be recalculated. This might be a bit difficult with how apply is currently implemented, though...

Copy link
Member

@rafaqz rafaqz Apr 14, 2024

Choose a reason for hiding this comment

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

That should work already? If not its a bug. Like Geointerface.extext will check the extent first and calculate if its not there. Maybe we dont copy it accross tho

Copy link
Member

@asinghvi17 asinghvi17 Apr 14, 2024

Choose a reason for hiding this comment

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

In general for apply I think you can't copy the extent, since there is some transformation going on there.

poly_disjoint = true # assume current polygon is disjoint from others
for (next_idx, _) in Iterators.filter(last, Iterators.drop(Iterators.enumerate(keep_idx), curr_idx))
next_poly = union_multipoly.geom[next_idx]
if intersects(curr_poly, next_poly) # if two polygons intersect
Copy link
Member

Choose a reason for hiding this comment

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

Then intersects needs an extent check (maybe it already has one?) to rule out non-intersecting extents

Copy link
Member

@asinghvi17 asinghvi17 left a comment

Choose a reason for hiding this comment

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

Looks good to me!

@skygering skygering merged commit 1d65f97 into JuliaGeo:main Apr 14, 2024
3 checks passed
@skygering skygering deleted the sg/improve_multipolygon_fixes branch April 14, 2024 19:59
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