项目作者: hyrodium

项目描述 :
Basic operations for B-spline functions and related things with julia
高级语言: Julia
项目地址: git://github.com/hyrodium/BasicBSpline.jl.git
创建时间: 2020-04-25T14:09:17Z
项目社区:https://github.com/hyrodium/BasicBSpline.jl

开源协议:MIT License

下载


BasicBSpline.jl

Basic (mathematical) operations for B-spline functions and related things with Julia.

Stable
Dev
Build Status
Coverage
Aqua QA
DOI
BasicBSpline Downloads

Summary

This package provides basic mathematical operations for B-spline.

  • B-spline basis function
  • Some operations for knot vector
  • Some operations for B-spline space (piecewise polynomial space)
  • B-spline manifold (includes curve, surface and solid)
  • Refinement algorithm for B-spline manifold
  • Fitting control points for a given function

Comparison to other B-spline packages

There are several Julia packages for B-spline, and this package distinguishes itself with the following key benefits:

  • Supports all degrees of polynomials.
  • Includes a refinement algorithm for B-spline manifolds.
  • Delivers high-speed performance.
  • Is mathematically oriented.
  • Provides a fitting algorithm using least squares. (via BasicBSplineFitting.jl)
  • Offers exact SVG export feature. (via BasicBSplineExporter.jl)

If you have any thoughts, please comment in:

Installation

Install this package via Julia REPL’s package mode.

  1. ]add BasicBSpline

Quick start

B-spline basis function

The value of B-spline basis function $B_{(i,p,k)}$ can be obtained with bsplinebasis₊₀.


\begin{aligned}
{B}{(i,p,k)}(t)
&=
\frac{t-k
{i}}{k{i+p}-k{i}}{B}{(i,p-1,k)}(t)
+\frac{k
{i+p+1}-t}{k{i+p+1}-k{i+1}}{B}{(i+1,p-1,k)}(t) \
{B}
{(i,0,k)}(t)
&=
\begin{cases}
&1\quad (k{i}\le t< k{i+1})\
&0\quad (\text{otherwise})
\end{cases}
\end{aligned}

  1. julia> using BasicBSpline
  2. julia> P3 = BSplineSpace{3}(KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0]))
  3. BSplineSpace{3, Float64, KnotVector{Float64}}(KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0]))
  4. julia> bsplinebasis₊₀(P3, 2, 7.5)
  5. 0.13786213786213783

BasicBSpline.jl has many recipes based on RecipesBase.jl, and BSplineSpace object can be visualized with its basis functions.
(Try B-spline basis functions in Desmos)

  1. using BasicBSpline
  2. using Plots
  3. k = KnotVector([0.0, 1.5, 2.5, 5.5, 8.0, 9.0, 9.5, 10.0])
  4. P0 = BSplineSpace{0}(k) # 0th degree piecewise polynomial space
  5. P1 = BSplineSpace{1}(k) # 1st degree piecewise polynomial space
  6. P2 = BSplineSpace{2}(k) # 2nd degree piecewise polynomial space
  7. P3 = BSplineSpace{3}(k) # 3rd degree piecewise polynomial space
  8. gr()
  9. plot(
  10. plot(P0; ylims=(0,1), label="P0"),
  11. plot(P1; ylims=(0,1), label="P1"),
  12. plot(P2; ylims=(0,1), label="P2"),
  13. plot(P3; ylims=(0,1), label="P3"),
  14. layout=(2,2),
  15. )

You can visualize the differentiability of B-spline basis function. See Differentiability and knot duplications for details.

https://github.com/hyrodium/BasicBSpline.jl/assets/7488140/034cf6d0-62ea-44e0-a00f-d307e6aad0fe

B-spline manifold

  1. using BasicBSpline
  2. using StaticArrays
  3. using Plots
  4. ## 1-dim B-spline manifold
  5. p = 2 # degree of polynomial
  6. k = KnotVector(1:12) # knot vector
  7. P = BSplineSpace{p}(k) # B-spline space
  8. a = [SVector(i-5, 3*sin(i^2)) for i in 1:dim(P)] # control points
  9. M = BSplineManifold(a, P) # Define B-spline manifold
  10. gr(); plot(M)

