Вычислить координаты x, y повернутых отрезков для рисования на холсте - PullRequest
2 голосов
/ 19 ноября 2011

Это не вопрос HTML, CANVAS, а скорее вопрос математики.Я разместил его здесь, потому что он создан на прототипе с использованием CANVAS и все еще является своего рода общим вопросом программирования, на который, я думал, кто-то может ответить.Вот основная идея: я хочу нарисовать линию толщиной 10 пикселей, но я не хочу использовать стандартную линию для установки ширины обводки.Я хочу на самом деле нарисовать границу линии, используя 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 ]

1 голос
/ 19 ноября 2011

Если вам не нужны заглушки. 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>
1 голос
/ 19 ноября 2011

Когда у меня возникают такие проблемы, я обычно вычисляю нормализованные векторы и «играю» с ними. Скажем, вы рисуете линию от 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 '.

Должен быть гораздо более оптимизированный способ сделать это (в конце концов, можно нарисовать линию только с дополнениями), этот простой и работает, это зависит от ваших требований к скорости. Вы также можете оптимизировать код после того, как заработаете формулы.

0 голосов
/ 19 ноября 2011

Я закончил разбираться с этим после того, как ответы Винсента и Сирисяна дали мне некоторые идеи. Я действительно ценю вклад ребята! По сути, оба этих ответа заставили меня понять, что я должен рассматривать сегменты как прямоугольники и что мне нужны некоторые дополнительные координаты. Я собрал jsfiddle, если кому-то было интересно.

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

...