diff --git a/README.md b/README.md
index 33bc6c5fa..4da957aee 100644
--- a/README.md
+++ b/README.md
@@ -38,16 +38,16 @@ If you have any thoughts, please comment in:
* [JuliaPackageComparisons](https://juliapackagecomparisons.github.io/pages/bspline/)
## Installation
-Install this package
+Install this package via Julia REPL's package mode.
-```julia
+```
]add BasicBSpline
```
## Quick start
### B-spline basis function
-The value of B-spline basis function $B_{(i,p,k)}$ can be obtained with `bsplinebasis₊₀`. ([example in Desmos](https://www.desmos.com/calculator/ql6jqgdabs))
+The value of B-spline basis function $B_{(i,p,k)}$ can be obtained with `bsplinebasis₊₀`.
$$
\begin{aligned}
@@ -64,6 +64,19 @@ $$
\end{aligned}
$$
+```julia
+julia> using BasicBSpline
+
+julia> P3 = BSplineSpace{3}(KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0]))
+BSplineSpace{3, Float64, KnotVector{Float64}}(KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0]))
+
+julia> bsplinebasis₊₀(P3, 2, 7.5)
+0.13786213786213783
+```
+
+BasicBSpline.jl has many recipes based on [RecipesBase.jl](https://docs.juliaplots.org/dev/RecipesBase/), and `BSplineSpace` object can be visualized with its basis functions.
+([Try B-spline basis functions in Desmos](https://www.desmos.com/calculator/ql6jqgdabs))
+
```julia
using BasicBSpline
using Plots
@@ -73,15 +86,16 @@ P0 = BSplineSpace{0}(k) # 0th degree piecewise polynomial space
P1 = BSplineSpace{1}(k) # 1st degree piecewise polynomial space
P2 = BSplineSpace{2}(k) # 2nd degree piecewise polynomial space
P3 = BSplineSpace{3}(k) # 3rd degree piecewise polynomial space
+
+gr()
plot(
- plot([t->bsplinebasis₊₀(P0,i,t) for i in 1:dim(P0)], 0, 10, ylims=(0,1), legend=false),
- plot([t->bsplinebasis₊₀(P1,i,t) for i in 1:dim(P1)], 0, 10, ylims=(0,1), legend=false),
- plot([t->bsplinebasis₊₀(P2,i,t) for i in 1:dim(P2)], 0, 10, ylims=(0,1), legend=false),
- plot([t->bsplinebasis₊₀(P3,i,t) for i in 1:dim(P3)], 0, 10, ylims=(0,1), legend=false),
+ plot(P0; ylims=(0,1), label="P0"),
+ plot(P1; ylims=(0,1), label="P1"),
+ plot(P2; ylims=(0,1), label="P2"),
+ plot(P3; ylims=(0,1), label="P3"),
layout=(2,2),
)
```
-
![](docs/src/img/cover.png)
You can visualize the differentiability of B-spline basis function. See [Differentiability and knot duplications](https://hyrodium.github.io/BasicBSpline.jl/dev/math/bsplinebasis/#Differentiability-and-knot-duplications) for details.
@@ -91,45 +105,78 @@ https://github.com/hyrodium/BasicBSpline.jl/assets/7488140/034cf6d0-62ea-44e0-a0
### B-spline manifold
```julia
using BasicBSpline
-using BasicBSplineExporter
using StaticArrays
+using Plots
+## 1-dim B-spline manifold
p = 2 # degree of polynomial
-k1 = KnotVector(1:8) # knot vector
-k2 = KnotVector(rand(7))+(p+1)*KnotVector([1])
-P1 = BSplineSpace{p}(k1) # B-spline space
-P2 = BSplineSpace{p}(k2)
-n1 = dim(P1) # dimension of B-spline space
-n2 = dim(P2)
-a = [SVector(2i-6.5+rand(),1.5j-6.5+rand()) for i in 1:dim(P1), j in 1:dim(P2)] # random generated control points
-M = BSplineManifold(a,(P1,P2)) # Define B-spline manifold
-save_png("2dim.png", M) # save image
+k = KnotVector(1:12) # knot vector
+P = BSplineSpace{p}(k) # B-spline space
+a = [SVector(i-5, 3*sin(i^2)) for i in 1:dim(P)] # control points
+M = BSplineManifold(a, P) # Define B-spline manifold
+gr(); plot(M)
```
-![](docs/src/img/2dim.png)
+![](docs/src/img/bspline_curve.png)
+
+### Rational B-spline manifold (NURBS)
+
+```julia
+using BasicBSpline
+using LinearAlgebra
+using StaticArrays
+using Plots
+plotly()
+
+R1 = 3 # major radius of torus
+R2 = 1 # minor radius of torus
+
+p = 2
+k = KnotVector([0,0,0,1,1,2,2,3,3,4,4,4])
+P = BSplineSpace{p}(k)
+a = [normalize(SVector(cosd(t), sind(t)), Inf) for t in 0:45:360]
+w = [ifelse(isodd(i), √2, 1) for i in 1:9]
+
+a0 = push.(a, 0)
+a1 = (R1+R2)*a0
+a5 = (R1-R2)*a0
+a2 = [p+R2*SVector(0,0,1) for p in a1]
+a3 = [p+R2*SVector(0,0,1) for p in R1*a0]
+a4 = [p+R2*SVector(0,0,1) for p in a5]
+a6 = [p-R2*SVector(0,0,1) for p in a5]
+a7 = [p-R2*SVector(0,0,1) for p in R1*a0]
+a8 = [p-R2*SVector(0,0,1) for p in a1]
+
+M = RationalBSplineManifold(hcat(a1,a2,a3,a4,a5,a6,a7,a8,a1), w*w', P, P)
+plot(M; controlpoints=(markersize=2,))
+```
+![](docs/src/img/rational_bspline_surface_plotly.png)
### Refinement
#### h-refinement
```julia
-k₊=(KnotVector([3.3,4.2]),KnotVector([0.3,0.5])) # additional knot vectors
+k₊ = (KnotVector([3.1, 3.2, 3.3]), KnotVector([0.5, 0.8, 0.9])) # additional knot vectors
M_h = refinement(M, k₊) # refinement of B-spline manifold
-save_png("2dim_h-refinement.png", M_h) # save image
+plot(M_h; controlpoints=(markersize=2,))
```
-![](docs/src/img/2dim_h-refinement.png)
+![](docs/src/img/rational_bspline_surface_href_plotly.png)
Note that this shape and the last shape are equivalent.
#### p-refinement
```julia
-p₊=(Val(1),Val(2)) # additional degrees
+p₊ = (Val(1), Val(2)) # additional degrees
M_p = refinement(M, p₊) # refinement of B-spline manifold
-save_png("2dim_p-refinement.png", M_p) # save image
+plot(M_p; controlpoints=(markersize=2,))
```
-![](docs/src/img/2dim_p-refinement.png)
+![](docs/src/img/rational_bspline_surface_pref_plotly.png)
Note that this shape and the last shape are equivalent.
### Fitting B-spline manifold
-[Try on Desmos graphing calculator!](https://www.desmos.com/calculator/2hm3b1fbdf)
+The next example shows the fitting for [the following graph on Desmos graphing calculator](https://www.desmos.com/calculator/2hm3b1fbdf)!
+
+![](docs/src/img/fitting_desmos.png)
+
```julia
using BasicBSplineFitting
@@ -144,9 +191,9 @@ f(u1, u2) = SVector(2u1 + sin(u1) + cos(u2) + u2 / 2, 3u2 + sin(u2) + sin(u1) /
a = fittingcontrolpoints(f, (P1, P2))
M = BSplineManifold(a, (P1, P2))
-save_png("fitting.png", M, unitlength=50, xlims=(-10,10), ylims=(-10,10))
+gr()
+plot(M; aspectratio=1)
```
-![](docs/src/img/fitting_desmos.png)
![](docs/src/img/fitting.png)
If the knot vector span is too coarse, the approximation will be coarse.
@@ -162,22 +209,25 @@ f(u1, u2) = SVector(2u1 + sin(u1) + cos(u2) + u2 / 2, 3u2 + sin(u2) + sin(u1) /
a = fittingcontrolpoints(f, (P1, P2))
M = BSplineManifold(a, (P1, P2))
-save_png("fitting_coarse.png", M, unitlength=50, xlims=(-10,10), ylims=(-10,10))
+plot(M; aspectratio=1)
```
![](docs/src/img/fitting_coarse.png)
### Draw smooth vector graphics
```julia
+using BasicBSpline
+using BasicBSplineFitting
+using BasicBSplineExporter
p = 3
-k = KnotVector(range(-2π,2π,length=8))+p*KnotVector(-2π,2π)
+k = KnotVector(range(-2π,2π,length=8))+p*KnotVector([-2π,2π])
P = BSplineSpace{p}(k)
f(u) = SVector(u,sin(u))
a = fittingcontrolpoints(f, P)
M = BSplineManifold(a, P)
-save_svg("sine-curve.svg", M, unitlength=50, xlims=(-2,2), ylims=(-8,8))
-save_svg("sine-curve_no-points.svg", M, unitlength=50, xlims=(-2,2), ylims=(-8,8), points=false)
+save_svg("sine-curve.svg", M, unitlength=50, xlims=(-8,8), ylims=(-2,2))
+save_svg("sine-curve_no-points.svg", M, unitlength=50, xlims=(-8,8), ylims=(-2,2), points=false)
```
![](docs/src/img/sine-curve.svg)
![](docs/src/img/sine-curve_no-points.svg)
diff --git a/docs/make.jl b/docs/make.jl
index 4f7536a81..8aabd7d80 100644
--- a/docs/make.jl
+++ b/docs/make.jl
@@ -23,10 +23,16 @@ function generate_indexmd_from_readmemd()
# generate text for index.md
text_index = text_readme
- text_index = replace(text_index, "![](docs/src/img" => "![](img")
text_index = replace(text_index, r"\$\$((.|\n)*?)\$\$" => s"```math\1```")
text_index = replace(text_index, "(https://hyrodium.github.io/BasicBSpline.jl/dev/math/bsplinebasis/#Differentiability-and-knot-duplications)" => "(@ref differentiability-and-knot-duplications)")
text_index = replace(text_index, r"https://github.com/hyrodium/BasicBSpline\.jl/assets/.*" => "![](math/differentiability.mp4)")
+ text_index = replace(text_index, "```julia\njulia>" => "```julia-repl\njulia>")
+ text_index = replace(text_index, "```julia\n" => "```@example readme\n")
+ text_index = replace(text_index, r"```\n!\[\]\(docs/src/img/(.*?)plotly\.png\)" => s"savefig(\"readme-\1plotly.html\") # hide\nnothing # hide\n```\n```@raw html\n\n```")
+ text_index = replace(text_index, r"```\n!\[\]\(docs/src/img/(.*?)\.png\)" => s"savefig(\"readme-\1.png\") # hide\nnothing # hide\n```\n![](readme-\1.png)")
+ text_index = replace(text_index, "![](docs/src/img" => "![](img")
+ text_index = replace(text_index, "![](img/sine-curve.svg)" => "![](sine-curve.svg)")
+ text_index = replace(text_index, "![](img/sine-curve_no-points.svg)" => "![](sine-curve_no-points.svg)")
text_index = """
```@meta
EditURL = "https://github.com/hyrodium/BasicBSpline.jl/blob/main/README.md"
diff --git a/docs/src/api.md b/docs/src/api.md
index 5e65c8806..0f6761878 100644
--- a/docs/src/api.md
+++ b/docs/src/api.md
@@ -1,57 +1,13 @@
# API
-# Public
-```@docs
-KnotVector
-UniformKnotVector
-SubKnotVector
-EmptyKnotVector
-AbstractKnotVector
-length(k::AbstractKnotVector)
-Base.:+(k1::KnotVector{T}, k2::KnotVector{T}) where T
-*(m::Integer, k::AbstractKnotVector)
-Base.issubset(k::KnotVector, k′::KnotVector)
-unique(k::AbstractKnotVector)
-countknots(k::AbstractKnotVector, t::Real)
-@knotvector_str
-bsplinebasis₊₀
-bsplinebasis₋₀
-bsplinebasis
-BasicBSpline.bsplinebasis₋₀I
-intervalindex
-bsplinebasisall
-bsplinesupport
-dim
-exactdim_R(P::BSplineSpace)
-exactdim_I(P::BSplineSpace)
-BSplineSpace
-isnondegenerate
-isdegenerate(P::BSplineSpace)
-BSplineManifold
-unbounded_mapping
-RationalBSplineManifold
-fittingcontrolpoints
+## BasicBSpline.jl
+```@autodocs
+Modules = [BasicBSpline]
+Order = [:type, :function, :macro]
```
-```@docs
-BasicBSpline.refinement_R
-BasicBSpline.refinement_I
-```
-
-```@docs
-BasicBSplineFitting.innerproduct_R
-BasicBSplineFitting.innerproduct_I
-```
-
-## Private
-Note that the following methods are considered private methods, and changes in their behavior are not considered breaking changes.
-
-```@docs
-BasicBSpline.r_nomial
-BasicBSpline._vec
-BasicBSpline._lower_R
-BasicBSpline._changebasis_R
-BasicBSpline._changebasis_I
-BasicBSpline.__changebasis_I
-BasicBSpline._changebasis_sim
+## BasicBSplineFitting.jl
+```@autodocs
+Modules = [BasicBSplineFitting]
+Order = [:type, :function, :macro]
```
diff --git a/docs/src/img/2dim.png b/docs/src/img/2dim.png
deleted file mode 100644
index 1fcd4863c..000000000
Binary files a/docs/src/img/2dim.png and /dev/null differ
diff --git a/docs/src/img/2dim_h-refinement.png b/docs/src/img/2dim_h-refinement.png
deleted file mode 100644
index c844b44f3..000000000
Binary files a/docs/src/img/2dim_h-refinement.png and /dev/null differ
diff --git a/docs/src/img/2dim_p-refinement.png b/docs/src/img/2dim_p-refinement.png
deleted file mode 100644
index 6b4a17e77..000000000
Binary files a/docs/src/img/2dim_p-refinement.png and /dev/null differ
diff --git a/docs/src/img/bspline_curve.png b/docs/src/img/bspline_curve.png
new file mode 100644
index 000000000..45c8bbd1d
Binary files /dev/null and b/docs/src/img/bspline_curve.png differ
diff --git a/docs/src/img/cover.png b/docs/src/img/cover.png
index 333e9ee39..9abe7773d 100644
Binary files a/docs/src/img/cover.png and b/docs/src/img/cover.png differ
diff --git a/docs/src/img/fitting.png b/docs/src/img/fitting.png
index 03fe12036..3192cba33 100644
Binary files a/docs/src/img/fitting.png and b/docs/src/img/fitting.png differ
diff --git a/docs/src/img/fitting_coarse.png b/docs/src/img/fitting_coarse.png
index 8cc7dc518..5a6c3a6a9 100644
Binary files a/docs/src/img/fitting_coarse.png and b/docs/src/img/fitting_coarse.png differ
diff --git a/docs/src/img/rational_bspline_surface_href_plotly.png b/docs/src/img/rational_bspline_surface_href_plotly.png
new file mode 100644
index 000000000..f0bee0dde
Binary files /dev/null and b/docs/src/img/rational_bspline_surface_href_plotly.png differ
diff --git a/docs/src/img/rational_bspline_surface_plotly.png b/docs/src/img/rational_bspline_surface_plotly.png
new file mode 100644
index 000000000..1a9546dbf
Binary files /dev/null and b/docs/src/img/rational_bspline_surface_plotly.png differ
diff --git a/docs/src/img/rational_bspline_surface_pref_plotly.png b/docs/src/img/rational_bspline_surface_pref_plotly.png
new file mode 100644
index 000000000..665838b4b
Binary files /dev/null and b/docs/src/img/rational_bspline_surface_pref_plotly.png differ
diff --git a/docs/src/interpolations.md b/docs/src/interpolations.md
index 7a2320e54..d88518529 100644
--- a/docs/src/interpolations.md
+++ b/docs/src/interpolations.md
@@ -2,11 +2,13 @@
Currently, BasicBSpline.jl doesn't have APIs for interpolations, but it is not hard to implement some basic interpolation algorithms with this package.
-```@setup interpolation
+## Setup
+
+```@example interpolation
using BasicBSpline
using IntervalSets
using Random; Random.seed!(42)
-using Plots; plotly()
+using Plots
```
## Interpolation with cubic B-spline
@@ -40,6 +42,7 @@ fs = [1.3, 1.5, 2, 2.1, 1.9, 1.3]
f = interpolate(xs,fs)
# Plot
+plotly()
scatter(xs, fs)
plot!(t->f(t))
savefig("interpolation_cubic.html") # hide
diff --git a/docs/src/math/bsplinebasis.md b/docs/src/math/bsplinebasis.md
index 5c42d2c85..d3eef1579 100644
--- a/docs/src/math/bsplinebasis.md
+++ b/docs/src/math/bsplinebasis.md
@@ -5,7 +5,7 @@
```@example math_bsplinebasis
using BasicBSpline
using Random
-using Plots; gr()
+using Plots
```
## Basic properties of B-spline basis function
@@ -42,6 +42,7 @@ These B-spline basis functions can be calculated with [`bsplinebasis₊₀`](@re
p = 2
k = KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0])
P = BSplineSpace{p}(k)
+gr()
plot([t->bsplinebasis₊₀(P,i,t) for i in 1:dim(P)], 0, 10, ylims=(0,1), label=false)
savefig("bsplinebasisplot.png") # hide
nothing # hide
@@ -250,7 +251,7 @@ for p in 1:3
plot(P, legend=:topleft, label="B-spline basis (p=1)")
plot!(t->intervalindex(P,t),0,10, label="Interval index")
plot!(t->sum(bsplinebasis(P,i,t) for i in 1:dim(P)),0,10, label="Sum of B-spline basis")
- plot!(k, label="knot vector", legend=:inside)
+ plot!(k, label="knot vector")
plot!([t->bsplinebasisall(P,1,t)[i] for i in 1:p+1],0,10, color=:black, label="bsplinebasisall (i=1)", ylim=(-1,8-2p))
savefig("bsplinebasisall-$(p).html") # hide
nothing # hide
diff --git a/docs/src/math/bsplinemanifold.md b/docs/src/math/bsplinemanifold.md
index 11052ff55..8dead1a4b 100644
--- a/docs/src/math/bsplinemanifold.md
+++ b/docs/src/math/bsplinemanifold.md
@@ -5,7 +5,7 @@
using BasicBSpline
using StaticArrays
using StaticArrays
-using Plots; plotly()
+using Plots
```
## Multi-dimensional B-spline
@@ -36,6 +36,7 @@ i1 = 3
i2 = 4
# Visualize basis functions
+plotly()
plot(P1; plane=:xz, label="P1", color=:red)
plot!(P2; plane=:yz, label="P2", color=:green)
plot!(k1; plane=:xz, label="k1", color=:red, markersize=2)
diff --git a/docs/src/math/bsplinespace.md b/docs/src/math/bsplinespace.md
index 29b0673e9..c3a5d032c 100644
--- a/docs/src/math/bsplinespace.md
+++ b/docs/src/math/bsplinespace.md
@@ -4,9 +4,8 @@
```@example math_bsplinespace
using BasicBSpline
-using BasicBSplineExporter
using StaticArrays
-using Plots; gr()
+using Plots
```
## Defnition
@@ -84,6 +83,7 @@ dim(P3), exactdim_R(P3), exactdim_I(P3)
Visualization:
```@example math_bsplinespace
+gr()
pl1 = plot(P1); plot!(pl1, knotvector(P1))
pl2 = plot(P2); plot!(pl2, knotvector(P2))
pl3 = plot(P3); plot!(pl3, knotvector(P3))
diff --git a/docs/src/math/derivative.md b/docs/src/math/derivative.md
index 31f7ab3f7..8152fdaa8 100644
--- a/docs/src/math/derivative.md
+++ b/docs/src/math/derivative.md
@@ -1,10 +1,9 @@
# Derivative of B-spline
-```@setup math
+```@example math_derivative
using BasicBSpline
-using BasicBSplineExporter
using StaticArrays
-using Plots; plotly()
+using Plots
```
!!! info "Thm. Derivative of B-spline basis function"
@@ -18,9 +17,10 @@ using Plots; plotly()
```
Note that ``\dot{B}_{(i,p,k)}\in\mathcal{P}[p-1,k]``.
-```@example math
+```@example math_derivative
k = KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0])
P = BSplineSpace{3}(k)
+plotly()
plot(
plot(BSplineDerivativeSpace{0}(P), label="0th derivative", color=:black),
plot(BSplineDerivativeSpace{1}(P), label="1st derivative", color=:red),
@@ -34,23 +34,3 @@ nothing # hide
```@raw html
```
-
-```@docs
-BSplineDerivativeSpace
-```
-
-```@docs
-BasicBSpline.derivative
-```
-
-```@docs
-bsplinebasis′₊₀
-```
-
-```@docs
-bsplinebasis′₋₀
-```
-
-```@docs
-bsplinebasis′
-```
diff --git a/docs/src/math/inclusive.md b/docs/src/math/inclusive.md
index 39928ea09..10a458f0a 100644
--- a/docs/src/math/inclusive.md
+++ b/docs/src/math/inclusive.md
@@ -1,12 +1,15 @@
# Inclusive relation between B-spline spaces
-```@setup math
+## Setup
+
+```@example math_inclusive
using BasicBSpline
-using BasicBSplineExporter
using StaticArrays
-using Plots; plotly()
+using Plots
```
+## Theorem on [`issubset`](@ref)
+
!!! info "Thm. Inclusive relation between B-spline spaces"
For non-degenerate B-spline spaces, the following relationship holds.
```math
@@ -15,32 +18,81 @@ using Plots; plotly()
\Leftrightarrow (m=p'-p \ge 0 \ \text{and} \ k+m\widehat{k}\subseteq k')
```
-```@docs
-Base.issubset(P::BSplineSpace{p}, P′::BSplineSpace{p′}) where {p, p′}
+### Examples
+
+Here are plots of the B-spline basis functions of the spaces `P1`, `P2`, `P3`.
+
+```@example math_inclusive
+P1 = BSplineSpace{1}(KnotVector([1,3,6,6]))
+P2 = BSplineSpace{1}(KnotVector([1,3,5,6,6,8,9]))
+P3 = BSplineSpace{2}(KnotVector([1,1,3,3,6,6,6,8,9]))
+gr()
+plot(
+ plot(P1; ylims=(0,1), label="P1"),
+ plot(P2; ylims=(0,1), label="P2"),
+ plot(P3; ylims=(0,1), label="P3"),
+ layout=(3,1),
+ link=:x
+)
+savefig("inclusive-issubset.png") # hide
+nothing # hide
```
+![](inclusive-issubset.png)
+
+These spaces have the folllowing incusive relationships.
+
+```@repl math_inclusive
+P1 ⊆ P2
+P1 ⊆ P3
+P2 ⊆ P3, P3 ⊆ P2, P2 ⊆ P1, P3 ⊆ P1
+```
+
+## Definition on [`issqsubset`](@ref)
+
+!!! tip "Def. Inclusive relation between B-spline spaces"
+ For non-degenerate B-spline spaces, the following relationship holds.
+ ```math
+ \mathcal{P}[p,k]
+ \sqsubseteq\mathcal{P}[p',k']
+ \Leftrightarrow
+ \mathcal{P}[p,k]|_{[k_{p+1},k_{l-p}]}
+ \subseteq\mathcal{P}[p',k']|_{[k'_{p'+1},k'_{l'-p'}]}
+ ```
+
+### Examples
+
Here are plots of the B-spline basis functions of the spaces `P1`, `P2`, `P3`.
-```@repl math
-P1 = BSplineSpace{1}(KnotVector([1,3,5,8]))
-P2 = BSplineSpace{1}(KnotVector([1,3,5,6,8,9]))
-P3 = BSplineSpace{2}(KnotVector([1,1,3,3,5,5,8,8]))
+```@example math_inclusive
+P1 = BSplineSpace{1}(KnotVector([1,3,6,6])) # Save definition as above
+P4 = BSplineSpace{1}(KnotVector([1,3,5,6,8]))
+P5 = BSplineSpace{2}(KnotVector([1,1,3,3,6,6,7,9]))
+gr()
plot(
- plot([t->bsplinebasis₊₀(P1,i,t) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
- plot([t->bsplinebasis₊₀(P2,i,t) for i in 1:dim(P2)], 1, 9, ylims=(0,1), legend=false),
- plot([t->bsplinebasis₊₀(P3,i,t) for i in 1:dim(P3)], 1, 9, ylims=(0,1), legend=false),
+ plot(P1; ylims=(0,1), label="P1"),
+ plot(P4; ylims=(0,1), label="P4"),
+ plot(P5; ylims=(0,1), label="P5"),
layout=(3,1),
link=:x
)
-savefig("subbsplineplot.html") # hide
+savefig("inclusive-issqsubset.png") # hide
nothing # hide
```
-```@raw html
-
+![](inclusive-issqsubset.png)
+
+These spaces have the folllowing incusive relationships.
+
+```@repl math_inclusive
+P1 ⊑ P4
+P1 ⊑ P5
+P4 ⊑ P5, P5 ⊑ P4, P4 ⊑ P1, P5 ⊑ P1
```
-This means, there exists a ``n \times n'`` matrix ``A`` which holds:
+## Change basis with a matrix
+
+If ``\mathcal{P}[p,k] \subseteq \mathcal{P}[p',k']`` (or ``\mathcal{P}[p,k] \sqsubseteq \mathcal{P}[p',k']``), there exists a ``n \times n'`` matrix ``A`` which holds:
```math
\begin{aligned}
@@ -51,14 +103,14 @@ n'&=\dim(\mathcal{P}[p',k'])
\end{aligned}
```
-You can calculate the change of basis matrix ``A`` with `changebasis`.
+You can calculate the change of basis matrix ``A`` with [`changebasis`](@ref).
-```@repl math
+```@repl math_inclusive
A12 = changebasis(P1,P2)
A13 = changebasis(P1,P3)
```
-```@repl math
+```@example math_inclusive
plot(
plot([t->bsplinebasis₊₀(P1,i,t) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
plot([t->sum(A12[i,j]*bsplinebasis₊₀(P2,j,t) for j in 1:dim(P2)) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
@@ -66,34 +118,52 @@ plot(
layout=(3,1),
link=:x
)
-savefig("subbsplineplot2.html") # hide
+savefig("inclusive-issubset-matrix.png") # hide
nothing # hide
```
-```@raw html
-
-```
+![](inclusive-issubset-matrix.png)
-```@docs
-changebasis_R
+```@repl math_inclusive
+A14 = changebasis(P1,P4)
+A15 = changebasis(P1,P5)
```
-```@docs
-changebasis_I
+```@example math_inclusive
+plot(
+ plot([t->bsplinebasis₊₀(P1,i,t) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
+ plot([t->sum(A14[i,j]*bsplinebasis₊₀(P4,j,t) for j in 1:dim(P4)) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
+ plot([t->sum(A15[i,j]*bsplinebasis₊₀(P5,j,t) for j in 1:dim(P5)) for i in 1:dim(P1)], 1, 9, ylims=(0,1), legend=false),
+ layout=(3,1),
+ link=:x
+)
+savefig("inclusive-issqsubset-matrix.png") # hide
+nothing # hide
```
-```@docs
-issqsubset
-```
+![](inclusive-issqsubset-matrix.png)
-```@docs
-expandspace
-```
+* [`changebasis_R`](@ref)
+ * Calculate the matrix based on ``P \subseteq P'``
+* [`changebasis_I`](@ref)
+ * Calculate the matrix based on ``P \sqsubseteq P'``
+* [`changebasis`](@ref)
+ * Return `changebasis_R` if ``P \subseteq P'``, otherwise return `changebasis_I` if ``P \sqsubseteq P'``.
-```@docs
-expandspace_R
-```
+## Expand spaces with additional knots or polynomial degree
+
+There are some functions to expand spaces with additional knots or polynomial degree.
+
+* [`expandspace_R`](@ref)
+* [`expandspace_I`](@ref)
+* [`expandspace`](@ref)
-```@docs
-expandspace_I
+```@repl math_inclusive
+P = BSplineSpace{2}(knotvector"21 113")
+P_R = expandspace_R(P, Val(1), KnotVector([3.4, 4.2]))
+P_I = expandspace_I(P, Val(1), KnotVector([3.4, 4.2]))
+P ⊆ P_R
+P ⊆ P_I
+P ⊑ P_R
+P ⊑ P_I
```
diff --git a/docs/src/math/knotvector.md b/docs/src/math/knotvector.md
index d9e91c9e7..4d853b32e 100644
--- a/docs/src/math/knotvector.md
+++ b/docs/src/math/knotvector.md
@@ -3,8 +3,8 @@
## Setup
```@example math_knotvector
using BasicBSpline
+using Plots
using InteractiveUtils # hide
-using Plots; gr()
```
## Definition
@@ -44,8 +44,9 @@ A knot vector can be visualized with `Plots.plot`.
```@repl math_knotvector
k1 = KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0])
-plot(k1; label="k1")
k2 = knotvector"1231123"
+gr()
+plot(k1; label="k1")
plot!(k2; label="k2", offset=0.5, ylims=(-0.1,1), xticks=0:10)
savefig("knotvector.png") # hide
nothing # hide
diff --git a/docs/src/math/rationalbsplinemanifold.md b/docs/src/math/rationalbsplinemanifold.md
index 58968d911..e4c30a64f 100644
--- a/docs/src/math/rationalbsplinemanifold.md
+++ b/docs/src/math/rationalbsplinemanifold.md
@@ -6,7 +6,7 @@
using BasicBSpline
using StaticArrays
using LinearAlgebra
-using Plots; plotly()
+using Plots
```
[Non-uniform rational basis spline (NURBS)](https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline) is also supported in BasicBSpline.jl package.
@@ -52,6 +52,7 @@ M3 = BSplineManifold(a3.*w,(P))
R3 = RationalBSplineManifold(a3,w,(P,))
# Plot
+plotly()
pl2 = plot(R2, xlims=(-1,1), ylims=(-1,1); color=:blue, linewidth=3, aspectratio=1, label=false)
pl3 = plot(R3; color=:blue, linewidth=3, controlpoints=(markersize=2,), label="Rational B-spline curve")
plot!(pl3, M3; color=:red, linewidth=3, controlpoints=(markersize=2,), label="B-spline curve")
diff --git a/docs/src/math/refinement.md b/docs/src/math/refinement.md
index 4e3c29bd7..ef555e01a 100644
--- a/docs/src/math/refinement.md
+++ b/docs/src/math/refinement.md
@@ -1,52 +1,54 @@
# Refinement
-```@setup math
+## Setup
+
+```@example math_refinement
using BasicBSpline
using BasicBSplineExporter
using StaticArrays
-using Plots; plotly()
-```
-
-## Documentation
-
-```@docs
-refinement
+using Plots
```
## Example
### Define original manifold
-```@example math
+```@example math_refinement
p = 2 # degree of polynomial
k = KnotVector(1:8) # knot vector
P = BSplineSpace{p}(k) # B-spline space
rand_a = [SVector(rand(), rand()) for i in 1:dim(P), j in 1:dim(P)]
a = [SVector(2*i-6.5, 2*j-6.5) for i in 1:dim(P), j in 1:dim(P)] + rand_a # random
M = BSplineManifold(a,(P,P)) # Define B-spline manifold
+gr()
+plot(M)
+savefig("refinement_2dim_original.png") # hide
nothing # hide
```
+![](refinement_2dim_original.png)
+
### h-refinement
-Insert additional knots to knot vector.
+Insert additional knots to knot vector without changing the shape.
-```@repl math
-k₊ = (KnotVector([3.3,4.2]),KnotVector([3.8,3.2,5.3])) # additional knot vectors
+```@repl math_refinement
+k₊ = (KnotVector([3.3,4.2]), KnotVector([3.8,3.2,5.3])) # additional knot vectors
M_h = refinement(M, k₊) # refinement of B-spline manifold
-save_png("2dim_h-refinement.png", M_h) # save image
+plot(M_h)
+savefig("refinement_2dim_h.png") # hide
+nothing # hide
```
-![](2dim_h-refinement.png)
-
-Note that this shape and the last shape are equivalent.
+![](refinement_2dim_h.png)
### p-refinement
-Increase the polynomial degree of B-spline manifold.
+Increase the polynomial degree of B-spline manifold without changing the shape.
-```@repl math
+```@repl math_refinement
p₊ = (Val(1), Val(2)) # additional degrees
M_p = refinement(M, p₊) # refinement of B-spline manifold
-save_png("2dim_p-refinement.png", M_p) # save image
+plot(M_p)
+savefig("refinement_2dim_p.png") # hide
+nothing # hide
```
-![](2dim_p-refinement.png)
-Note that this shape and the last shape are equivalent.
+![](refinement_2dim_p.png)
diff --git a/docs/update_images_in_readme.jl b/docs/update_images_in_readme.jl
new file mode 100644
index 000000000..d6b501fb6
--- /dev/null
+++ b/docs/update_images_in_readme.jl
@@ -0,0 +1,20 @@
+# Run this script after running make.jl
+
+dir_build = joinpath(@__DIR__, "build")
+dir_img = joinpath(@__DIR__, "src", "img")
+
+for filename in readdir(dir_build)
+ path_src = joinpath(dir_build, filename)
+ if startswith(filename, "readme-") && endswith(filename, ".html")
+ println(path_src)
+ path_png = joinpath(dir_img, chopsuffix(chopprefix(filename, "readme-"), ".html") * ".png")
+ cmd = `google-chrome-stable --headless --disable-gpu --screenshot=$path_png $path_src`
+ run(cmd)
+ end
+
+ if startswith(filename, "readme-") && endswith(filename, ".png")
+ println(path_src)
+ path_png = joinpath(dir_img, chopprefix(filename, "readme-"))
+ cp(path_src, path_png; force=true)
+ end
+end
diff --git a/src/_ChangeBasis.jl b/src/_ChangeBasis.jl
index dce046d90..e2d3a43c3 100644
--- a/src/_ChangeBasis.jl
+++ b/src/_ChangeBasis.jl
@@ -823,6 +823,12 @@ function _changebasis_R(P::BSplineSpace, dP′::BSplineDerivativeSpace{0})
return _changebasis_R(P, P′)
end
+@doc raw"""
+ changebasis(P::AbstractFunctionSpace, P′::AbstractFunctionSpace)
+
+Return `changebasis_R(P, P′)` if ``P ⊆ P′``, otherwise `changebasis_R(P, P′)` if ``P ⊑ P′``.
+Throw an error if ``P ⊈ P′`` and ``P ⋢ P′``.
+"""
function changebasis(P::AbstractFunctionSpace, P′::AbstractFunctionSpace)
P ⊆ P′ && return _changebasis_R(P, P′)
P ⊑ P′ && return _changebasis_I(P, P′)
diff --git a/src/_util.jl b/src/_util.jl
index 853fcd7ad..d6bb4c2fa 100644
--- a/src/_util.jl
+++ b/src/_util.jl
@@ -11,6 +11,7 @@ Calculate ``r``-nomial coefficient
r_nomial(n, k, r)
+**This function is considered as internal.**
```math
(1+x+\cdots+x^r)^n = \sum_{k} a_{n,k,r} x^k
```