Rational B-spline manifold (NURBS)

  1. using BasicBSpline
  2. using LinearAlgebra
  3. using StaticArrays
  4. using Plots
  5. plotly()
  6. R1 = 3 # major radius of torus
  7. R2 = 1 # minor radius of torus
  8. p = 2
  9. k = KnotVector([0,0,0,1,1,2,2,3,3,4,4,4])
  10. P = BSplineSpace{p}(k)
  11. a = [normalize(SVector(cosd(t), sind(t)), Inf) for t in 0:45:360]
  12. w = [ifelse(isodd(i), 2, 1) for i in 1:9]
  13. a0 = push.(a, 0)
  14. a1 = (R1+R2)*a0
  15. a5 = (R1-R2)*a0
  16. a2 = [p+R2*SVector(0,0,1) for p in a1]
  17. a3 = [p+R2*SVector(0,0,1) for p in R1*a0]
  18. a4 = [p+R2*SVector(0,0,1) for p in a5]
  19. a6 = [p-R2*SVector(0,0,1) for p in a5]
  20. a7 = [p-R2*SVector(0,0,1) for p in R1*a0]
  21. a8 = [p-R2*SVector(0,0,1) for p in a1]
  22. M = RationalBSplineManifold(hcat(a1,a2,a3,a4,a5,a6,a7,a8,a1), w*w', P, P)
  23. plot(M; controlpoints=(markersize=2,))

Refinement

h-refinement (knot insertion)

Insert additional knots to knot vectors without changing the shape.

  1. k = (KnotVector([3.1, 3.2, 3.3]), KnotVector([0.5, 0.8, 0.9])) # additional knot vectors
  2. M_h = refinement(M, k₊) # refinement of B-spline manifold
  3. plot(M_h; controlpoints=(markersize=2,))

p-refinement (degree elevation)

Increase the polynomial degrees of B-spline manifold without changing the shape.

  1. p = (Val(1), Val(2)) # additional degrees
  2. M_p = refinement(M, p₊) # refinement of B-spline manifold
  3. plot(M_p; controlpoints=(markersize=2,))

Fitting B-spline manifold

The next example shows the fitting for the following graph on Desmos graphing calculator!

  1. using BasicBSplineFitting
  2. p1 = 2
  3. p2 = 2
  4. k1 = KnotVector(-10:10)+p1*KnotVector([-10,10])
  5. k2 = KnotVector(-10:10)+p2*KnotVector([-10,10])
  6. P1 = BSplineSpace{p1}(k1)
  7. P2 = BSplineSpace{p2}(k2)
  8. f(u1, u2) = SVector(2u1 + sin(u1) + cos(u2) + u2 / 2, 3u2 + sin(u2) + sin(u1) / 2 + u1^2 / 6) / 5
  9. a = fittingcontrolpoints(f, (P1, P2))
  10. M = BSplineManifold(a, (P1, P2))
  11. gr()
  12. plot(M; aspectratio=1)

If the knot vector span is too coarse, the approximation will be coarse.

  1. p1 = 2
  2. p2 = 2
  3. k1 = KnotVector(-10:5:10)+p1*KnotVector([-10,10])
  4. k2 = KnotVector(-10:5:10)+p2*KnotVector([-10,10])
  5. P1 = BSplineSpace{p1}(k1)
  6. P2 = BSplineSpace{p2}(k2)
  7. f(u1, u2) = SVector(2u1 + sin(u1) + cos(u2) + u2 / 2, 3u2 + sin(u2) + sin(u1) / 2 + u1^2 / 6) / 5
  8. a = fittingcontrolpoints(f, (P1, P2))
  9. M = BSplineManifold(a, (P1, P2))
  10. plot(M; aspectratio=1)

Draw smooth vector graphics

  1. using BasicBSpline
  2. using BasicBSplineFitting
  3. using BasicBSplineExporter
  4. p = 3
  5. k = KnotVector(range(-2π,2π,length=8))+p*KnotVector([-2π,2π])
  6. P = BSplineSpace{p}(k)
  7. f(u) = SVector(u,sin(u))
  8. a = fittingcontrolpoints(f, P)
  9. M = BSplineManifold(a, P)
  10. save_svg("sine-curve.svg", M, unitlength=50, xlims=(-8,8), ylims=(-2,2))
  11. save_svg("sine-curve_no-points.svg", M, unitlength=50, xlims=(-8,8), ylims=(-2,2), points=false)


This is useful when you edit graphs (or curves) with your favorite vector graphics editor.

See Plotting smooth graphs with Julia for more tutorials.