Splines

Computer-Algebra und Visualisierungen zu Splines / Prof. Dr. Bernhard Zgraggen, HSR

Einführung in dieses Notebook

Dieses Dokument ist ein "selbsterklärendes" Mathematica-Notebook, das interaktiv bearbeitet werden kann ("Hands-On"). Input-Zellen können mittels der Tastenkombination ⇧⌤ (in Worten: Shift-Enter) ausgeführt werden. Falls Textzellen geschlossen sind, so können sie durch Klick auf das Icon ▼ oder auf die blaue Zellklammer rechterhand geöffnet werden.

Wenn Sie in Mathematica auf Befehle oder Begriffe stossen, die Sie nicht verstehen, so steht Ihnen die mächtige Hilfe/Doc Center zur Verfügung; diese ist interaktiv.

Allfällige Aufgaben/Übungen befinden sich am Ende des Dokuments.

Spline-Interpolation → {Interpolation}

({{, }})

Bézier-Splines (B-B-Splines) → {BezierFunction, BezierCurve, BernsteinBasis}

Bernstein-Basis Polys

demoBernsteinBasis1D

Bernstein Approximation by Equi-Distant Sampling

demoBernsteinApproximation

Casteljau's Algorithm for Bézier-Splines

As r changes from 1 to 3 a sequence of linear interpolations shows how to construct a point on the cubic Bézier curve when there are four control points. The parameter t controls the proportion of the distance along an interpolating line. As t varies between 0 and 1 the entire curve is generated.

demoBezierCasteljau1D

For n+1 control points, (Subscript[p, 0]), (Subscript[p, 1]),...,(Subscript[p, n]), the Bézier curve can be constructed by the recurrence relation (Subscript[B, i]^r)(t)=(1-t) (Subscript[B, i]^(r-1))(t)+t (Subscript[B, i+1]^(r-1))(t) where (Subscript[B, i]^1)=(1-t) (Subscript[p, i])+t (Subscript[p, i+1]) is the linear interpolation between control points (Subscript[p, i]) and (Subscript[p, i+1]). The recursion level r goes from 1 to n and i runs from 0 to n-r.

Composite Bézier-Spline Curve

This demonstration compares composite Bézier Splines with uniform BSpline (Basis splines with uniformly distributed knots).

demoBezier1D

Bézier-Spline Surface

demoBezierSurface

Basis-Splines (B-Splines) → {BSplineFunction, BSplineCurve, BSplineSurface, BSplineBasis}

B-Spline Curve with Knots

This Demonstration illustrates the relation between B-spline curves and their knot vectors. Start with the control points {(Subscript[p, 0]),(Subscript[p, 1]),...,(Subscript[p, n])|(Subscript[p, i])∈(ℝ^k)} and a knot vector {(Subscript[t, 0,])(Subscript[t, 1]),...,(Subscript[t, m])}, where the degree of the B-spline is p=m-n-1. The knot vector satisfies (Subscript[t, i])∈[0,1] and (Subscript[t, i])≤(Subscript[t, i+1]). The B-spline basis functions are defined as:

(Subscript[N, i,0])(t)=(Piecewise[{{1, (Subscript[t, i])≤t<(Subscript[t, i+1])}, {0, otherwise}}])

(Subscript[N, i,p])(t)=((t-(Subscript[t, i]))/((Subscript[t, i+p])-(Subscript[t, i])))(Subscript[N, i,p-1])(t)+(((Subscript[t, i+p+1])-t)/((Subscript[t, i+p+1])-(Subscript[t, i+1])))(Subscript[N, i+1,p-1])(t),

and a B-spline curve is defined as:

C(t)=(∑_(i=0)^n)(Subscript[p, i])(Subscript[N, i,p])(t).

For nonperiodic B-splines, the first p+1 knots are equal to 0 and the last p + 1 knots are equal to 1. If k duplication happens at the other knots, the curve becomes p-k times differentiable. So, by overlapping the knots, you can generate a curve with sharp turns or even discontinuities.

