简体   繁体   English

如何从矩形点计算旋转角度?

[英]How to calculate rotation angle from rectangle points?

I have 4 points 1 , 2 , 3 , 4 that closes a rectangle.我有 4 个点1 , 2 , 3 , 4闭合一个矩形。

The points are in a array in this following way: x1 y1 x2 y2 x3 y3 x4 y4这些点以如下方式排列在一个数组中: x1 y1 x2 y2 x3 y3 x4 y4

The problem I have is that the rectangle can be rotated in a angle.我的问题是矩形可以旋转一个角度。

How can I calculate the original points (gray outline), and the angle?如何计算原始点(灰色轮廓)和角度?

在此处输入图片说明

I'm trying to reproduce this effect in javascript+css3-transform, so I need to first know the straight dimensions and then rotate with the css.我试图在 javascript+css3-transform 中重现这种效果,所以我需要先知道直线尺寸,然后用 css 旋转。

I just know if the rectangle is straight by comparing points eg y1==y2我只是通过比较点来知道矩形是否是直的,例如y1==y2

if(x1==x4 && x2==x3 && y1==y2 && y4==y3){

    rectangle.style.top = y1;
    rectangle.style.left = x1;
    rectangle.style.width = x2-x1;
    rectangle.style.height = y4-y1;
    rectangle.style.transform = "rotate(?deg)";

}

You can use any coordinate pair on the same side to calculate the rotation angle.您可以使用同一侧的任何坐标对来计算旋转角度。 Note that mathematic angles normally assume 0 as long the +ve X axis and increase by rotating anti–clockwise (so along the +ve Y axis is 90°, -ve X axis is 180° and so on).请注意,数学角度通常假定为 0,只要 +ve X 轴越长,并通过逆时针旋转而增加(因此沿 +ve Y 轴为 90°,-ve X 轴为 180°,依此类推)。

Also, javascript trigonometry functions return values in radians that must be converted to degrees before being used in a CSS transform.此外,javascript 三角函数返回以弧度表示的值,在用于 CSS 转换之前必须将其转换为度数。

If the shape is not rotated more than 90°, then life is fairly simple and you can use the tanget ratio of a right angle triangle:如果形状旋转不超过 90°,那么生活就相当简单,您可以使用直角三角形的切线比:

tan(angle) = length of opposite side / length of adjacent side

For the OP, the best corners to use are 1 and 4 so that rotation is kept in the first quadrant and clockwise (per thedraft CSS3 spec ).对于 OP,最好使用 1 和 4 角,以便将旋转保持在第一象限和顺时针方向(根据CSS3 规范草案)。 In javascript terms:在 JavaScript 术语中:

var rotationRadians = Math.atan((x1 - x4) / (y1 - y4));

To convert to degrees:转换为度数:

var RAD2DEG = 180 / Math.PI;
var rotationDegrees = rotationRadians * RAD2DEG;

If the rotation is more than 90°, you will need to adjust the angle.如果旋转超过 90°,则需要调整角度。 eg where the angle is greater than 90° but less than 180°, you'll get a -ve result from the above and need to add 180°:例如,当角度大于 90° 但小于 180° 时,您会从上面得到 -ve 结果,需要加上 180°:

  rotationDegrees += 180;

Also, if you are using page dimentions, y coordinates increase going down the page, which is the opposite of the normal mathetmatic sense so you need to reverse the sense of y1 - y4 in the above.此外,如果您使用页面尺寸,则 y 坐标会随着页面向下而增加,这与正常的数学意义相反,因此您需要反转上述y1 - y4的意义。

Edit编辑

Based on the orientation of points in the OP, the following is a general function to return the center and clockwise rotation of the rectangle in degrees.基于OP中点的方向,下面是一个通用函数,以度数为单位返回矩形的中心和顺时针旋转。 That's all you should need, though you can rotate the corners to be "level" yourself if you wish.这就是您所需要的全部内容,但如果您愿意,您可以自己旋转角以使其“水平”。 You can apply trigonometric functions to calculate new corners or just do some averages (similar to Ian's answer).您可以应用三角函数来计算新的角或只是做一些平均值(类似于伊恩的回答)。

