Skip to content

Commit 790f8fa

Browse files
juliohmeliascarv
andauthored
Add TransformedGeometry (#1002)
* Add TransformedGeometry * More adjustments * Organize code * Update vertex * Add functor implementation * More adjustments * Organize Multi code * Update code * More adjustments * More adjustments * Fix code * Add tests * Apply suggestions from code review * Apply suggestions * Apply suggestions * Add more tests * Fix code * Fix code --------- Co-authored-by: Elias Carvalho <[email protected]>
1 parent c7e0a0c commit 790f8fa

File tree

7 files changed

+188
-22
lines changed

7 files changed

+188
-22
lines changed

src/discretization.jl

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,28 @@ discretize(parsurf::ParaboloidSurface) = discretize(parsurf, RegularDiscretizati
6868

6969
discretize(multi::Multi) = mapreduce(discretize, merge, parent(multi))
7070

71+
discretize(tgeom::TransformedGeometry) = transform(tgeom)(discretize(parent(tgeom)))
72+
7173
discretize(mesh::Mesh) = mesh
7274

75+
# ----------
76+
# FALLBACKS
77+
# ----------
78+
79+
discretize(multi::Multi, method::DiscretizationMethod) =
80+
mapreduce(geom -> discretize(geom, method), merge, parent(multi))
81+
82+
discretize(tgeom::TransformedGeometry, method::DiscretizationMethod) =
83+
transform(tgeom)(discretize(parent(tgeom), method))
84+
7385
# -----------------
7486
# BOUNDARY METHODS
7587
# -----------------
7688

77-
discretize(geometry::Geometry, method::BoundaryTriangulationMethod) = discretizewithin(boundary(geometry), method)
89+
discretize(geometry, method::BoundaryTriangulationMethod) = discretizewithin(boundary(geometry), method)
90+
91+
discretize(multi::Multi, method::BoundaryTriangulationMethod) =
92+
mapreduce(geom -> discretize(geom, method), merge, parent(multi))
7893

7994
function discretize(polygon::Polygon, method::BoundaryTriangulationMethod)
8095
# clean up polygon if necessary
@@ -129,9 +144,6 @@ function discretize(polygon::Polygon, method::BoundaryTriangulationMethod)
129144
end
130145
end
131146

132-
discretize(multi::Multi, method::BoundaryTriangulationMethod) =
133-
mapreduce(geom -> discretize(geom, method), merge, parent(multi))
134-
135147
function discretizewithin(ring::Ring, method::BoundaryTriangulationMethod)
136148
# collect vertices to get rid of static containers
137149
points = collect(vertices(ring))

src/domains/meshes/transformedmesh.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ vertex(m::TransformedMesh, ind::Int) = m.transform(vertex(m.mesh, ind))
3535

3636
centroid(m::TransformedMesh, ind::Int) = m.transform(centroid(m.mesh, ind))
3737

38-
==(m₁::TransformedMesh, m₂::TransformedMesh) = m₁.mesh == m₂.mesh && m₁.transform == m₂.transform
38+
==(m₁::TransformedMesh, m₂::TransformedMesh) = m₁.transform == m₂.transform && m₁.mesh == m₂.mesh
3939

4040
# alias to improve readability in IO methods
4141
const TransformedGrid{M<:Manifold,C<:CRS,Dim,G<:Grid,TR<:Transform} = TransformedMesh{M,C,GridTopology{Dim},G,TR}

src/geometries.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ Base.summary(io::IO, geom::Geometry) = print(io, prettyname(geom))
8181

8282
include("geometries/primitives.jl")
8383
include("geometries/polytopes.jl")
84-
include("geometries/multigeoms.jl")
84+
include("geometries/multigeom.jl")
85+
include("geometries/transformedgeom.jl")
8586

8687
# ------------
8788
# CONVERSIONS

src/geometries/multigeoms.jl renamed to src/geometries/multigeom.jl

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,49 @@ const MultiRope{M<:Manifold,C<:CRS} = Multi{M,C,<:Rope{M,C}}
2929
const MultiRing{M<:Manifold,C<:CRS} = Multi{M,C,<:Ring{M,C}}
3030
const MultiPolygon{M<:Manifold,C<:CRS} = Multi{M,C,<:Polygon{M,C}}
3131
const MultiPolyhedron{M<:Manifold,C<:CRS} = Multi{M,C,<:Polyhedron{M,C}}
32+
const MultiPolytope{K,M<:Manifold,C<:CRS} = Multi{M,C,<:Polytope{K,M,C}}
3233

33-
paramdim(m::Multi) = maximum(paramdim, m.geoms)
34-
35-
vertex(m::Multi, ind) = vertices(m)[ind]
36-
37-
vertices(m::Multi) = [vertex for geom in m.geoms for vertex in vertices(geom)]
38-
39-
nvertices(m::Multi) = sum(nvertices, m.geoms)
34+
Base.parent(m::Multi) = m.geoms
4035

41-
Base.unique(m::Multi) = unique!(deepcopy(m))
36+
# ---------
37+
# GEOMETRY
38+
# ---------
4239

43-
function Base.unique!(m::Multi)
44-
foreach(unique!, m.geoms)
45-
m
46-
end
40+
paramdim(m::Multi) = maximum(paramdim, m.geoms)
4741

4842
function centroid(m::Multi)
4943
cs = to.(centroid.(m.geoms))
5044
withcrs(m, sum(cs) / length(cs))
5145
end
5246

53-
rings(m::MultiPolygon) = [ring for poly in m.geoms for ring in rings(poly)]
54-
55-
Base.parent(m::Multi) = m.geoms
56-
5747
==(m₁::Multi, m₂::Multi) = m₁.geoms == m₂.geoms
5848

5949
Base.isapprox(m₁::Multi, m₂::Multi; atol=atol(lentype(m₁)), kwargs...) =
6050
length(m₁.geoms) == length(m₂.geoms) && all(isapprox(g₁, g₂; atol, kwargs...) for (g₁, g₂) in zip(m₁.geoms, m₂.geoms))
6151

52+
# ---------
53+
# POLYTOPE
54+
# ---------
55+
56+
vertex(m::MultiPolytope, ind) = vertices(m)[ind]
57+
58+
vertices(m::MultiPolytope) = [vertex for geom in m.geoms for vertex in vertices(geom)]
59+
60+
nvertices(m::MultiPolytope) = sum(nvertices, m.geoms)
61+
62+
Base.unique(m::MultiPolytope) = unique!(deepcopy(m))
63+
64+
function Base.unique!(m::MultiPolytope)
65+
foreach(unique!, m.geoms)
66+
m
67+
end
68+
69+
# --------
70+
# POLYGON
71+
# --------
72+
73+
rings(m::MultiPolygon) = [ring for poly in m.geoms for ring in rings(poly)]
74+
6275
# -----------
6376
# IO METHODS
6477
# -----------

src/geometries/transformedgeom.jl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# ------------------------------------------------------------------
2+
# Licensed under the MIT License. See LICENSE in the project root.
3+
# ------------------------------------------------------------------
4+
5+
"""
6+
TransformedGeometry(geometry, transform)
7+
8+
Lazy representation of a geometric `transform` applied to a `geometry`.
9+
"""
10+
struct TransformedGeometry{M<:Manifold,C<:CRS,G<:Geometry,T<:Transform} <: Geometry{M,C}
11+
geometry::G
12+
transform::T
13+
14+
function TransformedGeometry{M,C}(geometry::G, transform::T) where {M<:Manifold,C<:CRS,G<:Geometry,T<:Transform}
15+
new{M,C,G,T}(geometry, transform)
16+
end
17+
end
18+
19+
function TransformedGeometry(g::Geometry, t::Transform)
20+
p = t(centroid(g))
21+
TransformedGeometry{manifold(p),crs(p)}(g, t)
22+
end
23+
24+
# specialize constructor to avoid deep structures
25+
TransformedGeometry(g::TransformedGeometry, t::Transform) = TransformedGeometry(g.geometry, g.transform t)
26+
27+
# type aliases for convenience
28+
const TransformedPoint{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Point,T}
29+
const TransformedSegment{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Segment,T}
30+
const TransformedRope{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Rope,T}
31+
const TransformedRing{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Ring,T}
32+
const TransformedPolygon{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Polygon,T}
33+
const TransformedPolyhedron{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Polyhedron,T}
34+
const TransformedPolytope{M<:Manifold,C<:CRS,T<:Transform} = TransformedGeometry{M,C,<:Polytope,T}
35+
36+
Base.parent(g::TransformedGeometry) = g.geometry
37+
38+
transform(g::TransformedGeometry) = g.transform
39+
40+
# ---------
41+
# GEOMETRY
42+
# ---------
43+
44+
paramdim(g::TransformedGeometry) = paramdim(g.geometry)
45+
46+
centroid(g::TransformedGeometry) = g.transform(centroid(g.geometry))
47+
48+
==(g₁::TransformedGeometry, g₂::TransformedGeometry) = g₁.transform == g₂.transform && g₁.geometry == g₂.geometry
49+
50+
Base.isapprox(g₁::TransformedGeometry, g₂::TransformedGeometry; atol=atol(lentype(g₁)), kwargs...) =
51+
isapprox(g₁.geometry, g₂.geometry; atol, kwargs...) && g₁.transform == g₂.transform
52+
53+
(g::TransformedGeometry)(uvw...) = g.transform(g.geometry(uvw...))
54+
55+
# ---------
56+
# POLYTOPE
57+
# ---------
58+
59+
vertex(p::TransformedPolytope, ind) = p.transform(vertex(p.geometry, ind))
60+
61+
vertices(p::TransformedPolytope) = map(p.transform, vertices(p.geometry))
62+
63+
nvertices(p::TransformedPolytope) = nvertices(p.geometry)
64+
65+
Base.unique(p::TransformedPolytope) = unique!(deepcopy(p))
66+
67+
Base.unique!(p::TransformedPolytope) = (unique!(p.geometry); p)
68+
69+
# --------
70+
# POLYGON
71+
# --------
72+
73+
rings(p::TransformedPolygon) = map(p.transform, rings(p.geometry))
74+
75+
# -----------
76+
# IO METHODS
77+
# -----------
78+
79+
function Base.summary(io::IO, g::TransformedGeometry)
80+
name = prettyname(g.geometry)
81+
print(io, "Transformed$name")
82+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ testfiles = [
5151
"primitives.jl",
5252
"polytopes.jl",
5353
"multigeoms.jl",
54+
"transformedgeoms.jl",
5455
"connectivities.jl",
5556
"topologies.jl",
5657
"toporelations.jl",

test/transformedgeoms.jl

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@testset "TransformedGeometry" begin
2+
b = Box(cart(0, 0), cart(1, 1))
3+
t = Translate(T(1), T(2))
4+
tb = Meshes.TransformedGeometry(b, t)
5+
@test parent(tb) == b
6+
@test Meshes.transform(tb) == t
7+
t2 = Scale(T(2), T(3))
8+
tb2 = Meshes.TransformedGeometry(tb, t2)
9+
@test Meshes.transform(tb2) == (t t2)
10+
@test paramdim(tb) == paramdim(b)
11+
@test centroid(tb) == t(centroid(b))
12+
@test discretize(tb) == t(discretize(b))
13+
@test tb(T(0.5), T(0.5)) == t(b(T(0.5), T(0.5)))
14+
t3 = Scale(T(2), T(2))
15+
tb3 = Meshes.TransformedGeometry(b, t3)
16+
@test measure(tb3) == 4 * measure(b)
17+
equaltest(tb)
18+
isapproxtest(tb)
19+
20+
b = Ball(latlon(0, 0), T(1))
21+
t = Proj(Cartesian)
22+
tb = Meshes.TransformedGeometry(b, t)
23+
@test paramdim(tb) == paramdim(b)
24+
@test centroid(tb) == t(centroid(b))
25+
equaltest(tb)
26+
isapproxtest(tb)
27+
28+
s = Sphere(latlon(0, 0), T(1))
29+
t = Proj(Cartesian)
30+
ts = Meshes.TransformedGeometry(s, t)
31+
@test paramdim(ts) == paramdim(s)
32+
@test centroid(ts) == t(centroid(s))
33+
equaltest(ts)
34+
isapproxtest(ts)
35+
36+
s = Segment(cart(0, 0), cart(1, 1))
37+
t = Translate(T(1), T(2))
38+
ts = Meshes.TransformedGeometry(s, t)
39+
@test vertex(ts, 1) == t(vertex(s, 1))
40+
@test vertices(ts) == t.(vertices(s))
41+
@test nvertices(ts) == nvertices(s)
42+
equaltest(ts)
43+
isapproxtest(ts)
44+
45+
p = PolyArea(cart(0, 0), cart(1, 0), cart(1, 1), cart(0, 1))
46+
t = Translate(T(1), T(2))
47+
tp = Meshes.TransformedGeometry(p, t)
48+
@test vertex(tp, 1) == t(vertex(p, 1))
49+
@test vertices(tp) == t.(vertices(p))
50+
@test nvertices(tp) == nvertices(p)
51+
@test rings(tp) == t.(rings(p))
52+
p2 = PolyArea(cart(0, 0), cart(0, 0), cart(1, 0), cart(1, 1), cart(0, 1))
53+
tp2 = Meshes.TransformedGeometry(p2, t)
54+
@test unique(tp2) == tp
55+
equaltest(tp)
56+
isapproxtest(tp)
57+
end

0 commit comments

Comments
 (0)