贝塞尔曲线不过控制点,Catmull–Rom插值治国控制点,在某些场合希望曲线穿过所有控制点的话可以使用catmull-rom spline。catmull-rom spline需要4个点,具体原理可以参考维基百科。
demo:
按照定义,t应该从t1到t2,也就是说只画出中间两个控制点之间的曲线。如果我们把t0到t3之间的曲线都画出来,会是什么样子呢?
demo如下;
我发现catmull-rom spline并不能像贝塞尔曲线那样迭代,最后求c的公式和前面两个不一样。如果我们把c=(t2-t)/(t2-t1)*b1+(t-t1)/(t2-t1)*b2改为c=(t3-t)/(t3-t0)*b1+(t-t0)/(t3-t0)*b2会是什么样呢?
demo如下:
居然4个点都过了。
不知道如果像贝塞尔曲线那样改为任意阶会怎么样。
代码如下:
package { import fl.controls.NumericStepper; import flash.display.Graphics; import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.external.ExternalInterface; import flash.geom.Point; public class Main extends MovieClip { public var numSteper:NumericStepper; public var p0:MovieClip; public var p1:MovieClip; public var p2:MovieClip; public var p3:MovieClip; private var alp:Number = 0.5; private var fun:Function; public function Main() { // constructor code stage?initStage(null):addEventListener(Event.ADDED_TO_STAGE, initStage); } private function initStage(e:Event):void { removeEventListener(Event.ADDED_TO_STAGE, initStage); drag(p0); drag(p1); drag(p2); drag(p3); fun = CatmullRomSpline; var funType:* = root.loaderInfo.parameters["fun"]; switch(String(funType)) { case "1": fun = CatmullRomSpline_2; break; case "2": fun = CatmullRomSpline_3; break; default: fun = CatmullRomSpline; break; } if (ExternalInterface.available) { ExternalInterface.call("console.log","funType:"+funType); } numSteper.addEventListener(Event.CHANGE, onChanged); updateLine(); } private var curSp:Sprite; private function drag(sp:Sprite):void { sp.addEventListener(MouseEvent.MOUSE_DOWN, dragHandler); } private function dragHandler(e:Event):void { switch(e.type) { case MouseEvent.MOUSE_DOWN: curSp = e.currentTarget as Sprite; curSp.startDrag(); stage.addEventListener(MouseEvent.MOUSE_UP, dragHandler); stage.addEventListener(Event.MOUSE_LEAVE, dragHandler); stage.addEventListener(MouseEvent.MOUSE_MOVE, dragHandler); break; case MouseEvent.MOUSE_MOVE: updateLine(); break; default: curSp.stopDrag(); curSp = null; stage.removeEventListener(MouseEvent.MOUSE_UP, dragHandler); stage.removeEventListener(Event.MOUSE_LEAVE, dragHandler); stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragHandler); break; } } private function onChanged(e:Event):void { alp = numSteper.value; updateLine(); } private function updateLine():void { var arr:Array = fun(p0, p1, p2, p3, alp, 100); var g:Graphics = graphics; g.clear(); g.lineStyle(1, 0xff0000, 1.0); var len:int = arr.length; for (var i:int = 0; i <len;i++ ) { var p:Object = arr[i]; if (i==0) { g.moveTo(p.x, p.y); } else { g.lineTo(p.x, p.y); } } } /** * CatmullRomSpline * @param p0 * @param p1 * @param p2 * @param p3 * @param alp * @param nPoints * @return */ private function CatmullRomSpline(p0:Object,p1:Object,p2:Object,p3:Object,alp:Number=0.5,nPoints:int=100):Array { var t0:Number = 0; var t1:Number = Math.pow((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y), alp) + t0; var t2:Number = Math.pow((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y), alp) + t1; var t3:Number = Math.pow((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y), alp) + t2; var arr:Array = []; var step:Number = (t2 - t1) / (nPoints - 1); var a1:Point = new Point(); var a2:Point = new Point(); var a3:Point = new Point(); var b1:Point = new Point(); var b2:Point = new Point(); var c:Point; for (var t:Number = t1; t < t2;t+=step ) { a1.x = (t1 - t) / (t1 - t0) * p0.x + (t - t0) / (t1 - t0) * p1.x; a1.y = (t1 - t) / (t1 - t0) * p0.y + (t - t0) / (t1 - t0) * p1.y; a2.x = (t2 - t) / (t2 - t1) * p1.x + (t - t1) / (t2 - t1) * p2.x; a2.y = (t2 - t) / (t2 - t1) * p1.y + (t - t1) / (t2 - t1) * p2.y; a3.x = (t3 - t) / (t3 - t2) * p2.x + (t - t2) / (t3 - t2) * p3.x; a3.y = (t3 - t) / (t3 - t2) * p2.y + (t - t2) / (t3 - t2) * p3.y; b1.x = (t2 - t) / (t2 - t0) * a1.x + (t - t0) / (t2 - t0) * a2.x; b1.y = (t2 - t) / (t2 - t0) * a1.y + (t - t0) / (t2 - t0) * a2.y; b2.x = (t3 - t) / (t3 - t1) * a2.x + (t - t1) / (t3 - t1) * a3.x; b2.y = (t3 - t) / (t3 - t1) * a2.y + (t - t1) / (t3 - t1) * a3.y; c = new Point(); c.x = (t2 - t) / (t2 - t1) * b1.x + (t - t1) / (t2 - t1) * b2.x; c.y = (t2 - t) / (t2 - t1) * b1.y + (t - t1) / (t2 - t1) * b2.y; arr.push(c); } return arr; } /** * 让t从t0到t3. * @param p0 * @param p1 * @param p2 * @param p3 * @param alp * @param nPoints * @return */ private function CatmullRomSpline_2(p0:Object,p1:Object,p2:Object,p3:Object,alp:Number=0.5,nPoints:int=100):Array { var t0:Number = 0; var t1:Number = Math.pow((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y), alp) + t0; var t2:Number = Math.pow((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y), alp) + t1; var t3:Number = Math.pow((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y), alp) + t2; var arr:Array = []; var step:Number = (t3 - t0) / (nPoints - 1); var a1:Point = new Point(); var a2:Point = new Point(); var a3:Point = new Point(); var b1:Point = new Point(); var b2:Point = new Point(); var c:Point; for (var t:Number = t0; t < t3;t+=step ) { a1.x = (t1 - t) / (t1 - t0) * p0.x + (t - t0) / (t1 - t0) * p1.x; a1.y = (t1 - t) / (t1 - t0) * p0.y + (t - t0) / (t1 - t0) * p1.y; a2.x = (t2 - t) / (t2 - t1) * p1.x + (t - t1) / (t2 - t1) * p2.x; a2.y = (t2 - t) / (t2 - t1) * p1.y + (t - t1) / (t2 - t1) * p2.y; a3.x = (t3 - t) / (t3 - t2) * p2.x + (t - t2) / (t3 - t2) * p3.x; a3.y = (t3 - t) / (t3 - t2) * p2.y + (t - t2) / (t3 - t2) * p3.y; b1.x = (t2 - t) / (t2 - t0) * a1.x + (t - t0) / (t2 - t0) * a2.x; b1.y = (t2 - t) / (t2 - t0) * a1.y + (t - t0) / (t2 - t0) * a2.y; b2.x = (t3 - t) / (t3 - t1) * a2.x + (t - t1) / (t3 - t1) * a3.x; b2.y = (t3 - t) / (t3 - t1) * a2.y + (t - t1) / (t3 - t1) * a3.y; c = new Point(); c.x = (t2 - t) / (t2 - t1) * b1.x + (t - t1) / (t2 - t1) * b2.x; c.y = (t2 - t) / (t2 - t1) * b1.y + (t - t1) / (t2 - t1) * b2.y; arr.push(c); } return arr; } /** * c=(t2-t)/(t2-t1)*b1+(t-t1)/(t2-t1)*b2 * 改为: * c=(t3-t)/(t3-t0)*b1+(t-t0)/(t3-t0)*b2 * @param p0 * @param p1 * @param p2 * @param p3 * @param alp * @param nPoints * @return */ private function CatmullRomSpline_3(p0:Object,p1:Object,p2:Object,p3:Object,alp:Number=0.5,nPoints:int=100):Array { var t0:Number = 0; var t1:Number = Math.pow((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y), alp) + t0; var t2:Number = Math.pow((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y), alp) + t1; var t3:Number = Math.pow((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y), alp) + t2; var arr:Array = []; var step:Number = (t3 - t0) / (nPoints - 1); var a1:Point = new Point(); var a2:Point = new Point(); var a3:Point = new Point(); var b1:Point = new Point(); var b2:Point = new Point(); var c:Point; for (var t:Number = t0; t < t3;t+=step ) { a1.x = (t1 - t) / (t1 - t0) * p0.x + (t - t0) / (t1 - t0) * p1.x; a1.y = (t1 - t) / (t1 - t0) * p0.y + (t - t0) / (t1 - t0) * p1.y; a2.x = (t2 - t) / (t2 - t1) * p1.x + (t - t1) / (t2 - t1) * p2.x; a2.y = (t2 - t) / (t2 - t1) * p1.y + (t - t1) / (t2 - t1) * p2.y; a3.x = (t3 - t) / (t3 - t2) * p2.x + (t - t2) / (t3 - t2) * p3.x; a3.y = (t3 - t) / (t3 - t2) * p2.y + (t - t2) / (t3 - t2) * p3.y; b1.x = (t2 - t) / (t2 - t0) * a1.x + (t - t0) / (t2 - t0) * a2.x; b1.y = (t2 - t) / (t2 - t0) * a1.y + (t - t0) / (t2 - t0) * a2.y; b2.x = (t3 - t) / (t3 - t1) * a2.x + (t - t1) / (t3 - t1) * a3.x; b2.y = (t3 - t) / (t3 - t1) * a2.y + (t - t1) / (t3 - t1) * a3.y; c = new Point(); c.x = (t3 - t) / (t3 - t0) * b1.x + (t - t0) / (t3 - t0) * b2.x; c.y = (t3 - t) / (t3 - t0) * b1.y + (t - t0) / (t3 - t0) * b2.y; arr.push(c); } return arr; } } }
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。