Skip to content

Commit aedfdd4

Browse files
committed
2 parents 495cad6 + 8a7ded9 commit aedfdd4

File tree

11 files changed

+335
-76
lines changed

11 files changed

+335
-76
lines changed

docs/src/domains/meshes.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
```@example meshes
44
using Meshes # hide
5+
using CoordRefSystems # hide
56
import CairoMakie as Mke # hide
67
```
78

@@ -15,6 +16,17 @@ Mesh
1516
Grid
1617
```
1718

19+
```@docs
20+
RegularGrid
21+
```
22+
23+
```@example meshes
24+
# 2D regular grid
25+
grid = RegularGrid((8, 8), Point(Polar(0, 0)), (1, π/4))
26+
27+
viz(grid, showsegments = true)
28+
```
29+
1830
```@docs
1931
CartesianGrid
2032
```

src/Meshes.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ export
302302
Grid,
303303
SimpleMesh,
304304
TransformedMesh,
305+
RegularGrid,
305306
CartesianGrid,
306307
RectilinearGrid,
307308
StructuredGrid,

src/domains/meshes.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ end
240240
# IMPLEMENTATIONS
241241
# ----------------
242242

243+
include("meshes/regulargrid.jl")
243244
include("meshes/cartesiangrid.jl")
244245
include("meshes/rectilineargrid.jl")
245246
include("meshes/structuredgrid.jl")

src/domains/meshes/cartesiangrid.jl

Lines changed: 25 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Finally, a Cartesian grid can be constructed by only passing the dimensions
3030
`dims` as a tuple, or by passing each dimension `dim1`, `dim2`, ... separately.
3131
In this case, the origin and spacing default to (0,0,...) and (1,1,...).
3232
33+
`CartesianGrid` is an alias to [`RegularGrid`](@ref) with `Cartesian` CRS.
34+
3335
## Examples
3436
3537
Create a 3D grid with 100x100x50 hexahedrons:
@@ -49,31 +51,34 @@ Create a 1D grid from -1 to 1 with 100 segments:
4951
```julia
5052
julia> CartesianGrid((-1.0,), (1.0,), dims=(100,))
5153
```
54+
55+
See also [`RegularGrid`](@ref).
5256
"""
53-
struct CartesianGrid{C<:CRS,Mₚ<:Manifold,Dim,ℒ<:Len} <: Grid{𝔼{Dim},C,Dim}
54-
origin::Point{Mₚ,C}
55-
spacing::NTuple{Dim,ℒ}
56-
offset::Dims{Dim}
57-
topology::GridTopology{Dim}
57+
const CartesianGrid{M<:𝔼,C<:Cartesian} = RegularGrid{M,C}
5858

59-
function CartesianGrid(
60-
origin::Point{Mₚ,C},
61-
spacing::NTuple{Dim,ℒ},
62-
offset::Dims{Dim},
63-
topology::GridTopology{Dim}
64-
) where {C<:CRS,Mₚ<:Manifold,Dim,ℒ<:Len}
65-
if !all(>(zero(ℒ)), spacing)
66-
throw(ArgumentError("spacing must be positive"))
67-
end
68-
new{C,Mₚ,Dim,float(ℒ)}(origin, spacing, offset, topology)
69-
end
59+
function CartesianGrid(
60+
origin::Point{<:𝔼},
61+
spacing::NTuple{Dim,ℒ},
62+
offset::Dims{Dim},
63+
topology::GridTopology{Dim}
64+
) where {Dim,ℒ<:Len}
65+
orig = Point(convert(Cartesian, coords(origin)))
66+
RegularGrid(orig, spacing, offset, topology)
7067
end
7168

72-
CartesianGrid(origin::Point, spacing::NTuple{Dim,Len}, offset::Dims{Dim}, topology::GridTopology{Dim}) where {Dim} =
73-
CartesianGrid(origin, promote(spacing...), offset, topology)
69+
CartesianGrid(
70+
origin::Point{<:𝔼},
71+
spacing::NTuple{Dim,Len},
72+
offset::Dims{Dim},
73+
topology::GridTopology{Dim}
74+
) where {Dim} = CartesianGrid(origin, promote(spacing...), offset, topology)
7475

75-
CartesianGrid(origin::Point, spacing::NTuple{Dim,Number}, offset::Dims{Dim}, topology::GridTopology{Dim}) where {Dim} =
76-
CartesianGrid(origin, addunit.(spacing, u"m"), offset, topology)
76+
CartesianGrid(
77+
origin::Point{<:𝔼},
78+
spacing::NTuple{Dim,Number},
79+
offset::Dims{Dim},
80+
topology::GridTopology{Dim}
81+
) where {Dim} = CartesianGrid(origin, addunit.(spacing, u"m"), offset, topology)
7782

7883
function CartesianGrid(
7984
dims::Dims{Dim},
@@ -131,51 +136,3 @@ function CartesianGrid(dims::Dims{Dim}) where {Dim}
131136
end
132137

133138
CartesianGrid(dims::Int...) = CartesianGrid(dims)
134-
135-
spacing(g::CartesianGrid) = g.spacing
136-
137-
offset(g::CartesianGrid) = g.offset
138-
139-
vertex(g::CartesianGrid, ijk::Dims) = g.origin + Vec((ijk .- g.offset) .* g.spacing)
140-
141-
function xyz(g::CartesianGrid)
142-
dims = size(g)
143-
spac = spacing(g)
144-
orig = to(minimum(g))
145-
ntuple(embeddim(g)) do i
146-
o, s, d = orig[i], spac[i], dims[i]
147-
range(start=o, step=s, length=(d + 1))
148-
end
149-
end
150-
151-
XYZ(g::CartesianGrid) = XYZ(xyz(g))
152-
153-
function Base.getindex(g::CartesianGrid, I::CartesianIndices)
154-
@boundscheck _checkbounds(g, I)
155-
dims = size(I)
156-
offset = g.offset .- Tuple(first(I)) .+ 1
157-
CartesianGrid(dims, g.origin, g.spacing, offset)
158-
end
159-
160-
==(g₁::CartesianGrid, g₂::CartesianGrid) =
161-
g₁.topology == g₂.topology &&
162-
g₁.spacing == g₂.spacing &&
163-
Tuple(g₁.origin - g₂.origin) == (g₁.offset .- g₂.offset) .* g₁.spacing
164-
165-
# -----------
166-
# IO METHODS
167-
# -----------
168-
169-
function Base.summary(io::IO, g::CartesianGrid)
170-
dims = join(size(g.topology), "×")
171-
print(io, "$dims CartesianGrid")
172-
end
173-
174-
Base.show(io::IO, g::CartesianGrid) = summary(io, g)
175-
176-
function Base.show(io::IO, ::MIME"text/plain", g::CartesianGrid)
177-
println(io, g)
178-
println(io, "├─ minimum: ", minimum(g))
179-
println(io, "├─ maximum: ", maximum(g))
180-
print(io, "└─ spacing: ", spacing(g))
181-
end

src/domains/meshes/regulargrid.jl

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
5+
"""
6+
RegularGrid(dims, origin, spacing)
7+
8+
A regular grid with dimensions `dims`, lower left corner at `origin`
9+
and cell spacing `spacing`. The three arguments must have the same length.
10+
11+
RegularGrid(dims, origin, spacing, offset)
12+
13+
A regular grid with dimensions `dims`, with lower left corner of element
14+
`offset` at `origin` and cell spacing `spacing`.
15+
16+
## Examples
17+
18+
```
19+
RegularGrid((10, 20), Point(LatLon(30.0°, 60.0°)), (1.0, 1.0)) # add coordinate units to spacing
20+
RegularGrid((10, 20), Point(Polar(0.0mm, 0.0rad)), (10.0mm, 1.0rad)) # convert spacing units to coordinate units
21+
RegularGrid((10, 20), Point(Marcator(0.0, 0.0)), (1.5, 1.5))
22+
RegularGrid((10, 20, 30), Point(Cylindrical(0.0, 0.0, 0.0)), (3.0, 2.0, 1.0))
23+
```
24+
25+
See also [`CartesianGrid`](@ref).
26+
"""
27+
struct RegularGrid{M<:Manifold,C<:CRS,S<:Tuple,N} <: Grid{M,C,N}
28+
origin::Point{M,C}
29+
spacing::S
30+
offset::Dims{N}
31+
topology::GridTopology{N}
32+
33+
function RegularGrid{M,C,S,N}(origin, spacing, offset, topology) where {M<:Manifold,C<:CRS,S<:Tuple,N}
34+
if !all(s -> s > zero(s), spacing)
35+
throw(ArgumentError("spacing must be positive"))
36+
end
37+
new(origin, spacing, offset, topology)
38+
end
39+
end
40+
41+
function RegularGrid(
42+
origin::Point{M,C},
43+
spacing::Tuple,
44+
offset::Dims{N},
45+
topology::GridTopology{N}
46+
) where {M<:Manifold,C<:CRS,N}
47+
if manifold(origin) <: 🌐 && !(crs(origin) <: LatLon)
48+
throw(ArgumentError("regular spacing on `🌐` requires `LatLon` coordinates"))
49+
end
50+
51+
T = CoordRefSystems.mactype(C)
52+
nc = CoordRefSystems.ncoords(C)
53+
us = CoordRefSystems.units(C)
54+
ns = length(spacing)
55+
56+
if N nc
57+
throw(ArgumentError("""
58+
A $N-dimensional regular grid requires an origin with $N coordinates.
59+
The provided origin has $nc coordinates.
60+
"""))
61+
end
62+
63+
if ns nc
64+
throw(ArgumentError("""
65+
A $N-dimensional regular grid requires $N spacing values.
66+
The provided spacing has $ns values.
67+
"""))
68+
end
69+
70+
sp = ntuple(i -> numconvert(T, _withunit(spacing[i], us[i])), nc)
71+
72+
RegularGrid{M,C,typeof(sp),N}(origin, sp, offset, topology)
73+
end
74+
75+
function RegularGrid(dims::Dims{N}, origin::Point, spacing::Tuple, offset::Dims{N}=ntuple(i -> 1, N)) where {N}
76+
if !all(>(0), dims)
77+
throw(ArgumentError("dimensions must be positive"))
78+
end
79+
RegularGrid(origin, spacing, offset, GridTopology(dims))
80+
end
81+
82+
spacing(g::RegularGrid) = g.spacing
83+
84+
offset(g::RegularGrid) = g.offset
85+
86+
function vertex(g::RegularGrid, ijk::Dims)
87+
ctor = CoordRefSystems.constructor(crs(g))
88+
orig = CoordRefSystems.values(coords(g.origin))
89+
vals = orig .+ (ijk .- g.offset) .* g.spacing
90+
Point(ctor(vals...))
91+
end
92+
93+
@generated function xyz(g::RegularGrid{M,C,S,N}) where {M,C,S,N}
94+
exprs = ntuple(N) do i
95+
:(range(start=orig[$i], step=spac[$i], length=(dims[$i] + 1)))
96+
end
97+
98+
quote
99+
dims = size(g)
100+
spac = spacing(g)
101+
orig = CoordRefSystems.values(coords(g.origin))
102+
($(exprs...),)
103+
end
104+
end
105+
106+
XYZ(g::RegularGrid) = XYZ(xyz(g))
107+
108+
function Base.getindex(g::RegularGrid, I::CartesianIndices)
109+
@boundscheck _checkbounds(g, I)
110+
dims = size(I)
111+
offset = g.offset .- Tuple(first(I)) .+ 1
112+
RegularGrid(dims, g.origin, g.spacing, offset)
113+
end
114+
115+
function ==(g₁::RegularGrid, g₂::RegularGrid)
116+
orig₁ = CoordRefSystems.values(coords(g₁.origin))
117+
orig₂ = CoordRefSystems.values(coords(g₂.origin))
118+
g₁.topology == g₂.topology && g₁.spacing == g₂.spacing && orig₁ .- orig₂ == (g₁.offset .- g₂.offset) .* g₁.spacing
119+
end
120+
121+
# -----------
122+
# IO METHODS
123+
# -----------
124+
125+
function Base.summary(io::IO, g::RegularGrid)
126+
dims = join(size(g.topology), "×")
127+
name = prettyname(g)
128+
print(io, "$dims $name")
129+
end
130+
131+
function Base.show(io::IO, ::MIME"text/plain", g::RegularGrid)
132+
summary(io, g)
133+
println(io)
134+
println(io, "├─ minimum: ", minimum(g))
135+
println(io, "├─ maximum: ", maximum(g))
136+
print(io, "└─ spacing: ", spacing(g))
137+
end
138+
139+
# -----------------
140+
# HELPER FUNCTIONS
141+
# -----------------
142+
143+
_withunit(x::Number, u) = x * u
144+
_withunit(x::Quantity, u) = uconvert(u, x)

src/transforms/proj.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ applycoord(t::Proj{<:Projected}, g::Primitive{<:🌐}) = TransformedGeometry(g,
4949

5050
applycoord(t::Proj{<:Geographic}, g::Primitive{<:𝔼}) = TransformedGeometry(g, t)
5151

52-
applycoord(t::Proj, g::RectilinearGrid) = applycoord(t, convert(SimpleMesh, g))
52+
applycoord(t::Proj, g::RegularGrid) = TransformedGrid(g, t)
5353

54-
applycoord(t::Proj, g::StructuredGrid) = applycoord(t, convert(SimpleMesh, g))
54+
applycoord(t::Proj, g::RectilinearGrid) = TransformedGrid(g, t)
55+
56+
applycoord(t::Proj, g::StructuredGrid) = TransformedGrid(g, t)
5557

5658
# -----------
5759
# IO METHODS

src/units.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,10 @@ addunit(x::Number, u) = x * u
1818
addunit(x::AbstractArray{<:Number}, u) = x * u
1919
addunit(::Quantity, _) = throw(ArgumentError("invalid units, please check the documentation"))
2020
addunit(::AbstractArray{<:Quantity}, _) = throw(ArgumentError("invalid units, please check the documentation"))
21+
22+
"""
23+
numconvert(T, x)
24+
25+
Converts the number type of quantity `x` to `T`.
26+
"""
27+
numconvert(::Type{T}, x::Quantity{S,D,U}) where {T,S,D,U} = convert(Quantity{T,D,U}, x)

src/utils/basic.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ collectat(vec::AbstractVector, inds) = vec[inds]
4242
4343
Generate the coordinate arrays `XYZ` from the coordinate vectors `xyz`.
4444
"""
45-
@generated function XYZ(xyz::NTuple{Dim,<:AbstractVector{T}}) where {Dim,T}
45+
@generated function XYZ(xyz::NTuple{Dim,AbstractVector}) where {Dim}
4646
exprs = ntuple(Dim) do d
4747
quote
4848
a = xyz[$d]
49-
A = Array{T,Dim}(undef, length.(xyz))
49+
A = Array{eltype(a),Dim}(undef, length.(xyz))
5050
@nloops $Dim i A begin
5151
@nref($Dim, A, i) = a[$(Symbol(:i_, d))]
5252
end

test/crs.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
@test crs(d) <: Mercator{WGS84Latest}
3434
d = PointSet([merc(0, 0), merc(1, 1)])
3535
@test crs(d) <: Mercator{WGS84Latest}
36-
d = CartesianGrid((10, 10), merc(0, 0), (T(1), T(1)))
36+
d = RegularGrid((10, 10), merc(0, 0), (T(1), T(1)))
3737
@test crs(d) <: Mercator{WGS84Latest}
3838
p = merc.([(0, 0), (1, 0), (0, 1), (1, 1), (0.5, 0.5)])
3939
c = connect.([(1, 2, 5), (2, 4, 5), (4, 3, 5), (3, 1, 5)], Triangle)
@@ -137,7 +137,7 @@ end
137137
@test crs(d) <: LatLon{WGS84Latest}
138138
d = PointSet([latlon(0, 0), latlon(1, 1)])
139139
@test crs(d) <: LatLon{WGS84Latest}
140-
d = CartesianGrid((10, 10, 10), latlon(0, 0), (T(1), T(1), T(1)))
140+
d = RegularGrid((10, 10), latlon(0, 0), (T(1), T(1)))
141141
@test crs(d) <: LatLon{WGS84Latest}
142142
p = latlon.([(0, 0), (0, 1), (1, 0), (1, 1), (0.5, 0.5)])
143143
c = connect.([(1, 2, 5), (2, 4, 5), (4, 3, 5), (3, 1, 5)], Triangle)

0 commit comments

Comments
 (0)