flash – As3用于在样条曲线或Hermite曲线上外推点的函数,类似于
我希望有人可以帮我制作一些高级数据重新格式化.我希望的是一个函数,我可以输入一个值以及一系列关键位置,如下所示:
function remap(percentage:Number,keypoints:Array) { ... 数组以最小值开始,以最大点结束,沿途有嵌套关键点.例如,我会输入像重映射(0.25,[0:0,80:50,100:100])这样的函数,并且该函数将“想象”来自(0,0) – (100,100)的样条曲线图,其关键点为(80,50),然后返回该图表中25%的y值. 希望这很明确……任何想法? 解决方法
Hermite曲线的等式是这样的:
(通过Wikipedia) 其中p(t)是t处曲线上的点(百分比0.0到1.0) > p0是第一个控制点 因此,actionscript中的等式将是这样的: /* * 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; } 你可以看到一个基本的演示here 不过,我有点担心,因为你的例子提到3分(2个控制点和一个锚点). 立方曲线(Hermite / Catmull-Rom /等)有2个控制点和2个锚点(功率为3的方程式 – 立方) 如果您只需要一个控制点,则需要使用Quadratic Curve: (来自Adobe Actionscript 3文档的图像) 立方曲线: 二次曲线: (来自维基百科的动画) 二次方程是这样的: 哪个会转换为: 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; } 还有一些测试代码: 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; } } } 另外,我不清楚你的意思
代码片段是作为代码编写的公式,但还有其他方法可以计算它.
我们需要从P0到P1,从P1到P2. 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,t); } 由于动作脚本插值的实现方式,代码看起来有点倒退了:“两点之间的插值水平.指示新点的位置,沿着pt1和pt2之间的线.如果f = 1,返回pt1;如果f = 0,则返回pt2.“ UPDATE 进一步困惑:
你试图简单地沿着一系列线(多个点,0个锚点……直线)得到当前x的y值?
如果,那么,您可以这样做: >遍历路径的所有点并找到当前x值的行(这将是起始x位置小于给定x的行,并且行的结束x位置大于给定的x位置) 这是一个快速草图来说明这个想法: 想象一个直角三角形,其中当前行是连字符(ABC).现在想象一下你的鼠标光标的垂直线将该三角形分成两个相似的三角形(OO’).小三角形与大角形具有相同的角度,并且它的边是成比例的.使用AO和AB之间的比率来划分AC,并获得OO’的长度(该x的线上的y位置). 这是功能: 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,t).y; } } return -1; } } } 请注意,如果点数组中的x值按升序排序(例如,您的路径仅从左到右),则此方法有效 想到的一个肮脏的黑客是循环遍历点对并将Y值存储在查找表中.循环次数应该是’线条细节’ 然后,这让我感到困惑:
HTH (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |