Skip to content

Commit

Permalink
misc updates for release 4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
cormullion committed Apr 15, 2024
1 parent a5a4df5 commit e4fe3eb
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 110 deletions.
76 changes: 40 additions & 36 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53"
[compat]
Colors = "0.12"
Documenter = "1"
Images = "0.26"
Images = "0.26.1"
MathTeXEngine = "0.5.7"
10 changes: 5 additions & 5 deletions docs/src/howto/polygons.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ Luxor also provides a BezierPath type, which is an array of four-point tuples, e
|[`epitrochoid`](@ref) | | |[`ispolyconvex`](@ref) |[`polyclip`](@ref) |
|[`polyrotate!`](@ref) | | |[`ispointonpoly`](@ref) |[`polymove!`](@ref) |
|[`polyfit`](@ref) | | | |[`polyscale!`](@ref) |
|[`polyhull`](@ref) | | | | |
|[`polysuper`](@ref) | | | | |
| | | | |[`polyreflect!`](@ref) |
| | | | |[`polysample`](@ref) |
| | | | |[`polytriangulate`](@ref) |
|[`polyhull`](@ref) | | | |[`polyreflect!`](@ref) |
|[`polysuper`](@ref) | | | |[`polysample`](@ref) |
| [`polybspline`](@ref) | | | |[`polytriangulate`](@ref) |
| | | | |[`insertvertices!`](@ref) |
| | | | |[`polymorph`](@ref) |
| | | | | |
| | | | | |
| *paths* | | | | |
|[`storepath`](@ref) | | | | |
|[`getpath`](@ref) |[`pathtopoly`](@ref) |[`drawpath`](@ref) |[`pathlength`](@ref) |[`pathsample`](@ref) |
Expand Down
2 changes: 1 addition & 1 deletion src/Luxor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export Drawing,
noise, initnoise,

# experimental polygon functions
polyremovecollinearpoints, polytriangulate!,
polyremovecollinearpoints,
polytriangulate, ispointinsidetriangle, ispolyclockwise,
polyorientation, ispolyconvex, polymorph,

Expand Down
6 changes: 0 additions & 6 deletions src/deprecations.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
using Base: @deprecate

@deprecate intersection(pt1::Point, pt2::Point, pt3::Point, pt4::Point) intersectionlines(pt1::Point, pt2::Point, pt3::Point, pt4::Point)

@deprecate polytriangulate!(pt) polytriangulate(pt)

@deprecate rotate_point_around_point(targetpt, pt, angle) rotatepoint(targetpt, pt, angle)
28 changes: 24 additions & 4 deletions src/point.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ end

"""
isequal(p1::Point, p2::Point) =
isapprox(p1.x, p2.x, atol = 0.00000001) &&
(isapprox(p1.y, p2.y, atol = 0.00000001))
isapprox(p1.x, p2.x, atol = 0.00000001) &&
(isapprox(p1.y, p2.y, atol = 0.00000001))
Compare points.
"""
Expand Down Expand Up @@ -214,6 +214,26 @@ function between(couple::NTuple{2,Point}, x)
return p1 + (x * (p2 - p1))
end

# convenience functions for my own use :)
"""
between(p1::Point, p2::Point, r:range)
between(p1::Point, p2::Point, a:array)
Return an array of Points between point `p1` and point `p2` for
every `x` in range `r` or array `a`.
If `x` is 0.0, that point will be at `p1`; if `x` is 1.0, that point will be at `p2`.
When `x` is 0.5, that point is the midpoint between `p1` and `p2`.
"""
function between(pt1::Point, pt2::Point, r::AbstractRange)
[between(pt1, pt2, e) for e in r]
end

function between(pt1::Point, pt2::Point, a::AbstractArray)
[between(pt1, pt2, e) for e in a]
end

