贝塞尔曲线不过控制点,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;
}
}
}

发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。