AS3功能的样条曲线或埃尔米特曲线类似keframe插补推算点? [英] As3 Function for extrapolating points on a spline curve or Hermite Curve similar to keframe interpolation?

查看:241
本文介绍了AS3功能的样条曲线或埃尔米特曲线类似keframe插补推算点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望有人能帮助我制定出一些先进的数据格式化。我所希望的是一个功能,我可以输入以及关键岗位的数组像这样的值:

I was hoping someone could help me working out some advanced data reformatting. What I'm hoping for is a function where I can input a value along with an array of key positions like so:

function remap(percentage:Number, keypoints:Array) { ...

阵列将开始与最小和与最大点结束,与沿途嵌套关键点。例如,我会输入类似重映射(0.25,[0:0,80:50,100:100])和功能将想象从样条曲线图( 0,0) - (100,100),其(80,50一个关键点),然后返回在y值,该值是25%的沿该图

The array would start with the minimum and end with the maximum point, with nested key points along the way. For example, I would input something like remap(0.25, [0:0,80:50,100:100] ) and the function would 'imagine' a spline curve graph from (0,0)-(100,100) with a key point of (80,50), then return the y value that is 25% along that graph.

我希望这是明确的......任何想法?

Hopefully that's clear... Any ideas?

推荐答案

的计算公式埃尔米特曲线是这样的:

The equation for the Hermite Curve is this:

(通过维基百科

(via Wikipedia)

其中的 P(T)的是在t(百分之0.0至1.0)曲线上的点

Where p(t) is the point on the curve at t (percent 0.0 to 1.0)

  1. P0是第一个控制点
  2. M0是第一个锚点
  3. P1是第二个控制点
  4. M1是scond控制点

因此​​,在动作的公式是这样的:

So, the equation in actionscript would be something like this:

        /*
         * Computes x,y values for a given traversal of a Hermite Curve
         * @param t:Number - a normalized value (0.0 to 1.0) describing path traversal
         * @param points:Array - an array contining the 4 points describing the curve (P0,T0,P1,T1 - always in this order)
         * Anchor points are relative to they're control points
         */
        private function hermite(t:Number,points:Array):Point{
            var result:Point = new Point();
            result.x = (2 * Math.pow(t,3) - 3 * t * t + 1) * points[0].x+
                        (Math.pow(t,3) - 2 * t * t + t) * points[1].x + 
                        (- 2 * Math.pow(t,3) + 3*t*t) * points[2].x +
                        ( Math.pow(t,3) - t*t) * points[3].x;
            result.y = (2 * Math.pow(t,3) - 3 * t * t + 1) * points[0].y+
                        (Math.pow(t,3) - 2 * t * t + t) * points[1].y + 
                        (- 2 * Math.pow(t,3) + 3*t*t) * points[2].y +
                        ( Math.pow(t,3) - t*t) * points[3].y;
            return result;
        }

您可以在这里看到一个基本的演示

You can see a basic demo here

不过,我有点担心,因为你比如提到3点(2个控制点和一个锚点)。

Still, I am a bit concerned because you're example mentions 3 points (2 control points and one anchor point).

三次曲线(埃尔米特/卡特莫尔-ROM的/ etc。)有2个控制点和2个锚点(在3次方方程式 - 立方)

Cubic Curves(Hermite/Catmull-Rom/etc.) have 2 control points and 2 anchor points (equations at power of 3 - cubic)

如果你只需要一个控制点,你需要使用一个<一个href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#curveTo%28%29">Quadratic曲线

If you only need one control point, you need to use a Quadratic Curve:

(图片从Adobe的ActionScript 3文档)

(Image from Adobe Actionscript 3 Documentation)

三次曲线: 立方体

Cubic Curve:

二次曲线:

Quadratic Curve:

(动画维基百科)

二次方程是这样的:

The Quadratic Equation is this:

这将转化为:

private function quad(t:Number,p:Array):Point{
            var result:Point = new Point();
            var oneMinusTSq:Number = (1-t) * (1-t);
            var TSq:Number = t*t;
            result.x = oneMinusTSq*p[0].x+2*(1-t)*t*p[1].x+TSq*p[2].x;
            result.y = oneMinusTSq*p[0].y+2*(1-t)*t*p[1].y+TSq*p[2].y;
            return result;
        }

和有点考验code:

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    /**
     * @author george
     */
    public class BasicQuad extends Sprite {
        private var p0:Point = new Point(0,0);
        private var p1:Point = new Point(80,50);
        private var p2:Point = new Point(100,100);
        private var pts:Array = [p0,p1,p2];
        private var t:Number = 0;
        private var pt : Point;

        public function BasicQuad() {
            init();
        }
        private function init():void{
            stage.doubleClickEnabled = true;
            stage.addEventListener(MouseEvent.DOUBLE_CLICK, reset);
            reset();
        }
        private function reset(event : MouseEvent = null) : void {
            graphics.clear();
            graphics.lineStyle(3,0x009900,.5);
            t = 0;
            this.addEventListener(Event.ENTER_FRAME, draw);
        }
        private function draw(event : Event) : void {
            trace(t,pt);
            pt = quad(t, pts);
            if(t == 0) graphics.moveTo(pt.x,pt.y);//draw
            graphics.lineTo(pt.x,pt.y);
            t+= 0.015;
            if(t >= 1) removeEventListener(Event.ENTER_FRAME, draw);//done
        }
        private function quad(t:Number,p:Array):Point{
            var result:Point = new Point();
            var oneMinusTSq:Number = (1-t) * (1-t);
            var TSq:Number = t*t;
            result.x = oneMinusTSq*p[0].x+2*(1-t)*t*p[1].x+TSq*p[2].x;
            result.y = oneMinusTSq*p[0].y+2*(1-t)*t*p[1].y+TSq*p[2].y;
            return result;
        }
    }
}

另外,我不清楚你所说的

Also, am not clear what you mean by

高级数据格式化

在code片段是写成code中的公式,但也有其他方法来计算这一点。

The code snippets are the formulas written as code, but there are other ways to compute this.

二次贝塞尔曲线是由函数B(t)的跟踪路径,   给定的点P0,P1,和P2,

A quadratic Bézier curve is the path traced by the function B(t), given points P0, P1, and P2,

我们需要去从P0到P1,并从P1到P2。 既然你正在寻找一个Flash / ActionScript中的解决方案,我们可以利用的点的<一个href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Point.html#interpolate%28%29">interpolate()方法。 因此,我们插值P0和P1之间得到假设P01 再从P1到P2打通全取3分P12和插值会 P01和P12之间的插值:

We need to go from P0 to P1 and from P1 to P2. Since you're looking for a Flash/ActionScript solution, we can take advantage of the Point's interpolate() method. So we interpolate between P0 and P1 to get let's say P01 then from P1 to P2 to get P12 and the interpolation through all 3 points will be the interpolation between P01 and P12:

function quadLerp(t:Number,p:Array):Point {
            var p1:Point = Point.interpolate(p[1], p[0], t);
            var p2:Point = Point.interpolate(p[2], p[1], t);
            return Point.interpolate(p2, p1, t);
        }

在code看起来有点倒退从我写了上面,因为动作插值是如何实现的:内插的两个点之间的电平指示新点将位于pt1和之间的界限。PT2如果F = 1,PT1返回;如果F = 0,PT2返回

The code looks a bit backwards from what I wrote above because of how the actionscript interpolation is implemented: "The level of interpolation between the two points. Indicates where the new point will be, along the line between pt1 and pt2. If f=1, pt1 is returned; if f=0, pt2 is returned."

更新

另外困惑:

在提及你的问题:我的例子实际上提到了3个控制   分和0锚点

In reference to your question: my example actually mentions 3 control points and 0 anchor points

是你想简单地得到当前的X沿着一系列的线的y值(多点,0锚点...直线)?

are you trying to simply get the y value of the current x along a series of lines (multiple points, 0 anchor points...straight lines) ?

记得我不需要图本身 - 我只是需要一个点   只需在一条直线上图/锯齿线走(没有任何曲线)?

Remember I dont need the graph itself - I just need a point on it Simply walk on a straight line graph/jagged line(no curves whatsoever) ?

如果,那么,你可以做这样的事情:

If, so, you can do something like this:

  1. 通过您的路径的所有点环路和找到行当前x值(这将是的量,开始的x位置是否大于给定x和行末x位置越小线是比大给定的x位置)
  2. 计算从行的开始的X距离之间的比率给定的x和整个线路(end.x-start.x)
  3. 使用该比率来划分当前行高度(end.y和start.y之间的差)和由start.y抵消它,取相似三角形,据泰勒斯定理

下面是一个简单的草图来说明这个想法: 想象一个直角三角形,其中电流线是斜边(ABC)。现在想象从鼠标光标分割一个垂直线三角形分成两个相似的三角形(OO')。小三角形有相同的角度为一体的大型之一,它的两侧是成比例的。您可以使用AO和AB之间的比例来划分AC通过并获得OO的长度(上线是x y位置)。

Here's a quick sketch to illustrate the idea: Imagine a right angled triangle where the current line is the hypothenuse(ABC). Now imagine a vertical line from your mouse cursor splitting that triangle into two similar triangle(OO'). The small triangle has the same angles as the large one and it's sides are proportional. You use the ratio between AO and AB to divide AC by and obtain the length of OO' (the y position on the line for that x).

下面的功能:

private function getYforX(x:Number,pts:Vector.<Point>):Number{
            var numPts:int = pts.length;
            for (var i : int = 1; i < numPts; i++) {
                if(x > pts[i-1].x && x < pts[i].x) {//find the line on which the cursor lies
                    t = (x-pts[i-1].x)/(pts[i].x-pts[i-1].x);//ratio between the x distance from the start of the line to mouseX and the whole line (end.x-start.x)
                    return pts[i-1].y + ((pts[i].y-pts[i-1].y) * t);//Thales similar triangles version, cheaper version of Point.interpolate(pts[i], pts[i-1], t).y; 
                }
            }
            return -1;
        }

和一个快速演示:

package {
    import flash.events.*;
    import flash.display.*;
    import flash.geom.Point;

    public class LerpPoints extends Sprite {

        private var path:Shape = new Shape();
        private var cursor:Shape = new Shape();
        private var numPts:int = 11;
        private var pts:Vector.<Point> = new Vector.<Point>(numPts,true);
        private var t:Number = 0;

        public function LerpPoints() {
            init();
        }
        private function init():void{
            cursor.graphics.lineStyle(10,0x009900);
            cursor.graphics.drawCircle(-3, -3, 3);
            cursor.graphics.lineStyle(1,0x000099);
            cursor.graphics.moveTo(0, -stage.stageHeight);
            cursor.graphics.lineTo(0, stage.stageHeight);
            reset();
            addChild(path);addChild(cursor);
            addEventListener(Event.ENTER_FRAME, update);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, reset);
        }
        private function reset(event:Event = null):void{
            path.graphics.clear();
            for (var i : int = 0; i < numPts; i++) {
                pts[i] = new Point(i*55,Math.random() * 200);//generate points
                path.graphics.lineStyle(3,0);
                if(i == 0) path.graphics.moveTo(pts[0].x,pts[0].y);//draw path
                path.graphics.lineTo(pts[i].x,pts[i].y);
                if(i > 0){//right angled triangles
                    path.graphics.lineStyle(1,0x990000);
                    path.graphics.lineTo(pts[i-1].x,pts[i].y);
                    path.graphics.lineTo(pts[i-1].x,pts[i-1].y);
                    path.graphics.moveTo(pts[i].x,pts[i].y);
                }
            }
        }
        private function update(event:Event):void{
            cursor.x = mouseX;
            cursor.y = getYforX(mouseX, pts);
        }
        private function getYforX(x:Number,pts:Vector.<Point>):Number{
            var numPts:int = pts.length;
            for (var i : int = 1; i < numPts; i++) {
                if(x > pts[i-1].x && x < pts[i].x) {//find the line on which the cursor lies
                    t = (x-pts[i-1].x)/(pts[i].x-pts[i-1].x);//ratio between the x distance from the start of the line to mouseX and the whole line (end.x-start.x)
                    return pts[i-1].y + ((pts[i].y-pts[i-1].y) * t);//Thales similar triangles version, cheaper version of Point.interpolate(pts[i], pts[i-1], t).y; 
                }
            }
            return -1;
        }
    }
}

请注意,这个工作如果在你点阵列的X值是升序排列(例如,你的路径也仅限左至右)

Note that this works if the x values in your points array are in sorted ascending (e.g. your path goes only left to right)

一个肮脏的黑客自带的初衷就是通过点和商店Y值的查找表的双循环。圈数woud是行细节

A dirty hack that comes mind is to loop through the pairs of points and store Y values in a lookup table. The number of loops woud be the 'line detail'

话又说回来,这混淆了我:

Then again, this confuses me:

只需要能够评估一个点的数组(不只是2),最好   样条曲线的方式,而不是简单地加入了点   所以,你必须多点,但哪里花键进来,因为你提到的0锚点?

just need to to asses an array of points (not just 2) and ideally spline curve them rather than simply joining the dots So you have multiple points, but where does the spline come in, since you mentioned 0 anchor points ?

心连心

这篇关于AS3功能的样条曲线或埃尔米特曲线类似keframe插补推算点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