Skip to content

Commit

Permalink
Sg/update intersects (#21)
Browse files Browse the repository at this point in the history
* Fix up intersection point base calculation

* Update intersects and add line tests

* Add more tests and debug intersects

* Add comments to point_in_poly
  • Loading branch information
skygering authored Oct 4, 2023
1 parent 2ab27e4 commit 38dc5ed
Show file tree
Hide file tree
Showing 12 changed files with 518 additions and 119 deletions.
6 changes: 2 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ authors = ["Anshul Singhvi <anshulsinghvi@gmail.com> and contributors"]
version = "0.0.1-DEV"

[deps]
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
ExactPredicates = "429591f6-91af-11e9-00e2-59fbe8cec110"
GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
Expand All @@ -26,7 +27,4 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = [
"ArchGDAL", "Distributions", "GeoFormatTypes", "GeoJSON", "LibGEOS",
"Random", "Test",
]
test = ["ArchGDAL", "Distributions", "GeoFormatTypes", "GeoJSON", "LibGEOS", "Random", "Test"]
84 changes: 44 additions & 40 deletions src/methods/bools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -265,63 +265,66 @@ function point_in_polygon(
end

# Then check the point is inside the exterior ring
point_in_polygon(point, GI.getexterior(poly); ignore_boundary, check_extent=false) || return false
point_in_polygon(
point,GI.getexterior(poly);
ignore_boundary, check_extent=false,
) || return false

# Finally make sure the point is not in any of the holes,
# flipping the boundary condition
for ring in GI.gethole(poly)
point_in_polygon(point, ring; ignore_boundary=!ignore_boundary) && return false
point_in_polygon(
point, ring;
ignore_boundary=!ignore_boundary,
) && return false
end
return true
end

function point_in_polygon(
::PointTrait, pt,
::Union{LineStringTrait,LinearRingTrait}, ring;
ignore_boundary::Bool=false,
check_extent::Bool=false,
)::Bool
x, y = GI.x(pt), GI.y(pt)
# Cheaply check that the point is inside the ring extent
if check_extent
point_in_extent(point, GI.extent(ring)) || return false
end

# Then check the point is inside the ring
inside = false
n = GI.npoint(ring)
p_start = GI.getpoint(ring, 1)
p_end = GI.getpoint(ring, n)

# Handle closed on non-closed rings
l = if GI.x(p_start) == GI.x(p_end) && GI.y(p_start) == GI.y(p_end)
l = n - 1
else
n
# Handle closed vs opne rings
if GI.x(p_start) == GI.x(p_end) && GI.y(p_start) == GI.y(p_end)
n -= 1
end

# Loop over all points in the ring
for i in 1:l - 1
j = i + 1

for i in 1:(n - 1)
# First point on edge
p_i = GI.getpoint(ring, i)
p_j = GI.getpoint(ring, j)
xi = GI.x(p_i)
yi = GI.y(p_i)
xj = GI.x(p_j)
yj = GI.y(p_j)

on_boundary = (GI.y(pt) * (xi - xj) + yi * (xj - GI.x(pt)) + yj * (GI.x(pt) - xi) == 0) &&
((xi - GI.x(pt)) * (xj - GI.x(pt)) <= 0) && ((yi - GI.y(pt)) * (yj - GI.y(pt)) <= 0)

xi, yi = GI.x(p_i), GI.y(p_i)
# Second point on edge (j = i + 1)
p_j = GI.getpoint(ring, i + 1)
xj, yj = GI.x(p_j), GI.y(p_j)
# Check if point is on the ring boundary
on_boundary = ( # vertex to point has same slope as edge
yi * (xj - x) + yj * (x - xi) == y * (xj - xi) &&
(xi - x) * (xj - x) <= 0 && # x is between xi and xj
(yi - y) * (yj - y) <= 0 # y is between yi and yj
)
on_boundary && return !ignore_boundary

intersects = ((yi > GI.y(pt)) !== (yj > GI.y(pt))) &&
(GI.x(pt) < (xj - xi) * (GI.y(pt) - yi) / (yj - yi) + xi)

# Check if ray from point passes through edge
intersects = (
(yi > y) !== (yj > y) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi)
)
if intersects
inside = !inside
end
end

return inside
end

Expand All @@ -341,6 +344,7 @@ function line_on_line(t1::GI.AbstractCurveTrait, line1, t2::AbstractCurveTrait,
end

line_in_polygon(line, poly) = line_in_polygon(trait(line), line, trait(poly), poly)

function line_in_polygon(
::AbstractCurveTrait, line,
::Union{AbstractPolygonTrait,LinearRingTrait}, poly
Expand All @@ -365,19 +369,19 @@ function line_in_polygon(
end

function polygon_in_polygon(poly1, poly2)
# edges1, edges2 = to_edges(poly1), to_edges(poly2)
# extent1, extent2 = to_extent(edges1), to_extent(edges2)
# Check the extents intersect
Extents.intersects(GI.extent(poly1), GI.extent(poly2)) || return false

# Check all points in poly1 are in poly2
for point in GI.getpoint(poly1)
point_in_polygon(point, poly2) || return false
end
# edges1, edges2 = to_edges(poly1), to_edges(poly2)
# extent1, extent2 = to_extent(edges1), to_extent(edges2)
# Check the extents intersect
Extents.intersects(GI.extent(poly1), GI.extent(poly2)) || return false

# Check all points in poly1 are in poly2
for point in GI.getpoint(poly1)
point_in_polygon(point, poly2) || return false
end

# Check the line of poly1 does not intersect the line of poly2
line_intersects(poly1, poly2) && return false
# Check the line of poly1 does not intersect the line of poly2
#intersects(poly1, poly2) && return false

# poly1 must be in poly2
return true
# poly1 must be in poly2
return true
end
4 changes: 2 additions & 2 deletions src/methods/crosses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ end

function line_crosses_line(line1, line2)
np2 = GI.npoint(line2)
if line_intersects(line1, line2; meets=MEETS_CLOSED)
if intersects(line1, line2; meets=MEETS_CLOSED)
for i in 1:GI.npoint(line1) - 1
for j in 1:GI.npoint(line2) - 1
exclude_boundary = (j === 1 || j === np2 - 2) ? :none : :both
Expand All @@ -71,7 +71,7 @@ end

function line_crosses_poly(line, poly)
for l in flatten(AbstractCurveTrait, poly)
line_intersects(line, l) && return true
intersects(line, l) && return true
end
return false
end
Expand Down
2 changes: 1 addition & 1 deletion src/methods/disjoint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ function polygon_disjoint(poly1, poly2)
for point in GI.getpoint(poly2)
point_in_polygon(point, poly1) && return false
end
return !line_intersects(poly1, poly2)
return !intersects(poly1, poly2)
end
Loading

1 comment on commit 38dc5ed

@skygering
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@rafaqz @asinghvi17 I somehow merged this by mistake... I meant to merge it from a branch on my fork into my main branch on the fork and then open a PR back to this repo. But I think I just clicked the open PR button too quickly and then tried to bypass the PR tests on my fork due to limited GitHub Action minutes and having tested it locally. I am happy with the changes, but there were some things I wanted to discuss first. However, I still think it is an improvement. Would you prefer that I revert back to the previous commit, or are we okay to leave this and if there are changes, I will open a new branch and go from there?

Please sign in to comment.