Skip to content

Commit

Permalink
Add ParametrizedCurve (#1093)
Browse files Browse the repository at this point in the history
* add ParametrizedCurve

* include file

* add docstring

* format

* remove underscores in names

* use minimum and maximum

* fix

* interval ab as optional argument

* format

* move include

* Apply suggestions from code review

Co-authored-by: Júlio Hoffimann <julio.hoffimann@gmail.com>

* restructure range

* Apply suggestions from code review

Co-authored-by: Júlio Hoffimann <julio.hoffimann@gmail.com>

* promote range

* Update src/geometries/primitives/parametrizedcurve.jl

* Update src/geometries/primitives/parametrizedcurve.jl

* Update src/geometries/primitives/parametrizedcurve.jl

Co-authored-by: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com>

* add docs

* Update src/geometries/primitives/parametrizedcurve.jl

Co-authored-by: Júlio Hoffimann <julio.hoffimann@gmail.com>

* remove newline

* fix Float32 tests

* add predicates test

* add crs test

* add sampling test

* add discretization tests

* format

* use cart and merc consistently

* Apply suggestions from code review

Co-authored-by: Júlio Hoffimann <julio.hoffimann@gmail.com>

* Update src/geometries/primitives/parametrizedcurve.jl

Co-authored-by: Elias Carvalho <73039601+eliascarv@users.noreply.github.com>

* func -> fun

---------

Co-authored-by: Júlio Hoffimann <julio.hoffimann@gmail.com>
Co-authored-by: Elias Carvalho <73039601+eliascarv@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 9, 2024
1 parent 994b30a commit fe86b2e
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 0 deletions.
10 changes: 10 additions & 0 deletions docs/src/geometries/primitives.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ BezierCurve
BezierCurve((0.,0.), (1.,0.), (1.,1.)) |> viz
```

### ParametrizedCurve

```@docs
ParametrizedCurve
```

```@example primitives
ParametrizedCurve(t -> Point(cos(t), sin(t), 0.2t), (0, 4π)) |> viz
```

### Plane

```@docs
Expand Down
1 change: 1 addition & 0 deletions src/Meshes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export
Ray,
Line,
BezierCurve,
ParametrizedCurve,
Plane,
Box,
Ball,
Expand Down
5 changes: 5 additions & 0 deletions src/boundary.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ function boundary(b::BezierCurve)
p₁ p₂ ? nothing : Multi([p₁, p₂])
end

function boundary(c::ParametrizedCurve)
p₁, p₂ = extrema(c)
p₁ p₂ ? nothing : Multi([p₁, p₂])
end

boundary(::Plane) = nothing

boundary(b::Box{𝔼{1}}) = Multi([minimum(b), maximum(b)])
Expand Down
2 changes: 2 additions & 0 deletions src/discretization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ end

simplexify(bezier::BezierCurve) = discretize(bezier, RegularDiscretization(50))

simplexify(curve::ParametrizedCurve) = discretize(curve, RegularDiscretization(50))

simplexify(sphere::Sphere{𝔼{2}}) = discretize(sphere, RegularDiscretization(50))

simplexify(circle::Circle) = discretize(circle, RegularDiscretization(50))
Expand Down
1 change: 1 addition & 0 deletions src/geometries/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ include("primitives/point.jl")
include("primitives/ray.jl")
include("primitives/line.jl")
include("primitives/bezier.jl")
include("primitives/parametrizedcurve.jl")
include("primitives/plane.jl")
include("primitives/box.jl")
include("primitives/ball.jl")
Expand Down
44 changes: 44 additions & 0 deletions src/geometries/primitives/parametrizedcurve.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ------------------------------------------------------------------
# Licensed under the MIT License. See LICENSE in the project root.
# ------------------------------------------------------------------

"""
ParametrizedCurve(fun, range = (0.0, 1.0))
A parametrized curve is a curve defined by a function `fun` that maps a
(unitless) parameter `t` in the given `range` to a `Point` in space.
## Examples
```julia
ParametrizedCurve(t -> Point(cos(t), sin(t)), (0, 2π))
```
"""
struct ParametrizedCurve{M<:Manifold,C<:CRS,F<:Function,R<:Tuple} <: Primitive{M,C}
fun::F
range::R
ParametrizedCurve{M,C}(fun::F, range::R) where {M<:Manifold,C<:CRS,F<:Function,R<:Tuple} = new{M,C,F,R}(fun, range)
end

function ParametrizedCurve(fun, range=(0.0, 1.0))
a, b = promote(range...)
r = (a, b)
p = fun(a)
ParametrizedCurve{manifold(p),crs(p)}(fun, r)
end

paramdim(::Type{<:ParametrizedCurve}) = 1

Base.minimum(curve::ParametrizedCurve) = curve.fun(first(curve.range))

Base.maximum(curve::ParametrizedCurve) = curve.fun(last(curve.range))

Base.extrema(curve::ParametrizedCurve) = minimum(curve), maximum(curve)

function (curve::ParametrizedCurve)(t)
if t < 0 || t > 1
throw(DomainError(t, "c(t) is not defined for t outside [0, 1]."))
end
a, b = curve.range
curve.fun(a + t * (b - a))
end
2 changes: 2 additions & 0 deletions src/predicates/isparametrized.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ isparametrized(::Type{<:Plane}) = true

isparametrized(::Type{<:BezierCurve}) = true

isparametrized(::Type{<:ParametrizedCurve}) = true

isparametrized(::Type{<:Box{<:𝔼}}) = true

isparametrized(::Type{<:Ball{<:𝔼}}) = true
Expand Down
2 changes: 2 additions & 0 deletions src/predicates/isperiodic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ isperiodic(::Type{<:Line}) = (false,)

isperiodic(b::BezierCurve) = (first(controls(b)) == last(controls(b)),)

isperiodic(c::ParametrizedCurve) = (minimum(c) == maximum(c),)

isperiodic(::Type{<:Plane}) = (false, false)

isperiodic(B::Type{<:Box}) = ntuple(i -> false, embeddim(B))
Expand Down
2 changes: 2 additions & 0 deletions test/crs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
@test crs(g) <: Mercator{WGS84Latest}
g = BezierCurve(merc(0, 0), merc(1, 1), merc(2, 0))
@test crs(g) <: Mercator{WGS84Latest}
g = ParametrizedCurve(t -> merc(cos(t), sin(t)), (T(0), T(2π)))
@test crs(g) <: Mercator{WGS84Latest}
g = Box(merc(0, 0), merc(1, 1))
@test crs(g) <: Mercator{WGS84Latest}
g = Ball(merc(0, 0), T(1))
Expand Down
12 changes: 12 additions & 0 deletions test/discretization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,13 @@ end
@test eltype(mesh) <: Segment
@test nvertices.(mesh) [2]

curve = ParametrizedCurve(t -> cart(cos(t), sin(t)), (T(0), T(2π)))
mesh = discretize(curve, RegularDiscretization(10))
@test nvertices(mesh) == 11
@test nelements(mesh) == 10
@test eltype(mesh) <: Segment
@test nvertices.(mesh) [2]

box = Box(cart(0, 0), cart(2, 2))
mesh = discretize(box, RegularDiscretization(10))
@test mesh isa CartesianGrid
Expand Down Expand Up @@ -570,6 +577,11 @@ end
@test eltype(msh) <: Segment
@test nvertices(msh) == nelements(msh) + 1

curve = ParametrizedCurve(t -> cart(cos(t), sin(t)), (T(0), T(2π)))
msh = simplexify(curve)
@test eltype(msh) <: Segment
@test nvertices(msh) == nelements(msh) + 1

box = Box(cart(0, 0), cart(1, 1))
ngon = Quadrangle(cart(0, 0), cart(1, 0), cart(1, 1), cart(0, 1))
poly = readpoly(T, joinpath(datadir, "taubin.line"))
Expand Down
1 change: 1 addition & 0 deletions test/predicates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ end
@test isparametrized(Disk)
@test isparametrized(Circle)
@test isparametrized(BezierCurve)
@test isparametrized(ParametrizedCurve)
@test isparametrized(Cylinder)
@test isparametrized(CylinderSurface)
@test isparametrized(ConeSurface)
Expand Down
30 changes: 30 additions & 0 deletions test/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,36 @@ end
isapproxtest(f)
end

@testitem "ParametrizedCurve" setup = [Setup] begin
fun(t) = Point(Polar(T(1), T(t)))
c = ParametrizedCurve(fun, (T(0), T(2π)))
@test embeddim(c) == 2
@test paramdim(c) == 1
@test crs(c) <: Polar{NoDatum}
@test Meshes.lentype(c) ==

equaltest(c)

@test c(T(0)) == fun(T(0))
@test c(T(1)) == fun(T(2π))
@test c(T(0.5)) == fun(T(π))
@test_throws DomainError(T(-0.1), "c(t) is not defined for t outside [0, 1].") c(T(-0.1))
@test_throws DomainError(T(1.2), "c(t) is not defined for t outside [0, 1].") c(T(1.2))

@test boundary(c) === nothing

c = ParametrizedCurve(t -> cart(cospi(t), sinpi(t)), (T(0), T(1)))
@test boundary(c) == Multi([cart(1, 0), cart(-1, 0)])
@test perimeter(c) == zero(ℳ)

# CRS propagation
foo(t) = merc(t, 2t)
c = ParametrizedCurve(foo, (T(0), T(1)))
@test crs(c(T(0))) === crs(c)

@test sprint(show, c) == "ParametrizedCurve(fun: foo, range: (0.0, 1.0))"
end

@testitem "Torus" setup = [Setup] begin
t = Torus(T.((1, 1, 1)), T.((1, 0, 0)), 2, 1)
@test cart(1, 1, -1) t
Expand Down
7 changes: 7 additions & 0 deletions test/sampling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ end
@test p t
end

c = ParametrizedCurve(t -> cart(cos(t), sin(t)), (T(0), T(2π)))
ps = sample(c, RegularSampling(4))
ts = cart.([(1.0, 0.0), (-0.5, 0.8660254037844387), (-0.5, -0.8660254037844385), (1.0, 0.0)])
for (p, t) in zip(ps, ts)
@test p t
end

s = Sphere(cart(0, 0), T(2))
ps = sample(s, RegularSampling(4))
ts = cart.([(2, 0), (0, 2), (-2, 0), (0, -2)])
Expand Down

0 comments on commit fe86b2e

Please sign in to comment.