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

polygon_to_line function not working if a GeoInterface Polygon has holes. #201

Open
BG-AIMS opened this issue Sep 2, 2024 · 7 comments
Open

Comments

@BG-AIMS
Copy link

BG-AIMS commented Sep 2, 2024

I have run into an issue where polygon_to_line produces an error if a polygon has holes and has been created with GeoInterface methods. If the polygon originates from ArchGDAL creation then polygon_to_line does work even if the polygon has holes.

For context I found this issue as I have ArchGDAL polygons that are simplified with GO, and polygon_to_line works with these polygons (even if there are holes), however after using GO.buffer on these polygons an error is encountered if the polygon has holes.
Below is example code:

import GeoInterface as GI
import GeometryOps as GO
import ArchGDAL as AG
using GLMakie
using LibGEOS

# GeoInterface
x = [-5, -5, 5, 5];
y = [-5, 5, 5, -5];
multipoint = GI.MultiPoint(GI.Point.(zip(x, y)));

x = [-10, -10, 10, 10, -10]
y = [-10, 10, 10, -10, -10]
lines = GI.LineString(GI.Point.(zip(x,y)));

ring1 = GI.LinearRing(GI.getpoint(lines));
polygon1 = GI.Polygon([ring1]);
poly(polygon1)

hole = GI.LinearRing(GI.getpoint(multipoint))
polygon2 = GI.Polygon([ring1, hole])
GO.polygon_to_line(polygon2)

poly(polygon2)
GO.polygon_to_line(polygon1)


# ArchGDAL
x = [[-10, -10], [-10, 10], [10, 10], [10, -10], [-10, -10]]
polygon1 = AG.createpolygon()
ring = AG.createlinearring(x)
AG.addgeom!(polygon1, ring)
poly(polygon1)

h = [[-5, -5], [-5, 5], [5, 5], [5, -5], [-5, -5]]
polygon2 = AG.createpolygon()
hole = AG.createlinearring(h)
AG.addgeom!(polygon2, ring)
AG.addgeom!(polygon2, hole)
poly(polygon2)
GO.polygon_to_line(polygon2)
GO.polygon_to_line(GO.simplify(polygon2; number=8))
GO.polygon_to_line(GO.buffer(GO.simplify(polygon2; number=8), 0.5)) # my context use case

Below is the error message encountered on line 22, and is the same error as the final line (my use case for context):
image

@JuliaGeo JuliaGeo deleted a comment from maher-nakesh Sep 2, 2024
@asinghvi17
Copy link
Member

I see. The implementation from ArchGDAL is buggy in that it does not recognize linear rings on output (though it does require them on input, as you saw). This probably needs an implementation of coerce(LineStringTrait(), ::LinearRingTrait, geom) to ensure that all geometry is able to fit into the multilinestring.

Thanks for the bug report!

@asinghvi17
Copy link
Member

asinghvi17 commented Sep 2, 2024

Why do you need polygons as linestrings, though? If it's just for plotting you can simply lines(polygon) and it will work. Or do poly(polygon; color = :transparent, strokewidth = 2, strokecolor = :red) for example.

@BG-AIMS
Copy link
Author

BG-AIMS commented Sep 3, 2024

Why do you need polygons as linestrings, though? If it's just for plotting you can simply lines(polygon) and it will work. Or do poly(polygon; color = :transparent, strokewidth = 2, strokecolor = :red) for example.

I am looking to get each edge line between pairs of polygon vertices (so I can see which polygon line segment is closest to a point). I used something similar to GO.LineString(GO.Point.(linestring.geom)) which worked until this issue with hole polygons was encountered. Let me know if there's an easier way to go about this.

Note that I do also need the line segments from the holes in a polygon so I currently do Linestring(Point.()) separately for each linestring if the polygon has holes.

Along the lines of my desired output:
image

@rafaqz
Copy link
Member

rafaqz commented Sep 3, 2024

Isn't polygon_to_line internals? Its not exported. I don't think it should be documented either, that should be a comment.

Its also pretty wrong, this just can't work most of the time. First we should always return a MulltiLineString for type stability, and the we should check if the contents are LinearRing or LineString and I guess convert them?

    GI.ngeom(poly) > 1 && return GI.MultiLineString(collect(GI.getgeom(poly)))

Maybe... just maybe... LineString in GeoInterface should be allowed to wrap any LinearRingTrait object so this can be allocation free. If its just a GI.LinearRing it can simply switch to LineString, otherwise it can wrap. Then LinearRing can do the reverse.

@BG-AIMS
Copy link
Author

BG-AIMS commented Sep 3, 2024

I've realised for my use case I can use something like GO.LineString(GO.Point.(GI.coordinates(polygon))) instead of going through polygon_to_line().

@asinghvi17
Copy link
Member

GI.getpoint will probably be more efficient than GI.coordinates, but otherwise yes!

@rafaqz
Copy link
Member

rafaqz commented Sep 4, 2024

Yeah, never used GI.coordinates if you can help it

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

3 participants