/** General case solution for a rectangle
 *
 *  Given coordinages of [x1, y1, x2, y2, x3, y3, x4, y4]
 *  where the corners are:
 *            top left    : x1, y1
 *            top right   : x2, y2
 *            bottom right: x3, y3
 *            bottom left : x4, y4
 *
 *  The centre is the average top left and bottom right coords:
 *  center: (x1 + x3) / 2 and (y1 + y3) / 2
 *
 *  Clockwise rotation: Math.atan((x1 - x4)/(y1 - y4)) with
 *  adjustment for the quadrant the angle is in.
 *
 *  Note that if using page coordinates, y is +ve down the page which
 *  is the reverse of the mathematic sense so y page coordinages
 *  should be multiplied by -1 before being given to the function.
 *  (e.g. a page y of 400 should be -400).
 *
 * @see https://stackoverflow.com/a/13003782/938822
 */
function getRotation(coords) {
    // Get center as average of top left and bottom right
    var center = [(coords[0] + coords[4]) / 2,
                  (coords[1] + coords[5]) / 2];

    // Get differences top left minus bottom left
    var diffs = [coords[0] - coords[6], coords[1] - coords[7]];

    // Get rotation in degrees
    var rotation = Math.atan(diffs[0]/diffs[1]) * 180 / Math.PI;

    // Adjust for 2nd & 3rd quadrants, i.e. diff y is -ve.
    if (diffs[1] < 0) {
        rotation += 180;
      
    // Adjust for 4th quadrant
    // i.e. diff x is -ve, diff y is +ve
    } else if (diffs[0] < 0) {
        rotation += 360;
    }
    // return array of [[centerX, centerY], rotation];
    return [center, rotation];
}

The center of the rectangle is right between two opposite corners:矩形的中心位于两个对角之间:

cx = (x1 + x3) / 2
cy = (y1 + y3) / 2

The size of the rectangle is the distance between two points:矩形的大小是两点之间的距离:

w = sqrt(pow(x2-x1, 2) + pow(y2-y1, 2))
h = sqrt(pow(x3-x2, 2) + pow(y3-y2, 2))

The corners of the gray rectangle can be calculated from the center and the size, for example the top left corner:灰色矩形的角可以从中心和大小计算,例如左上角:

x = cx - w / 2
y = cy - h / 2

The angle is the arctangent of a side of the square:角是正方形边的反正切:

a = arctan2(y4 - y1, x4 - x1)

(I'm not sure exactly which angle it returns, or what angle you expect for that matter, so you get to test a bit.) (我不确定它返回的是哪个角度,或者您对此期望的角度是什么,因此您可以稍微测试一下。)

This is how you get the angle between the vertical pink line and the black line starting at the pink line intersection:这是您如何从粉红色线交叉点开始获得垂直粉红色线和黑色线之间的角度:

var deg = 90 - Math.arctan((x2-x1) / (y2-y1));

The dimensions can be calculated with the help of the Pythagoras theorem:可以借助毕达哥拉斯定理计算维度:

var width = Math.sqrt((x2-x1)^2 / (y2-y1)^2));
var height = Math.sqrt((x1-x4)^2) / (y4-y1)^2));

The positional coordinates (left and top) are the averages of x1 and x3 and y1 and y3 respectively.位置坐标(左和上)分别是 x1 和 x3 以及 y1 和 y3 的平均值。

var left = Math.floor((x1 + x3) / 2);
var top = Math.floor((y1 + y3) / 2);

You want to use the negative-margin trick.您想使用负边距技巧。

var marginLeft = -Math.ceil(width / 2);
var marginTop = -Math.ceil(height / 2);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM