从角落旋转方形后计算偏移量 [英] Calculating offsets after square rotated from corner

查看:139
本文介绍了从角落旋转方形后计算偏移量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我旋转一个正方形时,我想计算旋转点的4个偏移。

I am wanting to calculate the 4 offsets from the point of rotation when I rotate a square.

旋转轴最初是方形的左上角。当我执行旋转时,我想知道形状在所有4个方向上的长度(minX,minY,maxX,maxy)。

The axis of rotation is initially the top left of the square. When I perform a rotation I would like to know how far the shape will spead in all 4 directions (minX, minY, maxX, maxy).

我目前有一般数学:

const rotation = .35  // radians = 20 degrees
const size = 50 // size of original square

const o1 = Math.round(size * Math.sin(rotation))
const o2 = Math.round(size * Math.cos(rotation))

使用这些数字,我看到如何使用它们来创建偏移数组

Using these numbers I see how I can use them to create an array of offsets

const offsets = [o1, 0, o2, o1 + o2]

当我将方块从20度,110度,200度和290度旋转时,它将围绕图像上黑点标记的轴旋转。

When I rotate my square from 20, 110, 200 and 290 degrees it will rotate around the axis marked by the black dot on image.

对于4个旋转中的每一个,我都有offests数组以及实际的麻木我想要的。正如你所看到的那样,数字有点......但我最初认为阵列转换是我所需要的,但不仅如此。

For each of the 4 rotations I have the offests array as well as the actual numbers that I desire. As you can see the numbers are sort of there but... I initially thought an array shift was all I needed but its more than that.

// 20 degrees
console.log(offsets) // [17, 0, 47, 64] 
// The dimensions I actually need
// minX: -17,
// minY: 0
// maxX: 47
// maxY: -64

// 110 degrees
console.log(offsets) // [47, 0, -17, 30] 
// The dimensions I actually need
// minX: -64,
// minY: -17,
// maxX: 0,
// maxY: 47

// 200 degrees
console.log(offsets) // [-17, 0, -47, -64] 
// The dimensions I actually need
// minX: -47,
// minY: -64,
// maxX: 17,
// maxY: 0

// 290 degrees
console.log(offsets) // [-47, 0, 17, -30] 
// The dimensions I actually need
// minX: 0,
// minY: -47,
// maxX: 64,
// maxY: 17

如果需要,我当然可以移动阵列(比如说每90度),但我怎么能得到这个正确的号码?我正在寻找任何角度的神奇公式。

I can certainly shift the array if needed (say for every 90deg) but how can I get the correct numbers? I'm looking for the magic formula for any angle.

推荐答案

转换点



最简单的方法是创建一个简单的旋转矩阵。这只是x和y轴的方向,作为向量,每个向量的长度大小为像素(或任何可能的单位)和原点的位置。

Transforming points

The easiest way to do this is create a simple rotation matrix. This is just the direction of the x and y axis as vectors each with a length the size of a pixel (or unit whatever that may be) and the location of the origin.

首先定义点

var x = ?;  // the point to rotate
var y = ?;

然后原点和轮换

const ox = ?; // location of origin
const oy = ?;
const rotation = ?; // in radians

从旋转我们计算出的向量是x轴的方向

From the rotation we calculate to vector that is the direction of the x axis

var xAxisX = Math.cos(rotation);
var xAxisY = Math.sin(rotation);

除此之外你也可以有一个比例

Optionally you could have a scale as well

const scale = ?;

会改变x轴和y轴的长度,因此x轴计算

that would change the length of the x and y axis so the x axis calculation is

var xAxisX = Math.cos(rotation) * scale;
var xAxisY = Math.sin(rotation) * scale;

我们不能将轮换应用到该点。首先移动相对于原点的点。

No we can apply the rotation to the point. First move the point relative to the origin.

x -= ox;
y -= oy;

然后沿x轴移动点x距离

Then move the point x distance along the x axis

var rx = x * xAxisX;
var ry = x * xAxisY;

然后沿y轴移动y距离。 y轴与x顺时针成90度。要旋转任何矢量90deg,您可以交换x和y并取消新的x。因此沿y轴移动如下

Then move y distance along the y axis. The y axis is at 90 deg clockwise from the x. To rotate any vector 90deg you swap the x and y and negate the new x. Thus moving along the y axis is as follows

rx -= y * xAxisY;  // use x axis y for y axis x and negate
ry += y * xAxisX;  // use x axis x for y axis y 

现在该点已经旋转但仍然相对于起源,我们需要把它移回世界空间。要做到这一点,只需添加原点

