【问题标题】:Calculate x, y coordinates of rotated line segments to draw on a Canvas计算旋转线段的X,Y坐标,以绘制帆布
【发布时间】:2012-01-01 14:47:01
【问题描述】:

这不是 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>

【问题讨论】:

    标签: javascript math canvas trigonometry


    【解决方案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>
    

    【讨论】:

    • 我确实需要端盖,但是看着你的回答让我意识到我需要将线段更像矩形来处理,这有助于确定额外的我最终需要的坐标。所以谢谢。 :)
    • 我最终没有使用它,但它确实帮助我到达了我需要的地方,所以我选择它作为答案。为了看看我想出了什么,我在下面回答了我自己的问题。或者您可以查看 jsfiddle:jsfiddle.net/WesleyJohnson/sAaM9/1
    • 嗬,因为我在那个时候工作,你想知道如何制作一个平滑的关节吗?因为您可能已经注意到,坡度不同的两个段有一个可怕的关节,只有矩形绘图(有点 PS1 看起来 :=))
    【解决方案2】:

    当我遇到此类问题时,我通常会计算归一化向量,并与它们“玩耍”。 假设您从 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' 矩形。

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

    【讨论】:

    • 嗨文森特!我很感激你的回答,我有点理解你的意思,但数学有点超出我的想象。我认为 Sirisian 基本上按照你的意思做了,但他实际上把代码写出来了。你的回答解释了这个概念,他的回答写出来了,这对我有很大帮助。谢谢!
    • 太糟糕了,我不能画画,因为画画太明显了。很高兴我能帮上忙:=)
    【解决方案3】:

    在 Vincent 和 Sirisian 的回答给了我一些想法之后,我最终解决了这个问题。我真的很感谢输入的家伙!基本上,这两个答案都让我意识到我应该像矩形一样对待这些线段,并且我需要一些额外的坐标。如果有人感兴趣,我整理了一个 jsfiddle。

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

    【讨论】:

    • 谢谢伙计,用笔和纸解决所有这些问题,您可能会节省我一些时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 2022-01-23
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    相关资源
    最近更新 更多