Уравнение для кривой Эрмита таково:
(через Википедию )
Где p (t) - этоточка на кривой в точке t (процент от 0,0 до 1,0)
- p0 - первая контрольная точка
- m0 - первая опорная точка
- p1 - вторая контрольная точкаpoint
- m1 - контрольная точка scond
Итак, уравнение в 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;
}
Вы можете увидеть базовую демонстрацию здесь
Тем не менее, я немного обеспокоен тем, что в вашем примере упоминаются 3 точки (2 контрольных точки и одна точка привязки).
Кубические кривые (Эрмит)/ 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;
}
И немного теста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;
}
}
}
Кроме того, неясно, что вы подразумеваете под
расширенное переформатирование данных
Фрагменты кода - это формулы, записанные в виде кода, но есть и другие способы вычислить это.
Квадратичная кривая Безье - это путь, пройденный функцией B (t), заданные точки P0, P1 и P2,
Нам нужно перейти от P0 к P1 и от P1 к P2.Поскольку вы ищете решение Flash / ActionScript, мы можем воспользоваться методом Point interpolate () .Таким образом, мы интерполируем между P0 и P1, чтобы получить, скажем, P01, затем из P1 в P2, чтобы получить P12, и интерполяция через все 3 точки будет интерполяцией между P01 и 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);
}
Код выглядит немногов противоположность тому, что я написал выше, из-за того, как реализована интерполяция ActionScript: «Уровень интерполяции между двумя точками. Указывает, где будет находиться новая точка, вдоль линии между pt1 и pt2. Если f = 1, возвращается pt1;если f = 0, возвращается pt2. "
ОБНОВЛЕНИЕ
Далее запутано:
В связи с вашим вопросом: мой пример на самом делеупоминает 3 контрольные точки и 0 опорных точек
Вы пытаетесь просто получить значение y текущего x по ряду линий (несколько точек, 0 опорных точек ... прямые линии)?
Помните, мне не нужен сам график - мне просто нужна точка на нем. Просто пройдитесь по прямому графику / неровной линии (вообще никаких кривых)?
Если это так, вы можете сделать что-то вроде этого:
- Перебрать все точки вашего пути и найти линию для текущего значения x (это будет линия, для которой начальная позиция x равнаменьше заданного значения x, а конечная позиция x в строке больше заданной позиции x)
- Рассчитать соотношение между расстоянием x от начала строки до заданного x и всей линией (конец)..x-start.x)
- Используйте это отношение, чтобы разделить текущую строку 'height' (разницу между end.y и start.y) и сместить ее на start.y, используя преимущество аналогичные треугольники, согласно теореме Фалеса
Вот краткий набросок, иллюстрирующий идею: Представьте прямоугольный треугольник, где текущая линия - гипотенуза (ABC).Теперь представьте вертикальную линию от курсора мыши, разделяющую этот треугольник на два одинаковых треугольника (OO ').Маленький треугольник имеет те же углы, что и большой, и его стороны пропорциональны.Вы используете соотношение между AO и AB, чтобы разделить AC и получить длину OO '(позиция y на строке для этого 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 в вашем массиве точек отсортированы по возрастанию (например, ваш путь идет только слева направо)
Грязный взлом, который приходит на ум, состоит в том, чтобы перебирать пары точек и сохранять значения Y в таблице поиска. Количество циклов будет «деталью линии»
Опять же, это меня смущает:
просто нужно оценивать массив точек (а не только 2) и в идеале
сплайновая кривая их, а не просто соединение точек
Итак, у вас есть несколько точек, но где появляется сплайн, так как вы упомянули 0 опорных точек?
НТН