Skip to content

Commit 52b2050

Browse files
committed
Implement geodesic area
1 parent da7e4fd commit 52b2050

File tree

4 files changed

+78
-38
lines changed

4 files changed

+78
-38
lines changed

ext/GeometryOpsProjExt/GeometryOpsProjExt.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ using GeometryOps, Proj
77

88
include("reproject.jl")
99
include("segmentize.jl")
10-
include("perimeter.jl")
10+
include("perimeter_area.jl")
1111

1212
end

ext/GeometryOpsProjExt/perimeter.jl

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import GeometryOps: perimeter, area, applyreduce, TraitTarget, WithTrait
2+
import GeoInterface as GI
3+
4+
function perimeter(m::Geodesic, geom, ::Type{T} = Float64; init = zero(T), kwargs...) where T
5+
# Create a Proj geodesic object using the ellipsoid parameters from the Geodesic manifold
6+
proj_geodesic = Ref(Proj.geod_geodesic(m.semimajor_axis, 1/m.inv_flattening))
7+
proj_polygon = Ref(Proj._null(Proj.geod_polygon))
8+
9+
function _perimeter_geodesic_inner(trait, geom)
10+
@assert GI.npoint(geom) >= 2 "Geodesic perimeter requires at least 2 points"
11+
12+
# Initialize the polygon
13+
proj_polygon[] = Proj._null(Proj.geod_polygon)
14+
Proj.geod_polygon_init(proj_polygon, 1)
15+
16+
# Add all points to the polygon
17+
for point in GI.getpoint(trait, geom)
18+
lat, lon = GI.y(point), GI.x(point) # Proj expects lat, lon order
19+
Proj.geod_polygon_addpoint(proj_geodesic, proj_polygon, lat, lon)
20+
end
21+
22+
# Compute the polygon properties
23+
# geod_polygon_compute returns (num_vertices, perimeter, area)
24+
area_result, perimeter_result = Proj.geod_polygon_compute(proj_geodesic[], proj_polygon[], false, true)
25+
26+
return T(perimeter_result)
27+
end
28+
29+
return applyreduce(
30+
WithTrait(_perimeter_geodesic_inner),
31+
+,
32+
TraitTarget(GI.AbstractCurveTrait),
33+
geom; init, kwargs...
34+
)
35+
end
36+
37+
function GeometryOps.area(m::Geodesic, geom, ::Type{T} = Float64; threaded = False(), init = zero(T), kwargs...) where T
38+
# Create a Proj geodesic object using the ellipsoid parameters from the Geodesic manifold
39+
proj_geodesic = Ref(Proj.geod_geodesic(m.semimajor_axis, 1/m.inv_flattening))
40+
proj_polygon = Ref(Proj._null(Proj.geod_polygon))
41+
42+
function _area_geodesic_inner(trait, geom)
43+
@assert GI.npoint(geom) >= 2 "Geodesic perimeter requires at least 2 points"
44+
45+
# Initialize the polygon
46+
proj_polygon[] = Proj._null(Proj.geod_polygon)
47+
Proj.geod_polygon_init(proj_polygon, 0)
48+
49+
# Add all points to the polygon
50+
for point in GI.getpoint(trait, geom)
51+
lat, lon = GI.y(point), GI.x(point) # Proj expects lat, lon order
52+
Proj.geod_polygon_addpoint(proj_geodesic, proj_polygon, lat, lon)
53+
end
54+
55+
# Compute the polygon properties
56+
# geod_polygon_compute returns (num_vertices, perimeter, area)
57+
area_result, perimeter_result = Proj.geod_polygon_compute(proj_geodesic[], proj_polygon[], true, false)
58+
59+
return T(area_result)
60+
end
61+
62+
return applyreduce(
63+
WithTrait(_area_geodesic_inner),
64+
+,
65+
TraitTarget(GI.AbstractCurveTrait),
66+
geom; init, kwargs...
67+
)
68+
end

src/methods/area.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,12 @@ This is computed slightly differently for different geometries:
6666
Result will be of type T, where T is an optional argument with a default value
6767
of Float64.
6868
"""
69-
function area(geom, ::Type{T} = Float64; threaded=false) where T <: AbstractFloat
70-
applyreduce(WithTrait((trait, g) -> _area(T, trait, g)), +, _AREA_TARGETS, geom; threaded, init=zero(T))
69+
function area(geom, ::Type{T} = Float64; threaded=false, kwargs...) where T <: AbstractFloat
70+
area(Planar(), geom, T; threaded, kwargs...)
71+
end
72+
73+
function area(::Planar, geom, ::Type{T} = Float64; threaded=false, kwargs...) where T <: AbstractFloat
74+
applyreduce(WithTrait((trait, g) -> _area(T, trait, g)), +, _AREA_TARGETS, geom; threaded, init=zero(T), kwargs...)
7175
end
7276

7377
"""
@@ -151,3 +155,6 @@ function _signed_area(::Type{T}, geom) where T
151155
area += _area_component(p1, p2)
152156
return T(area / 2)
153157
end
158+
159+
160+
# ## Spherical

0 commit comments

Comments
 (0)