Как я могу изменить свой код, чтобы он проходил через контрольные точки Безье?

Всем привет -

Я использую точки привязки и контрольные точки для создания формы с помощью curveTo. Все работает нормально, но я не могу понять, как заставить мои линии проходить через центр контрольных точек (синие точки), когда линия не прямая.

Вот мой код для рисования фигуры:

           // clear old line and draw new / begin fill
        var g:Graphics = graphics;
        g.clear();
        g.lineStyle(2, 0, 1);
        g.beginFill(0x0099FF,.1);

        //move to starting anchor point
        var startX:Number = anchorPoints[0].x;
        var startY:Number = anchorPoints[0].y;
        g.moveTo(startX, startY);

        // Connect the dots
        var numAnchors:Number = anchorPoints.length;
        for (var i:Number=1; i<numAnchors; i++) {

            // curve to next anchor through control
            g.curveTo(controlPoints[i].x,controlPoints[i].y, anchorPoints[i].x, anchorPoints[i].y);

        }
        // Close the loop
        g.curveTo(controlPoints[0].x,controlPoints[0].y,startX,startY);

И форма, которую я рисую для справки:

Как я могу изменить свой код, чтобы линии проходили прямо через синие контрольные точки?

Заранее спасибо!

b


person WillyCornbread    schedule 16.01.2010    source источник


Ответы (1)


Пример проекта Исходный код

Если вас не интересует, как это получается, перейдите к разделу ответов.

Исходная информация


Кривые Безье интересны и интересны в работе. Эта анимация показывает, как ваша квадратичная кривая рисуется между двумя опорными точками ( P0 и P2) во времени относительно контрольной точки (P1).

Что вам нужно сделать, вместо того, чтобы рисовать контрольную точку (P1), это нарисовать точку на кривой при t = 0,5:

Указать на t=0,5
(источник: whilenotnull.com)

К счастью, это легко сделать с помощью уравнения, приведенного на странице Википедии: http://en.wikipedia.org/wiki/Bezier_Curve#Quadratic_B.C3.A9zier_curves

Вот формула в ActionScript:

public function calculatePoint(p0:Point, p1:Point, p2:Point, t:Number):Point
{
    var p:Point = new Point(calculateTerm(p0.x, p1.x, p2.x, t), calculateTerm(p0.y, p1.y, p2.y, t));
    return p;
}

public function calculateTerm(p0:Number, p1:Number, p2:Number, t:Number):Number
{
    var negT:Number = 1 - t;

    var a0:Number = Math.pow(negT, 2) * p0;
    var a1:Number = 2 * negT * t * p1;
    var a2:Number = Math.pow(t, 2) * p2;

    var pos:Number = a0 + a1 + a2;
    return pos;
}

Итак, если вы подключите три точки: var t0:Point = calculatePoint(p0, p1, p2, 0.5);, вы получите точку на кривой, где вы хотите нарисовать свою «контрольную точку».


Отвечать

Теперь мы можем написать функцию, которая предполагает, что вторым параметром является точка на кривой, и определить координаты контрольной точки:

public function derivePoint(p0:Point, b1:Point, p2:Point, t:Number = 0.5):Point
{
    var p:Point = new Point(deriveTerm(p0.x, b1.x, p2.x, t), deriveTerm(p0.y, b1.y, p2.y, t));
    return p;
}

public function deriveTerm(p0:Number, bt:Number, p2:Number, t:Number):Number
{
    var negT:Number = 1 - t;

    var a0:Number = Math.pow(negT, 2) * p0;
    var a1:Number = 2 * negT * t;
    var a2:Number = Math.pow(t, 2) * p2;

    var p1:Number = (bt - a0 - a2) / a1;
    return p1;
}

Из этого я обновил ваш фрагмент кода, чтобы (надеюсь) нарисовать кривую через ваши «контрольные точки»:

// clear old line and draw new / begin fill
var g:Graphics = graphics;
g.clear();
g.lineStyle(2, 0, 1);
g.beginFill(0x0099FF,.1);

//move to starting anchor point
var startX:Number = anchorPoints[0].x;
var startY:Number = anchorPoints[0].y;
g.moveTo(startX, startY);

// Connect the dots
var p0:Point = new Point(startX, startY);
var p2:Point;

var numAnchors:Number = anchorPoints.length;
for (var i:Number=1; i<numAnchors; i++) {

    p2 = new Point(anchorPoints[i].x, anchorPoints[i].y);

    // curve to next anchor through control
    var b1:Point = new Point(controlPoints[i].x,controlPoints[i].y);
    var p1:Point = derivePoint(p0, b1, p2);

    g.curveTo(p1.x, p1.y, p2.x, p2.y);

    p0 = p2;

}
// Close the loop
g.curveTo(controlPoints[0].x,controlPoints[0].y,startX,startY);

Пример проекта Исходный код

person Sly_cardinal    schedule 16.01.2010
comment
Это, безусловно, самый полный и исчерпывающий ответ, который я когда-либо получал - спасибо за ваше время и особенно за дополнительную информацию, чтобы я мог понять «почему». б - person WillyCornbread; 16.01.2010
comment
Отличный ответ, здорово иметь всю информацию о том, как это работает, в дополнение к коду! - person Julien L; 23.03.2012