"""
perpendicular(p1::Point, p2::Point, p3::Point)
Expand Down Expand Up @@ -311,9 +331,9 @@ function ispointonline(pt::Point, pt1::Point, pt2::Point;

# point on the line
if (abs(dxl) >= abs(dyl))
return dxl > 0 ? pt1.x <= pt.x+atol && pt.x <= pt2.x+atol : pt2.x <= pt.x+atol && pt.x <= pt1.x+atol
return dxl > 0 ? pt1.x <= pt.x + atol && pt.x <= pt2.x + atol : pt2.x <= pt.x + atol && pt.x <= pt1.x + atol
else
return dyl > 0 ? pt1.y <= pt.y+atol && pt.y <= pt2.y+atol : pt2.y <= pt.y+atol && pt.y <= pt1.y+atol
return dyl > 0 ? pt1.y <= pt.y + atol && pt.y <= pt2.y + atol : pt2.y <= pt.y + atol && pt.y <= pt1.y + atol
end
end

Expand Down
111 changes: 55 additions & 56 deletions src/polygons.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# polygons, part of Luxor

"""
Draw a polygon.
poly(pointlist::Array{Point, 1}, action = :none;
close=false,
reversepath=false)
Create a path with the points in `pointlist` and apply `action`.
Draw a polygon. Create a path with the points in `pointlist` and apply `action`.
By default `poly()` doesn't close or fill the polygon.
"""
function poly(pointlist::Array{Point,1};
Expand Down Expand Up @@ -38,13 +36,12 @@ poly(pointlist::Array{Point,1}, a::Symbol;
close = false,
reversepath = false) = poly(pointlist, action = action, close = close, reversepath = reversepath)


"""
polysortbyangle(pointlist::Array, refpoint=minimum(pointlist))
Sort the points of a polygon into order. Points are sorted according to the angle they make
with a specified point.
polysortbyangle(pointlist::Array, refpoint=minimum(pointlist))
The `refpoint` can be chosen, but the default minimum point is usually OK too:
polysortbyangle(parray, polycentroid(parray))
Expand All @@ -59,11 +56,11 @@ function polysortbyangle(pointlist::Array{Point,1}, refpoint = minimum(pointlist
end

"""
polysortbydistance(p, starting::Point)
Sort a polygon by finding the nearest point to the starting point, then
the nearest point to that, and so on.
polysortbydistance(p, starting::Point)
You can end up with convex (self-intersecting) polygons, unfortunately.
"""
function polysortbydistance(pointlist::Array{Point,1}, starting::Point)
Expand All @@ -82,9 +79,9 @@ function polysortbydistance(pointlist::Array{Point,1}, starting::Point)
end

"""
Use a non-recursive Douglas-Peucker algorithm to simplify a polygon. Used by `simplify()`.
douglas_peucker(pointlist::Array, start_index, last_index, epsilon)
douglas_peucker(pointlist::Array, start_index, last_index, epsilon)
Use a non-recursive Douglas-Peucker algorithm to simplify a polygon. Used by `simplify()`.
"""
function douglas_peucker(pointlist::Array{Point,1}, start_index, last_index, epsilon)
temp_stack = Tuple{Int,Int}[]
Expand Down Expand Up @@ -117,10 +114,10 @@ function douglas_peucker(pointlist::Array{Point,1}, start_index, last_index, eps
end

"""
Simplify a polygon:
simplify(pointlist::Array, detail=0.1)
Simplify a polygon.
`detail` is the maximum approximation error of simplified polygon.
"""
function simplify(pointlist::Array{Point,1}, detail = 0.1)
Expand Down Expand Up @@ -380,7 +377,7 @@ function polysmooth(points::Array{Point,1}, radius, action::Symbol; debug = fals
# there are less than three points to smooth
return nothing
else
@inbounds for i in 1:(close ? l : l-2)
@inbounds for i in 1:(close ? l : l - 2)
p1 = points[mod1(i, l)]
p2 = points[mod1(i + 1, l)]
p3 = points[mod1(i + 2, l)]
Expand Down Expand Up @@ -622,7 +619,7 @@ end
# third method

"""
offsetpoly(plist, shape::Function)
offsetpoly(plist, shape::Function)
Return a closed polygon that is offset from and encloses an
polyline.
Expand Down Expand Up @@ -651,8 +648,8 @@ This example draws a tilde, with the ends starting at 20
the middle, as f(0.5) = 25.
```julia
f(x, θ) = 10 + 15sin(x * π)
sinecurve = [Point(50x, 50sin(x)) for x in -π:π/24:π]
f(x, θ) = 10 + 15sin(x * π)
sinecurve = [Point(50x, 50sin(x)) for x in (-π):(π / 24):π]
pgon = offsetpoly(sinecurve, f)
poly(pgon, :fill)
```
Expand All @@ -662,7 +659,7 @@ thins the horizontal parts.
```julia
g(x, θ) = rescale(abs(sin(θ)), 0, 1, 0.1, 30)
sinecurve = [Point(50x, 50sin(x)) for x in -π:π/24:π]
sinecurve = [Point(50x, 50sin(x)) for x in (-π):(π / 24):π]
pgon = offsetpoly(sinecurve, g)
poly(pgon, :fill)
```
Expand Down Expand Up @@ -781,34 +778,36 @@ end
Generate a B-spline curve from a given set of control points.
# Arguments
- `controlpoints::Array{Point,1}`: An array of control points that define the B-spline.
- `npoints=100`: The number of points to generate on the B-spline curve.
- `degree=3`: The degree of the B-spline. Default is 3.
- `clamped=true`: A boolean to indicate if the B-spline is clamped. Default is true.
- `controlpoints::Array{Point,1}`: An array of control points that define the B-spline.
- `npoints=100`: The number of points to generate on the B-spline curve.
- `degree=3`: The degree of the B-spline. Default is 3.
- `clamped=true`: A boolean to indicate if the B-spline is clamped. Default is true.
# Returns
- An array of points on the B-spline curve.
- An array of points on the B-spline curve.
"""
function polybspline(controlpoints::Array{Point,1}, npoints=30;degree=3, clamped=true)
function polybspline(controlpoints::Array{Point,1}, npoints = 30; degree = 3, clamped = true)
nCP::Int64 = length(controlpoints)
nCP == 0 && error("Error: controlpoints array cannot be empty.")
npoints <= 0 && error("Error: npoints must be greater than zero.")
degree <= 0 && error("Error: degree must be greater than zero.")
degree >= nCP && error("Error: degree cannot be greater than the number of control points.")
points = Array{Point,1}(undef, npoints)
T = Array{Float64,1}(undef, nCP+degree+1)
T = Array{Float64,1}(undef, nCP + degree + 1)
if clamped
T[1:degree] .= 0.
for i=degree+1:nCP+1
T[1:degree] .= 0.0
for i in (degree + 1):(nCP + 1)
T[i] = (i - degree - 1) / (nCP - degree)
end
T[nCP+2:end] .= 1.
T[(nCP + 2):end] .= 1.0
else
for i=1:nCP+degree+1
for i in 1:(nCP + degree + 1)
T[i] = (i - 1) / (nCP + degree)
end
end

"""De Boor's algorithm for B-spline evaluation.
from https://en.wikipedia.org/wiki/De_Boor%27s_algorithm
Arguments
Expand All @@ -819,33 +818,33 @@ function polybspline(controlpoints::Array{Point,1}, npoints=30;degree=3, clamped
c: Array of control points.
p: Degree of B-spline.
"""
function deBoor(k::Int64,x::Float64,t::Array{Float64,1},c::Array{Point,1},p::Int64)::Point
d = Array{Point,1}(undef, p+1)
for j=1:p+1
d[j] = c[j+k-p]
function deBoor(k::Int64, x::Float64, t::Array{Float64,1}, c::Array{Point,1}, p::Int64)::Point
d = Array{Point,1}(undef, p + 1)
for j in 1:(p + 1)
d[j] = c[j + k - p]
end
@inbounds for r=1:p
for j=p+1:-1:r+1
alpha=(x-t[j+k-p])/(t[j+1+k-r] - t[j+k-p])
d[j]=(1-alpha)*d[j-1]+alpha*d[j]
@inbounds for r in 1:p
for j in (p + 1):-1:(r + 1)
alpha = (x - t[j + k - p]) / (t[j + 1 + k - r] - t[j + k - p])
d[j] = (1 - alpha) * d[j - 1] + alpha * d[j]
end
end
return d[p+1]
return d[p + 1]
end

@inbounds for i=0:npoints-1
t=i/(npoints-1)
@inbounds for i in 0:(npoints - 1)
t = i / (npoints - 1)
if !clamped
t =t*(T[nCP+1]-T[degree+1])+T[degree+1]
t = t * (T[nCP + 1] - T[degree + 1]) + T[degree + 1]
end
k=1 #index of knot interval
k = 1 #index of knot interval
while k < nCP
if t<T[k+1]
if t < T[k + 1]
break
end
k += 1
end
points[i+1]=deBoor(k-1,t,T,controlpoints,degree)
points[i + 1] = deBoor(k - 1, t, T, controlpoints, degree)
end
return points
end
Expand Down Expand Up @@ -928,7 +927,7 @@ than `value`, and the difference value. Array is assumed to be sorted.
(Designed for use with `polydistances()`).
"""
function nearestindex(a::Array{Float64, 1}, val)
function nearestindex(a::Array{Float64,1}, val)
ind = findlast(v -> (v < val), a)
if isnothing(ind)
throw(error("nearestindex: no index"))
Expand Down Expand Up @@ -963,9 +962,9 @@ using `polydistances(p, closed=closed)`.
Use the complementary `polyremainder()` function to return
the other part.
"""
function polyportion(p::Array{Point,1}, portion = 0.5;
closed = true,
pdist = Array{Float64, 1}[])
function polyportion(p::Array{Point,1}, portion = 0.5;
closed = true,
pdist = Array{Float64,1}[])
# portion is 0 to 1
if isempty(pdist)
pdist = polydistances(p, closed = closed)
Expand Down Expand Up @@ -1017,9 +1016,9 @@ calculated afresh, using `polydistances(p, closed=closed)`.
Use the complementary `polyportion()` function to return the other part.
"""
function polyremainder(p::Array{Point,1}, portion = 0.5;
closed = true,
pdist = Array{Union{Float64, Int}, 1}[])
function polyremainder(p::Array{Point,1}, portion = 0.5;
closed = true,
pdist = Array{Union{Float64,Int},1}[])
# portion is 0 to 1
if isempty(pdist)
pdist = polydistances(p, closed = closed)
Expand Down Expand Up @@ -1277,7 +1276,7 @@ Scale (permanently) a polygon by `sh` horizontally and `sv` vertically,
relative to `center`.
"""
function polyscale!(pgon, sh, sv;
center = O)
center = O)
return pgon .= (pgon .- center) .* Ref((sh, sv))
end

Expand Down Expand Up @@ -1654,10 +1653,10 @@ end
```
"""
function polymorph(pgon1::Array{Array{Point,1}}, pgon2::Array{Array{Point,1}}, k;
samples = 100,
easingfunction = easingflat,
kludge = true,
closed = true)
samples = 100,
easingfunction = easingflat,
kludge = true,
closed = true)
isapprox(k, 0.0) && return pgon1
isapprox(k, 1.0) && return pgon2
loopcount1 = length(pgon1)
Expand Down
3 changes: 2 additions & 1 deletion test/polybspline-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ function test_polybspline()
@test all(min_x <= p.x <= max_x && min_y <= p.y <= max_y for p in resultUnClamped)
end

test_polybspline()
test_polybspline()
println("...finished polybpline() test")

0 comments on commit e4fe3eb

Please sign in to comment.