When the number of control points is p-1, the basis functions are reduced to Bernstein polynomial, thus the curve becomes a Bézier curve.

demoBSpline1D

Red points indicate the knot points on the curve. Hold down the Alt key and click to add new control points (up to 12). Changes in degree and number of control points will cause the knot vector to be recomputed.
Choose "view basis functions" to show the B-spline basis functions of a given knot vector instead of the B-spline curve.

Bi-Cubic Polynomial uniform B-Spline Surfaces

By default the SplineWeights are uniformly equal to 1 (non-rational = polynomial spline surface), the SplineDegree is 3 (bi-cubic, tri-cubic etc.), the SplineKnots are chosen to be uniform and to make the surface reach the control points at the edges of the array.

demoBSpline2D

Aufgabe(n)

(1)
Führen Sie die Demos in den Abschnitten Bézier-Splines und BasisSplines aus.

Demonstration-Codes

Casteljau's Algorithm for Bézier-Splines (extern)

Clear[b];
b[t_,i_,r_]:=(1-t) b[t,i,r-1]+t b[t,i+1,r-1];

b[t_,0,1]:=(1-t)p[0]+t p[1];
b[t_,1,1]:=(1-t) p[1]+t p[2];
b[t_,2,1]:=(1-t) p[2]+t p[3];

p[0]={0.0,0.5};
p[1]={0.5,2.5};
p[2]={3.0,2.0};
p[3]={4.0,0.0};

demoBezierCasteljau1D:=Manipulate[Module[{plt},plt=ParametricPlot[b[t,0,3],{t,0,s},PlotStyle->{Blue,Dotted,Thickness[0.01]}][[1]];Which[
r==1,Graphics[{{Lighter[Gray],Line[{p[0],p[1],p[2],p[3]}]},{PointSize[0.015],Point[{p[0],p[1],p[2],p[3]}]},{Green,PointSize[0.015],Point[{b[s,0,1],b[s,1,1],b[s,2,1]}]},{Purple,Thickness[0.005],Line[{p[0],b[s,0,1]}],Line[{p[1],b[s,1,1]}],Line[{p[2],b[s,2,1]}]}},PlotRange->{{-0.1,4.1},{-0.1,2.6}},ImageSize->{500,375}],
r==2,Graphics[{{Lighter[Gray],Line[{p[0],p[1],p[2],p[3]}]},{PointSize[0.015],Point[{p[0],p[1],p[2],p[3]}]},{Lighter[Gray],Line[{{b[s,0,1],b[s,1,1]},{b[s,1,1],b[s,2,1]}}]},{Green,PointSize[0.015],Point[{b[s,0,1],b[s,1,1],b[s,2,1]}]},
{LightRed,PointSize[0.015],Point[{b[s,0,2],b[s,1,2]}]},{Purple,Thickness[0.005],Line[{{p[0],b[s,0,1]},{p[1],b[s,1,1]},{p[2],b[s,2,1]},{b[s,0,1],b[s,0,2]},{b[s,1,1],b[s,1,2]}}]}},PlotRange->{{-0.1,4.1},{-0.1,2.6}},ImageSize->{500,375}],r==3,Graphics[{plt,{Lighter[Gray],Line[{p[0],p[1],p[2],p[3]}]},{PointSize[0.015],Point[{p[0],p[1],p[2],p[3]}]},{Green,PointSize[0.015],Point[{b[s,0,1],b[s,1,1],b[s,2,1]}]},
{LightRed,PointSize[0.015],Point[{b[s,0,2],b[s,1,2]}]},{Lighter[Gray],Line[{{b[s,0,1],b[s,1,1]},{b[s,1,1],b[s,2,1]},{b[s,0,2],b[s,1,2]}}]},
{Red,PointSize[0.015],Point[{b[s,0,3]}]},
{Purple,Thickness[0.005],Line[{{p[0],b[s,0,1]},{p[1],b[s,1,1]},{p[2],b[s,2,1]},{b[s,0,1],b[s,0,2]},{b[s,1,1],b[s,1,2]},{b[s,0,2],b[s,0,3]}}]}},PlotRange->{{-0.1,4.1},{-0.1,2.6}},ImageSize->{500,375}]]],{{r,3,"Step r"},{1,2,3}},{{s,0.5,"Parameter t"},0.001,1.0,Appearance->"Labeled"},SaveDefinitions->True]

