计算要在Canvas上绘制的旋转线段的x,y坐标

时间:2011-11-18 21:09:20

标签: javascript math canvas trigonometry

这不是HTML,CANVAS问题,而是更多的一般数学问题。我在这里发布它是因为它是使用CANVAS的原型,并且仍然是我认为有人可以回答的一般编程问题。这是基本的想法:我想画一条10像素厚的线,但我不想使用标准的lineTo并设置笔画宽度。我想实际使用beginPath和lineTo绘制线条的边框。原因是这实际上是AS3项目,使用这种方法可以让我们进行线条笔划和填充。所以旋转帆布和那种性质的东西是不可能的。我只需要弄清楚如何计算线的正确x,y坐标。

在下面的代码中是一行顶部的坐标。我基本上想要取这个坐标,为每个坐标添加10到y轴,这将给出行底部的返回坐标。当然,线的每个部分都是旋转的,因此计算线底部的坐标已经证明是棘手的。我希望有人可以提供帮助。

运行示例代码后,问题应该很明显。该线未正确绘制。对于相对温和的线段旋转,它似乎有效,但随着旋转角度越来越严重,x,y坐标计算错误。

<!doctype html>
<html>
<body>
<canvas id="canvas" width="800" height="600">
</canvas>
<script type="text/javascript">
var coords = [
    {x:78,y:183},
    {x:130,y:183},
    {x:237,y:212},
    {x:450,y:213},
    {x:517,y:25},
    {x:664,y:212},
    {x:716,y:212}
];

var coordsBck = [];

for( i = 0; i < coords.length; i++ ) {
    var c1, c2, r;
    c1 = coords[i];

    if( i < coords.length - 1 ) {
        c2 = coords[i + 1];
        r = Math.atan2((c2.y - c1.y),(c2.x - c1.x));
        console.log( c1.x, c1.y, c2.x, c2.y, ( r * 180/Math.PI ));
    }
    else
    {
        r = 00;
    }
    var d = r * 180/Math.PI;    
    var cos = Math.cos( r );
    var sin = Math.sin( r );

    var x = cos * 0 - sin * 10;
    var y = sin * 0 + cos * 10;
    coordsBck.push({x: c1.x + x, y: c1.y + y});
}

while(coordsBck.length > 0 )
{
    coords.push( coordsBck.pop() );
}

var ctx = document.getElementById("canvas").getContext("2d");
ctx.beginPath();
for( i = 0; i < coords.length; i++ ) {
    var line = coords[i];
    console.log( i, line.x, line.y );
    if( i == 0 )
    {
        ctx.moveTo( line.x, line.y );
    }
    else
    {
        ctx.lineTo( line.x, line.y );
    }
}
ctx.fill();

function t(o) {
    return "x: " + o.x + ", y: " + o.y;
}
</script>
</body>
</html>

3 个答案:

答案 0 :(得分:1)

当我遇到这样的问题时,我通常会计算规范化的向量,并用它们“玩”。 假设您从A到B绘制一条线,计算AB矢量(ABx = Bx-Ax; ABy = By-Ay)然后我将其标准化(...)以获得ABN。

然后我计算ABNR,ABN的90度旋转(ABNR.x = -ABN.y; ABNR.y = ABN.x)

然后在你的例子中,说A'和A''是围绕A的点,我们有简单的A'= A + 5 * ABNR和A''= A-5 * ABNR,以及B'= B + 5 * ABNR和B''= B-5 * ABNR。 你想要绘制的矩形是A'A''B''B'矩形。

必须有更多优化的方法来做到这一点(毕竟,人们可以画一条只添加的线),这个很简单并且有效,这取决于你的速度要求。一旦配方工作,您也可以优化代码。

答案 1 :(得分:1)

如果您不需要端盖。 http://jsfiddle.net/xA6kB/1/

<doctype !html>
<html>
<body>
<canvas id="canvas" width="800" height="600">
</canvas>
<script type="text/javascript">
var points =
[
    {x: 78, y: 183},
    {x: 130, y: 183},
    {x: 237, y: 212},
    {x: 450, y: 213},
    {x: 517, y: 25},
    {x: 664, y: 212},
    {x: 716, y: 212}
];

var quads = [];
var lineThickness = 10;

// Remove the -1 to create a loop
for (var i = 0; i < points.length - 1; ++i)
{
    var point = points[i];
    var nextPoint = points[(i + 1) % points.length];
    // Right hand normal with x positive to the right and y positive down
    var normal = {x: -(nextPoint.y - point.y), y: nextPoint.x - point.x};
    // Normalize normal
    var normalLength = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
    normal.x /= normalLength;
    normal.y /= normalLength;

    // A quad has 4 points
    quads.push({x: point.x - lineThickness / 2 * normal.x, y: point.y - lineThickness / 2 * normal.y});
    quads.push({x: nextPoint.x - lineThickness / 2 * normal.x, y: nextPoint.y - lineThickness / 2 * normal.y});
    quads.push({x: nextPoint.x + lineThickness / 2 * normal.x, y: nextPoint.y + lineThickness / 2 * normal.y});
    quads.push({x: point.x + lineThickness / 2 * normal.x, y: point.y + lineThickness / 2 * normal.y});
}

var context = document.getElementById("canvas").getContext("2d");

context.beginPath();
for(var i = 0; i < quads.length; i += 4)
{
    context.moveTo(quads[i].x, quads[i].y);
    context.lineTo(quads[i + 1].x, quads[i + 1].y);
    context.lineTo(quads[i + 2].x, quads[i + 2].y);
    context.lineTo(quads[i + 3].x, quads[i + 3].y);
}
context.fill();
</script>
</body>
</html>

答案 2 :(得分:0)

在文森特和Sirisian的答案给了我一些想法后,我最终把它排除在外。我非常感谢输入的人!基本上,这两个答案让我意识到我应该像矩形一样对待片段,我需要一些额外的坐标。如果有人感兴趣,我会把一个小伙子放在一起。

http://jsfiddle.net/WesleyJohnson/sAaM9/1/