CSE 477/577   G. Farin
Degree reduction

A Bezier polygon is given in the array b, defining a degree n Bezier curve. The process of degree reduction produces an array bred, defining a degree n-1 Bezier curve.

b = elevmat·bred (degree elevation)
(elevmat^T)bred = [(elevmat^T)· elevmat ]·bred (linear system for degree reduction, resulting in bred. )

bb={{{0,0},{1,1},{2,1},{3,0}},  (* This cubic is actually a quadratic *)
Table[{i,((-1)^i)+RandomReal[]},{i,1,15}],
{{0,0}, {1,1}, {1,1}, {2,0}} (* although this looks like a quadratic, it is a true cubic *)
};
(* choose your polygon from array bb -- bb[[1]], bb[[2]], etc*)
b=bb[[1]];  (* to be degree reduced *)
n=Length[b]-1;  (* current degree *)

nred = n-1; (* reduced degree *)
elevmat=Table[0.0,{i,1,nred+2},{j,1,nred+1}]; (* matrix used to elevate from degree n to n+1 *)

elevmat[[1,1]]=1;
elevmat[[nred+2,nred+1]]=1;
Do[(elevmat[[i,i-1]]=(i-1)/(nred+1); elevmat[[i,i]]=1-elevmat[[i,i-1]]),{i,2,nred+1}]; (* end building elevation matrix *)

(*
Print["elevtion matrix: ",MatrixForm[elevmat]]
Print["elev_transpose.elev ",MatrixForm[Transpose[elevmat].elevmat]]
MatrixForm[b]
*)

center=Sum[b[[i]],{i,1,n+1}]/(n+1);
dists=Table[Norm[b[[i]]-center],{i,1n+1}];
radius=Max[dists];
Do[b[[i]]=b[[i]]-center,{i,1n+1}];
(* This centers all control points around the origin, for easy window sizing *)

(* Black polygon & curve: original. Red: degree reduced *)
Manipulate[(
curveplot=Graphics[{Thick,BezierCurve[pt,SplineDegree-> n]}];
poly=Graphics[Line[pt]];bred=LinearSolve[Transpose[elevmat].elevmat,Transpose[elevmat].pt];
redcurve=Graphics[{Thick,Red,BezierCurve[bred,SplineDegree-> n-1]}];
redpoly=Graphics[{Thick,Red,Line[bred]}];
redpoints=Graphics[{PointSize[Large],Point[bred]}];
Show[{poly,redpoly,curveplot, redcurve,redpoints},PlotRange->1.2radius]),{{pt,b},Locator}
]
(* Experiment with moving the control points *)