Interactive Bézier-Spline (extern)

demoBezier1D:=Manipulate[Graphics[Through[spline[#,SplineDegree->d]&[pts]]/.{b_BSplineCurve:>{Blue,b}},PlotRange->2],{{spline,{BezierCurve,BSplineCurve}},{BezierCurve->"Bézier curve",BSplineCurve->"B-spline curve"},ControlType->TogglerBar},{{d,3},1,Length[pts],1},{{pts,{Re[z],Im[z]}/.Solve[z^5==1,z]},{-2,-2},{2,2},Locator,LocatorAutoCreate->2},{{spline,{BezierCurve,BSplineCurve}},{{},{BezierCurve},{BSplineCurve},{BezierCurve,BSplineCurve}},ControlType->None},AutorunSequencing->{{3,5},4,2},ControllerLinking->False]

Bernstein Polynomials (extern)

DivZ[s_,0]:=0;
DivZ[s_,t_]:=s/t;
PowerZ[(x_)?((#1 == 0) & ), (y_)?((#1 == 0) & )] := 1; 
PowerZ[x_, y_] := x^y; 
Bernstein[i_, n_, t_]:=Binomial[n,i]*PowerZ[1-t,n-i]*PowerZ[t,i];

demoBernsteinBasis1D:=Manipulate[Module[{ps,f},If[k>n,k=n];ps=Table[{Hue[.67,.6,.6],Opacity[.1(8+2Boole[k==i])],Thickness[0.001(1+4Boole[k==i])]},{i,0,n}];
f[t_]:=Table[Bernstein[i,n,t],{i,0,n}];Show[Plot[Evaluate@f[x],{x,0,1},PlotStyle->ps,PlotPoints->25,MaxRecursion->ControlActive[1,2],PlotRange->{0,1.1},Filling->If[fill,{k+1->{Axis,{Opacity[.15],Green}}},None],PlotLabel->Style[(Subscript[B, k,n])[x]==Bernstein[k,n,x],14]],Graphics[If[n==0,{},With[{j=k+.3Boole[k==0]-.3Boole[k==n]},Arrow[{{.5,1.1},{DivZ[j,n],Bernstein[k,n,DivZ[j,n]]}}]]]],Graphics[If[env&&n≠0,{Part[Plot[(1/(Sqrt[2π n t(1-t)])),{t,0,1},Filling->Axis,FillingStyle->{Gray,Opacity[.05]},PlotStyle->{Red,Thickness[0.004],Opacity[.7]},PlotRange->All],1]},{}]],ImageSize->{450,300},ImagePadding->{{25,25},{25,38}}]],
{{n,12,"degree"},0,20,1},{{k,5,"(k^th)"},0,n,1},{{env,True,"show envelope"},{True,False},ControlPlacement->Bottom},{{fill,True,"show filling"},{True,False},ControlPlacement->Bottom},SaveDefinitions->True,ControllerLinking->False]

Image Warping (extern)

demoBezierSurface:=Manipulate[
(* Compute linear interpolation function for colors *)
If[ii=!=previi,colfun=BSplineFunction[ImageData[images[[ii]]],SplineDegree->1];previi=ii];
(* Reset the grid *)
If[n=!=prevn,pts=Flatten[Table[{i,j},{i,0,1,1/(n-1)},{j,0,1,1/(n-1)}],1];If[approx,order=n-1,order=2];prevn=n];
(* Fix the interpolation order *)
If[approx=!=prevapprox,If[approx,order=n-1,order=2];prevapprox=approx];
(* Generate B-spline warping function *)
If[approx,
f=BSplineFunction[Partition[pts,n],SplineDegree->order,Method->{"Extrapolation"->"Clamp"}],
f=Interpolation[Flatten[Table[{{N[1/(n-1)]i,N[1/(n-1)]j},pts[[n i+j+1]]},{i,0,n-1},{j,0,n-1}],1],Method->"Spline",InterpolationOrder->order]
];
(* Display everything *)
ParametricPlot[f[u,v],{u,0,1},{v,0,1},ColorFunction->(colfun[1-#4,#3]&),MaxRecursion->0,PlotPoints->ControlActive[20,100],Mesh->None,Epilog->{If[grid,{Gray,Opacity[.7],Line[Partition[pts,n]],Line[Transpose[Partition[pts,n]]]},{}],If[locators,Locator/@pts,{}]},ImageSize->400,PlotRange->{{0,1},{0,1}},PlotRangePadding->Scaled[.03],FrameTicks->None],
(* Controls *)
"None"->{{pts,Flatten[Table[{i,j},{i,0,1,.25},{j,0,1,.25}],1]},{0,0},{1,1},Locator,Appearance->None},
{{ii,1,"source"},{1->"image",2->"pattern"},ControlType->RadioButton},
Delimiter,
{{n,4,"grid size"},4,8,1,ControlType->RadioButton},
{{approx,True,"method"},{False->"B-spline interpolation",True->"Bézier surface"},ControlType->RadioButton},
{{order,3},Dynamic[RadioButtonBar[Dynamic[order],Range[2,n-1,1],Enabled->Not[approx]]]&},
Delimiter,
Row[{Control[{{grid,True,"show grid"},{True,False}}],
Control[{{locators,True,"show locators"},{True,False}}],
Control[{{dummy,"",""},Button["reset grid",pts=Flatten[Table[{i,j},{i,0,1,1/(n-1)},{j,0,1,1/(n-1)}],1]]&}]},Spacer[10]],
(* Dummy controls for dynamic variables *)
{{previi,0},ControlType->None},
{{prevn,5},ControlType->None},
{{prevapprox,True},ControlType->None},
{colfun,ControlType->None},
{f,ControlType->None},
{g,ControlType->None},
AutorunSequencing->{1,2},
(* The second image is generated by the following code: Image[Table[Boole[Xor[EvenQ[Quotient[i-1,20]],EvenQ[Quotient[j-1,20]]]],{i,200},{j,200},{k,3}]] *)
Initialization:>(images={,};)]

B-Spline Curve with Knots (extern)

(* Some utility function for zero division, zero power *)
DivZ[s_,t_/;t==0]:=0.;
DivZ[s_,t_]:=N[(s/t)];
PowerZ[x_/;x==0,y_/;y==0] := 1.; 
PowerZ[x_, y_] := N[(x^y)]; 

(* B-spline basis function *)
myBSplineBasis[i_,0,knots_]:=Function[{t},If[(knots[[i]]≤t<knots[[i+1]])||(t==1.&&knots[[i+1]]==1.),1.,0.]];
(* Piecewise looks pretty, but a tad slower than If[]. It is here forr the reference *)
(* BSplineBasis[i_,0,knots_]:=Function[{t},Piecewise[{{1.,knots[[i]]≤t<knots[[i+1]]},{1.,t==1.&&knots[[i+1]]==1.},{0.,True}}]]; *)
myBSplineBasis[i_,k_,knots_]:=With[{l=k-1,j=i+1},Function[{t},DivZ[t-knots[[i]],knots[[i+k]]-knots[[i]]] myBSplineBasis[i,l,knots][t]+DivZ[knots[[i+k+1]]-t,knots[[i+k+1]]-knots[[i+1]]] myBSplineBasis[j,l,knots][t]]];

(* B-spline basis plot *)
PlotmyBSplineBasis[knots_,deg_]:=Plot[Evaluate[Table[Tooltip[10+myBSplineBasis[j,deg,knots][t],Subscript[Style["N",Italic],Row[{j-1,",",deg}]]],{j,Length[knots]-1-deg}]],{t,0,1},PlotStyle->Table[Directive[Lighter[ColorData[1][j],.5],Thick],{j,Length[knots]-1-deg}],PlotRange->{{0,1},{10,11}},Exclusions->None,
Ticks->{Automatic,{{10.2,.2},{10.4,.4},{10.6,.6},{10.8,.8},{11,1}}},AxesStyle->LightGray];

(* B-spline curve *)
myBSplineCurve[x_,knots_]:=
With[{n=Length[x],m=Length[knots]-Length[x]-1},
Function[{t},Table[myBSplineBasis[i,m,knots][t],{i,n}].x]
  ];

(* B-spline curve plot *)
PlotmyBSplineCurve[x_,knots_,deg_,kf_]:=Module[
{xpts=Union[N[knots[[deg+1;;Length[knots]-deg]]]],
xmulti=Length/@Split[N[knots[[deg+1;;Length[knots]-deg]]]],
f,s
},
f=myBSplineCurve[x,knots][s];
{
Table[
{If[xmulti[[i+1]]≤deg,Line[Table[f/.s->t,{t,xpts[[i]],xpts[[i+1]],ControlActive[0.25,0.05] (xpts[[i+1]]-xpts[[i]])}]],Line[Table[f/.s->t,{t,Append[Most[Range[xpts[[i]],xpts[[i+1]],ControlActive[0.25,0.05] (xpts[[i+1]]-xpts[[i]])]],xpts[[i+1]]-0.001]}]]],If[kf,{Red,AbsolutePointSize[5],Tooltip[Point[f/.s->xpts[[i]]],xpts[[i]]]},{}]},
{i,Length[xpts]-1}],

If[kf,{Red,AbsolutePointSize[5],Tooltip[Point[f/.s->xpts[[-1]]],xpts[[-1]]]},{}]
}];

(* Generate control polygon *)
ControlNets[x:{{_,_}..}]:=GraphicsComplex[x,{Line[Table[{i,i+1},{i,Length[x]-1}]]}];

(* Generate uniform knot vector *)
uniformknots[cpts_,deg_]:=Join[ConstantArray[0.,deg+1],Table[Round[(i/(Length[cpts]-deg)),.01],{i,Length[cpts]-deg-1}],ConstantArray[1.,deg+1]];

(* Custom sliders for knots *)
knotslider[knots_,deg_]:=With[{r=Range[deg+2,Length[knots]-deg-1]},
If[r==={},
Grid[{{Spacer[3],"no knot control",Spacer[2],"(Bézier curve)"}}],Grid[{Spacer[3],Subscript[Style["t",Italic],#-1],Slider[Dynamic@knots[[#1]],{0,1,.01},Appearance->"UpArrow",ImageSize->{200,12}],Dynamic@knots[[#1]]}&/@r]
]
];

SetAttributes[knotslider,HoldAll];

demoBSpline1D:=
Manipulate[

(* Any degree or control points change invoke reconfiguration of knots *)
If[pdeg≠deg||lencpts≠Length[cpts],
deg=Min[deg,Length[cpts]-1];knots=uniformknots[cpts,deg];pdeg=deg;lencpts=Length[cpts]];

(* Main graphics *)
If[view===1,
(* View curve *)
Graphics[{
(* Control points labels *)
Table[Switch[i,
1,Text[Style[i,White],Offset[20Normalize[cpts[[1]]-cpts[[2]]],cpts[[i]]]],
Length[cpts],Text[Style[i,White],Offset[20Normalize[cpts[[-1]]-cpts[[-2]]],cpts[[-1]]]],
_,Text[Style[i,White], Offset[20Normalize[Normalize[cpts[[i]]-cpts[[i-1]]]+Normalize[cpts[[i]]-cpts[[i+1]]]],cpts[[i]]]]
],{i,Length[cpts]}],

(* Control polygon *)
If[cnet,{Yellow,Opacity[.9],ControlNets[cpts]},{}],

(* B-spline curve *)
White,AbsoluteThickness[2],
If[OrderedQ[knots],
PlotmyBSplineCurve[cpts,knots,deg,kpts],
Do[If[knots[[i-1]]>knots[[i]],knots[[i-1]]=knots[[i]]],{i,2,Length[knots]}];PlotmyBSplineCurve[cpts,knots,deg,kpts]
]
},PlotRange->{{-.5,2.5},{-.5,1.5}},PlotRangePadding->{{Scaled[.02],Scaled[.02]},{Scaled[.06],Scaled[.02]}},ImageSize->{400,280},Frame->False,GridLines->Automatic,GridLinesStyle->Directive[Gray,Dashed],Epilog->Inset[Style[Row[{"knot vector: ",knots/.{0.->0,1.->1}}],11,White,"SmallText"],{Center,Bottom},{Center,Bottom}],Background->Hue[(2/3),.5,.5]],

(* View basis functions *)
Show[
If[OrderedQ[knots],
PlotmyBSplineBasis[knots,deg],
Do[If[knots[[i-1]]>knots[[i]],knots[[i-1]]=knots[[i]]],{i,2,Length[knots]}];PlotmyBSplineBasis[knots,deg]],
ImageSize->{400,280},ImagePadding->{{30,30},{20,20}},Background->Hue[(2/3),.5,.5],
PlotRangeClipping->False,GridLines->{None,{10.2,10.4,10.6,10.8,11}},GridLinesStyle->Directive[Dotted,Gray],Epilog->With[{xpts=Union[N[knots[[deg+1;;Length[knots]-deg]]]]},{AbsolutePointSize[5],Red,Table[Tooltip[Point[{xpts[[i]],10}],xpts[[i]]],{i,Length[xpts]}]}]]
],

{{cpts,{{0,0},{0,1},{0.5,1},{1.5,0},{2,0},{2,1}}},{-.5,-.5},{2.5,1.5},Locator,LocatorAutoCreate->{4,12}},
{{deg,2,"degree"},Dynamic@RadioButtonBar[Dynamic[deg],Range[0,Min[Length@cpts-1,5]]]&},
{{cnet,True,"control polygon"},{True,False}},
{{kpts,True,"knots on curve"},{True,False}},
{{view,1,"view"},{1->" curve ",2->" basis functions "}},
(* Dummy control for button panel *)
{{dummy,,"control points"},1,(Row[{Spacer[10],
Button["delete last",cpts=Most[cpts];knots=uniformknots[cpts,deg],Enabled->(Length[cpts]>4)],
Spacer[10],
Button["reset all",cpts={{0,0},{0,1},{0.5,1},{1.5,0},{2,0},{2,1}};knots=uniformknots[{{0,0},{0,1},{1,1},{1,0},{2,0},{2,1}},2];deg=2]}])&,ControlPlacement->Bottom},
Delimiter,
{{knots,uniformknots[{{0,0},{0,1},{1,1},{1,0},{2,0},{2,1}},2],"knot control"},knotslider[knots,deg]&,ControlPlacement->Bottom},
(* To track variable changes *)
{{pdeg,2},ControlType->None},
{{lencpts,6},ControlType->None},
AutorunSequencing->{1,5},
SaveDefinitions->True,
TrackedSymbols->{cpts,deg,cnet,kpts,view,knots,pdeg,lencpts}
]

B-Spline Surfaces (extern)

demoBSpline2D:=
Manipulate[Module[{cpts},
cpts={{pt1,pt2,pt3,pt4},{pt5,pt6,pt7,pt8}};
Graphics3D[{BSplineSurface[cpts],RGBColor[.6,.73,.36],PointSize[.05],Point[Flatten[cpts,1]],
Black,If[labels,{Text[1,pt1],Text[2,pt2],Text[3,pt3],Text[4,pt4],Text[5,pt5],Text[6,pt6],Text[7,pt7],Text[8,pt8]},{}]},ImageSize->{400,400},Axes->True,AxesLabel->{Style["x",Bold,Blue,Larger],Style["y",Bold,Blue,Larger],Style["z",Bold,Blue,Larger]},PlotRange->1]
],{{pt,1,"select control point"},{1,2,3,4,5,6,7,8}},{{labels,True},{True,False}},PaneSelector[{1->Control[{{pt1,{0,0,0},"xyz"},{-1,-1,-1},{1,1,1}}],2->Control[{{pt2,{-0.3,0.8,0.9},"xyz"},{-1,-1,-1},{1,1,1}}],3->Control[{{pt3,{-0.2,0,0.6},"xyz"},{-1,-1,-1},{1,1,1}}],4->Control[{{pt4,{0.3,0.7,-0.7},"xyz"},{-1,-1,-1},{1,1,1}}],5->Control[{{pt5,{-0.4,0.9,-0.1},"xyz"},{-1,-1,-1},{1,1,1}}],6->Control[{{pt6,{-0.4,-0.8,0.7},"xyz"},{-1,-1,-1},{1,1,1}}],7->Control[{{pt7,{0.4,-0.1,0.2},"xyz"},{-1,-1,-1},{1,1,1}}],8->Control[{{pt8,{0,-0.4,-0.5},"xyz"},{-1,-1,-1},{1,1,1}}]},Dynamic[pt]],TrackedSymbols->True,AutorunSequencing->{2,3}]

Bernstein Approximation by Equi-Distant Sampling (extern)

demoBernsteinApproximation:=
Manipulate[
Pane[

Switch[View,

"graphs",

Graphics[
Show[
First@Plot[Evaluate[{func/.x->t,(∑_(k=0)^n)(func/.x->(k/n))Binomial[n,k]((x^k) (((1-x))^(n-k)))/.{x->t,n->order}}],{t,0,1},ImageSize->.9{550,400},PlotRange->{{0,1},{-1,1}},Axes->True,GridLines->Automatic,PlotLegends->{TraditionalForm[f[x]],TraditionalForm[(Subscript[B, n])[f][x]]}], 
ListPlot[Evaluate[Table[{k/n,(func/.x->(k/n))},{k,0,n/. {n->order}}]/.{n->order}],Filling->Axis,PlotStyle->Red]
]
],

"difference",

Labeled[Graphics[{First@Plot[Evaluate[Abs[func-(∑_(k=0)^n)(func/.x->(k/n))Binomial[n,k]((x^k) (((1-x))^(n-k)))/.n->order],{x,0,1}]]},ImageSize->.9{550,400},PlotRange->{{0,1},{0,.5}},Axes->True,
AxesLabel->{x,Row[{Spacer[30],TraditionalForm[Abs[f[x] -(Subscript[B, n])[f][x]]]}]},RotateLabel->True,ImagePadding->{{20,20},{20,20}},GridLines->Automatic],Text@Row[{"(sup_(x ∈ [0; 1]))\[LeftBracketingBar]",TraditionalForm[f[x]],"-",TraditionalForm[(Subscript[B, n])[f][x]],"\[RightBracketingBar]⩽ ",ToString[NumberForm[MaxValue[{Abs[(func-(∑_(k=0)^n)(func/.x->(k/n))Binomial[n,k]((x^k) (((1-x))^(n-k)))/.n->order)//N],0≤x≤1},x],{7,4},NumberPadding->{"","0"}]]," if ",Style["n",Italic]," ≥ degree of ",TraditionalForm[(Subscript[B, n])[f][x]]}]]
]
,ImageSize->{630,420},Alignment->Center],

{{xx,0},-2,2,ControlType->None},{{func,Cos[3 Pi x],TraditionalForm[f[x]]},{Sin[4x]->TraditionalForm[Sin[4x]],(E^(-10x))->TraditionalForm[(E^(-10x))],Sqrt[x]->TraditionalForm[Sqrt[x]],Cos[3 Pi x]->TraditionalForm[Cos[3 Pi x]]}},{{order,21,Row[{"degree n of ",TraditionalForm[(Subscript[B, n])[f][x]]}]},1,200,1,Appearance->"Labeled"},
{{View,"graphs","view"},{"graphs","difference"}}];