Now the point has been rotated but is still relative to the origin, we need to move it back to the world space. To do that just add the origin

rx += ox;
ry += oy;

并且rx,ry是原点周围的旋转点,如果你这样做,则缩放。

And rx,ry is the rotated point around the origin, and scaled if you did that.

您可以获取2D上下文为您执行相同的操作

You can get the 2D context to do the same for you

ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, ox, oy);
ctx.fillRect(x,y,1,1); // draw the rotated pixel
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform

或者你可以通过函数调用添加旋转

Or you can add the rotation via a function call

ctx.setTransform(1, 0, 0, 1, ox, oy);
ctx.rotate(rotation);
// and if scale then 
// ctx.scale(scale,scale)
ctx.fillRect(x,y,1,1); // draw the rotated pixel
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform

上面的各个步骤可以压缩,答案的下一部分会旋转一个使用上述方法的矩形。

The various steps above can be compacted, the next part of the answer rotates a rectangle using the above method.

以下函数将返回4个旋转的角。 / p>

The following function will return the 4 rotated corners.

// angle is the amount of rotation in radians
// ox,oy is the origin (center of rotation)
// x,y is the top left of the rectangle
// w,h is the width and height of the rectangle
// returns an array of points as arrays [[x,y],[x1,y1],...]
// Order of returned points topLeft, topRight, bottomRight, bottomLeft
function rotateRect(angle,ox,oy,x,y,w,h){
    const xAx = Math.cos(angle);  // x axis x
    const xAy = Math.sin(angle);  // x axis y
    x -= ox;  // move rectangle onto origin
    y -= oy; 
    return [[ // return array holding the resulting points
            x * xAx - y * xAy + ox,   // Get the top left rotated position
            x * xAy + y * xAx + oy,   // and move it back to the origin
        ], [
            (x + w) * xAx - y * xAy + ox,   // Get the top right rotated position
            (x + w) * xAy + y * xAx + oy,   
        ], [
            (x + w) * xAx - (y + h) * xAy + ox,   // Get the bottom right rotated position
            (x + w) * xAy + (y + h) * xAx + oy,   
        ], [
            x * xAx - (y + h) * xAy + ox,   // Get the bottom left rotated position
            x * xAy + (y + h) * xAx + oy,   
        ]
    ]; 
}



查找抵消额



使用函数

Finding the offsets

To use the function

var angle = 1;  // amount to rotate in radians
var ox = 0;   // origin top left of rectangle
var oy = 0; 
const rotatedRect = rotateRect(angle,ox,oy,0,0,50,50);
const r = rotatedRect; // alias to make following code more readable
var leftOfOrigin  = Math.min(r[0][0],r[1][0],r[2][0],r[3][0]) - ox;
var rightOfOrigin = Math.max(r[0][0],r[1][0],r[2][0],r[3][0]) - ox;
var aboveOrigin   = Math.min(r[0][1],r[1][1],r[2][1],r[3][1]) - oy;
var belowOrigin   = Math.max(r[0][1],r[1][1],r[2][1],r[3][1]) - oy;

我将距离计算保留在函数外部,因为您可能需要更多信息,因为它更有用关于旋转点。

I keep the distance calcs outside the function as that is a little more useful as you may want more information about the rotated points.

例如

const ctx = canvas.getContext("2d");
canvas.width = 512;
canvas.height = 512;



// angle is the amount of rotation in radians
// ox,oy is the origin (center of rotation)
// x,y is the top left of the rectangle
// w,h is the width and height of the rectangle
// returns an array of points as arrays [[x,y],[x1,y1],...]
// Order of returned points topLeft, topRight, bottomRight, bottomLeft
function rotateRect(angle,ox,oy,x,y,w,h){
    const xAx = Math.cos(angle);  // x axis x
    const xAy = Math.sin(angle);  // x axis y
    x -= ox;  // move rectangle onto origin
    y -= oy; 
    return [[ // return array holding the resulting points
            x * xAx - y * xAy + ox,   // Get the top left rotated position
            x * xAy + y * xAx + oy,   // and move it back to the origin
        ], [
            (x + w) * xAx - y * xAy + ox,   // Get the top right rotated position
            (x + w) * xAy + y * xAx + oy,   
        ], [
            (x + w) * xAx - (y + h) * xAy + ox,   // Get the bottom right rotated position
            (x + w) * xAy + (y + h) * xAx + oy,   
        ], [
            x * xAx - (y + h) * xAy + ox,   // Get the bottom left rotated position
            x * xAy + (y + h) * xAx + oy,   
        ]
    ]; 
}
function drawRectangle(angle, ox, oy, rect){
    ctx.strokeStyle = "red";
    ctx.lineWidth = 2;
    ctx.setTransform(1,0,0,1,ox,oy);
    ctx.rotate(angle);
    ctx.strokeRect(rect.x - ox, rect.y - oy, rect.w, rect.h);
    ctx.setTransform(1,0,0,1,0,0); // restore transform to default
}
function drawBounds(rotatedRect){
    const r = rotatedRect; // alias to make following code more readable
    const left     = Math.min(r[0][0], r[1][0], r[2][0], r[3][0]);
    const right    = Math.max(r[0][0], r[1][0], r[2][0], r[3][0]);
    const top      = Math.min(r[0][1], r[1][1], r[2][1], r[3][1]);
    const bottom   = Math.max(r[0][1], r[1][1], r[2][1], r[3][1]);

    ctx.strokeStyle = "#999";
    ctx.lineWidth = 2;
    ctx.strokeRect(left, top, right - left, bottom - top);
}

