在两点之间绘制一条平滑的弧形弧()

时间:2013-12-03 14:22:13

标签: javascript html5 math canvas

我正在尝试在画布中的两个点之间绘制一个平滑的弧形弧,我将这些点设置为sutch note 这些是动态的并且可以改变。

var p1 = {
    x=100, y=100 
}

var p2 = {
    x=255, y=255
}

曲线看起来像这样

curves

这里是我开始的代码,我无法理解这个函数的数学/逻辑:

function curveA2B(a,b){

    var mindpoint = {
        x: (a.x+b.x)/2,
        y: (a.y+b.y)/2,
        d: Math.sqrt(Math.pow(b.x-a.x,2) + Math.pow(b.y-a.y,2))
    };

    context.beginPath();
    context.arc(
        a.x,
        a.y,
        mindpoint.d/2,
        1.5*Math.PI,
        0,
        false
    );

    context.arc(
        b.x,
        b.y,
        mindpoint.d/2,
        1*Math.PI,
        0.5*Math.PI,
        true
    );

    context.context.stroke();

}

动态示例如下: http://jsfiddle.net/CezarisLT/JDdjp/6/

2 个答案:

答案 0 :(得分:2)

我创建了一个可以轻松修改的函数,名为plot_curve,可以让您了解问题的细分。

快速 DEMO http://jsfiddle.net/LVFat/

function plot_curve(x,y,xx,yy, target,color)
{
    var startX=x;  
    var startY=y;  

    var endX=xx;  
    var endY=yy;  

    var diff_x = xx - x;
    var diff_y = yy - y;


    var bezierX=x;  // x1
    var bezierY=yy; // y2

    console.log("bx:"+bezierX);
    console.log("by:"+bezierY); 

    var cx,cy, t;   

    for(t=0.0; t<=1; t+=0.01)  
    {  
        cx =  Math.round(  (1-t)*(1-t)*startX + 2*(1-t) * t * bezierX + t*t*endX);  
        cy =  Math.round(  (1-t)*(1-t)*startY + 2*(1-t) * t * bezierY + t*t*endY);  

        // change this part to whatever you are trying to manipulate to the curve
        plot_pixel( Math.round(cx), Math.round(cy), target, color);
    }  
}

示例...(使用我制作的divCanvas函数..查看jsfiddle链接...)

plot_curve(25,25,5,5, ".divCanvas","blue");

如果你只想要两点之间曲线的坐标,请试试这个:

function plot_curve(x,y,xx,yy)
{
    // returns an array of x,y coordinates to graph a perfect curve between 2 points.
    var startX=x;  
    var startY=y;  

    var endX=xx;  
    var endY=yy;  

    var diff_x = xx - x;
    var diff_y = yy - y;

    var xy = [];
    var xy_count = -1;

    var bezierX=x;  // x1
    var bezierY=yy; // y2

    var t;   

    for(t=0.0; t<=1; t+=0.01)  
    {
      xy_count++;
      xy[xy_count] = {};
      xy[xy_count].x = Math.round(  (1-t)*(1-t)*startX + 2*(1-t) * t * bezierX + t*t*endX);
      xy[xy_count].y = Math.round(  (1-t)*(1-t)*startY + 2*(1-t) * t * bezierY + t*t*endY);
    }

    return xy; // returns array of coordinates
}

答案 1 :(得分:1)

您可以将两点的中间值用作x轴和y轴的两个半径设置。

以下示例已经过简化,但它显示了一种在方框内创建平滑曲线的方法,如示例所示。

这些框将始终缩放,以便曲线穿过两点之间的中点(例如,改变终点)。

DEMO

Snapshot from demo

/// set up some values
var ctx = demo.getContext('2d'),
    p1 = {x:100, y:100},           /// point 1
    p2 = {x:355, y:255},           /// point 2
    mx = (p2.x - p1.x) * 0.5,      /// mid-point between point 1 and 2
    my = (p2.y - p1.y) * 0.5,
    c1 = {x: p1.x, y: p1.y + my},  /// create center point objects
    c2 = {x: p2.x, y: p2.y - my},
    steps = 0.05;                  /// curve resolution

/// mark the points and the boxes which represent the center of those
ctx.fillStyle = '#ff6e6e';
ctx.fillRect(p1.x, p1.y, mx, my);

ctx.fillStyle = '#6e93ff';
ctx.fillRect(p1.x + mx, p1.y + my, mx, my);

然后我们为每个“框”渲染四分之一椭圆:

/// render the smooth curves using 1/4 ellipses    
ctx.beginPath();

for(var isFirst = true,            /// first point is moveTo, rest lineTo
        angle = 1.5 * Math.PI,     /// start angle in radians
        goal = 2 * Math.PI,        /// goal angle
        x, y; angle < goal; angle += steps) {

    /// calculate x and y using cos/sin
    x = c1.x + mx * Math.cos(angle);
    y = c1.y + my * Math.sin(angle);

    /// move or draw line
    (isFirst) ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    isFirst = false;
}

/// second box    
for(var isFirst = true,
        angle = Math.PI,
        goal = 0.5 * Math.PI,
        x, y;angle > goal; angle -= steps) {

    x = c2.x + mx * Math.cos(angle);
    y = c2.y + my * Math.sin(angle);

    (isFirst) ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    isFirst = false;
}
ctx.stroke();

我会留给你把它放到可重复使用的功能中。希望这有帮助!

如果这没有削减它,我建议你看一下我的cardinal spline implementation