function drawDistance(text,x,y,dist,direction,textOverflowDir){
    if(dist.toFixed(2) == 0) { return }
    function drawArrows(){
        ctx.strokeStyle = "blue";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.lineTo(8,-12);
        ctx.lineTo(0,-7);
        ctx.lineTo(8,-2);
        ctx.moveTo(dist - 8, -12);
        ctx.lineTo(dist, -7);
        ctx.lineTo(dist - 8, -2);
        ctx.stroke();
    }
    
    
    ctx.setTransform(1,0,0,1,x,y);
    ctx.rotate(direction);
    const width = ctx.measureText(text).width;
    ctx.fillStyle = "blue";
    ctx.fillRect(-1, - 16, 2, 14);
    ctx.fillRect(dist -1,  - 16, 2, 14);
    if(width + 8 > dist){
        ctx.fillRect(1, -8, dist - 2, 2);
        drawArrows();
        ctx.fillStyle = "black";
        if(textOverflowDir < 0){
            ctx.fillText(text, - width / 2 - 4, - 9);
        }else{
            ctx.fillText(text,dist + width / 2 + 6, - 9);
        }
    }else{
        ctx.fillRect(-1,       - 8, (dist - width) / 2 - 4, 2);
        ctx.fillRect(dist - 1 - ((dist - width) / 2 - 4), - 8, (dist - width) / 2 - 4, 2);
        drawArrows();
        
        ctx.fillStyle = "black";
        ctx.fillText(text, dist / 2, - 9);
    }
    ctx.setTransform(1,0,0,1,0,0); //restore default transform
}
// set up the font
ctx.font = "16px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";

var angle = 3.2;  // amount to rotate in radians
var ox = 256;   // origin top left of rectangle
var oy = 256; 
const rect = {
    x : 256,
    y : 256,
    w : 164,
    h : 164,
}




function mainLoop(){
    ctx.clearRect(0,0,512,512);
    angle += 0.01; // slowly rotate 
    // draw origin 
    ctx.fillStyle = "#FA2";
    ctx.fillRect(ox-1,0,2,512);
    ctx.fillRect(0,oy-1,512,2);
    
    const rotatedRect = rotateRect(angle, ox, oy, rect.x, rect.y, rect.w, rect.h);
    drawBounds(rotatedRect);
    drawRectangle(angle, ox, oy, rect);
    
    const r = rotatedRect; // alias to make following code more readable
    var leftOfOrigin  = Math.min(r[0][0],r[1][0],r[2][0],r[3][0]) - ox;
    var rightOfOrigin = Math.max(r[0][0],r[1][0],r[2][0],r[3][0]) - ox;
    var aboveOrigin   = Math.min(r[0][1],r[1][1],r[2][1],r[3][1]) - oy;
    var belowOrigin   = Math.max(r[0][1],r[1][1],r[2][1],r[3][1]) - oy;
    
    // draw distances
    
    drawDistance(leftOfOrigin.toFixed(2), ox + leftOfOrigin, oy +aboveOrigin, - leftOfOrigin, 0, -1);
    drawDistance(rightOfOrigin.toFixed(2), ox, oy + aboveOrigin, rightOfOrigin, 0, 1);
    drawDistance(belowOrigin.toFixed(2), ox + leftOfOrigin, oy + belowOrigin,  belowOrigin, - Math.PI / 2, -1);
    drawDistance(aboveOrigin.toFixed(2), ox + leftOfOrigin, oy, - aboveOrigin, - Math.PI / 2, 1);

    requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);

canvas { border : 2px solid black; }

<canvas id="canvas"></canvas>

这篇关于从角落旋转方形后计算偏移量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