计算容器中旋转矩形的角
Calculate corners of rotated rectangle in container
我在计算旋转容器内旋转矩形的角时遇到一些问题,两个矩形都具有偏移 x/y 坐标。
枢轴已关闭,但我不确定解决方案。以下场景有效:
(x, y, rotation)
image = 0, 0, 45
container = 100, 100, 45
image = 200, 0, 45
container = 100, 100, 0
但是设置容器的旋转,图像坐标会弄乱枢轴,例如
image = 200, 0, 45
container = 100, 100, 45
下面是计算全局坐标中图像角点的代码space:
public get corners() {
const worldData = this.worldData;
//Get angle of object in radians;
const radAngle = worldData.rotation * Math.PI / 180;
const pivotX = worldData.pivotX;
const pivotY = worldData.pivotY;
const width = this.sourceWidth * worldData.scaleX;
const height = this.sourceHeight * worldData.scaleY;
const x = worldData.x;//this.x;
const y = worldData.y;//this.y;
//Get the corners
const c1 = this.getCorner(pivotX, pivotY, x, y, radAngle);
const c2 = this.getCorner(pivotX, pivotY, x + width, y, radAngle);
const c3 = this.getCorner(pivotX, pivotY, x + width, y + height, radAngle);
const c4 = this.getCorner(pivotX, pivotY, x, y + height, radAngle);
return {c1, c2, c3, c4};
}
public get worldData() {
let x = this.x;
let y = this.y;
let pivotX = this.x;
let pivotY = this.y;
let rotation = this.rotation;
let scaleX = this.scaleX;
let scaleY = this.scaleY;
let parent = this.parent;
while(parent) {
x += parent.x;
y += parent.y;
pivotX += parent.x;
pivotY += parent.y;
rotation += parent.rotation;
scaleX *= parent.scaleX;
scaleY *= parent.scaleY;
parent = parent.parent;
}
return {x, y, scaleX, scaleY, rotation, pivotX, pivotY}
}
protected getCorner(pivotX:number, pivotY:number, cornerX:number, cornerY:number, angle:number) {
let x, y, distance, diffX, diffY;
/// get distance from center to point
diffX = cornerX - pivotX;
diffY = cornerY - pivotY;
distance = Math.sqrt(diffX * diffX + diffY * diffY);
/// find angle from pivot to corner
angle += Math.atan2(diffY, diffX);
/// get new x and y and round it off to integer
x = pivotX + distance * Math.cos(angle);
y = pivotY + distance * Math.sin(angle);
return {x, y};
}
假设场景如下:
其中图像左下角(实线)的坐标为(x_i, y_i)
,容器左下角(虚线)的坐标为(X_c, Y_c)
。此外,图像(宽度 w
和高度 h
)相对于实验室框架逆时针旋转角度 beta
,而容器本身旋转(也是逆时针) 按角度 alpha
.
现在,让我们以右上角为例P
。相对于实验室坐标系(全局canvas),其坐标可以表示为:
R(beta) . ( w, h ) + ( x_i, y_i )
其中.
表示矩阵相乘,R
为逆时针旋转矩阵
R(beta) = [ cos(beta) -sin(beta) ]
[ sin(beta) cos(beta) ]
现在,我们需要将其转换为相对于容器的坐标系。形式上,这意味着我们需要先减去偏移量,然后顺时针旋转 -alpha
(或 alpha
)。因此,一切都在一起:
R(-alpha).( R(beta) . (w, h) + (x_i, y_i) - (X_c, Y_c) )
其他角可以类似处理,只需将 (w, h)
替换为适当的坐标...
就代码而言,可以将这些公式实现为:
//counter-clock-wise rotation by given angle in degrees
function rotateCCWBy(angle, {x, y}) {
const angle_rad = angle * Math.PI / 180;
const cos_a = Math.cos(angle_rad),
sin_a = Math.sin(angle_rad);
return {
x: cos_a * x - sin_a * y,
y: sin_a * x + cos_a * y
};
}
//shift by a multiple fac of an offset {xref, yref}
function offsetBy(fac, {x:xref, y:yref}, {x, y}) {
return {
x: fac*xref + x,
y: fac*yref + y
};
}
const image = {
coords: {x: 200, y: 0}, //lab-frame coordinates
angle: 45, //lab-frame rotation angle
width: 50,
height: 10
};
const container = {
coords: {x: 100, y: 100}, //lab-frame coordinates
angle: 45 //lab-frame rotation angle
};
//calculate the coordinates of the image's top-right corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
offsetBy(
-1, container.coords,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
console.log(corner);
编辑:
如果 y 轴应该指向 "downwards",上面的公式也适用,只需要将角度解释为顺时针而不是逆时针(因此原则上函数rotateCCWBy
应重命名为 rotateCWBy
)。例如,让我们考虑这种情况:
此处,容器的左上角位于位置 (2,1),容器本身旋转了 15 度。宽度为 4、高度为 2 的图像(黑色矩形)旋转了 30 度,其左上角位于位置 (3, 3)。现在,我们要计算点 P 相对于容器的坐标 (x, y)
。
使用:
const image = {
coords: {x: 3, y: 3}, //lab-frame coordinates
angle: 30, //lab-frame rotation angle
width: 4,
height: 2
};
const container = {
coords: {x: 2, y: 1}, //lab-frame coordinates
angle: 15 //lab-frame rotation angle
};
//calculate the coordinates of the image's top-left corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
offsetBy(
-1, container.coords,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
console.log(corner);
产量
{ x: 4.8296291314453415, y: 4.640160440463835 }
从附图中可以(大致)目测验证。
编辑 2:
添加clarification后,图像的坐标不应该是"lab-frame"(即相对于canvas),而是相对于已经旋转的容器.因此,转换需要调整为:
const corner =
offsetBy(
+1, container.coords,
rotateCCWBy(container.angle,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
function rotateCCWBy(angle, {x, y}) {
const angle_rad = angle * Math.PI / 180;
const cos_a = Math.cos(angle_rad),
sin_a = Math.sin(angle_rad);
return {
x: cos_a * x - sin_a * y,
y: sin_a * x + cos_a * y
};
}
我在计算旋转容器内旋转矩形的角时遇到一些问题,两个矩形都具有偏移 x/y 坐标。
枢轴已关闭,但我不确定解决方案。以下场景有效:
(x, y, rotation)
image = 0, 0, 45
container = 100, 100, 45
image = 200, 0, 45
container = 100, 100, 0
但是设置容器的旋转,图像坐标会弄乱枢轴,例如
image = 200, 0, 45
container = 100, 100, 45
下面是计算全局坐标中图像角点的代码space:
public get corners() {
const worldData = this.worldData;
//Get angle of object in radians;
const radAngle = worldData.rotation * Math.PI / 180;
const pivotX = worldData.pivotX;
const pivotY = worldData.pivotY;
const width = this.sourceWidth * worldData.scaleX;
const height = this.sourceHeight * worldData.scaleY;
const x = worldData.x;//this.x;
const y = worldData.y;//this.y;
//Get the corners
const c1 = this.getCorner(pivotX, pivotY, x, y, radAngle);
const c2 = this.getCorner(pivotX, pivotY, x + width, y, radAngle);
const c3 = this.getCorner(pivotX, pivotY, x + width, y + height, radAngle);
const c4 = this.getCorner(pivotX, pivotY, x, y + height, radAngle);
return {c1, c2, c3, c4};
}
public get worldData() {
let x = this.x;
let y = this.y;
let pivotX = this.x;
let pivotY = this.y;
let rotation = this.rotation;
let scaleX = this.scaleX;
let scaleY = this.scaleY;
let parent = this.parent;
while(parent) {
x += parent.x;
y += parent.y;
pivotX += parent.x;
pivotY += parent.y;
rotation += parent.rotation;
scaleX *= parent.scaleX;
scaleY *= parent.scaleY;
parent = parent.parent;
}
return {x, y, scaleX, scaleY, rotation, pivotX, pivotY}
}
protected getCorner(pivotX:number, pivotY:number, cornerX:number, cornerY:number, angle:number) {
let x, y, distance, diffX, diffY;
/// get distance from center to point
diffX = cornerX - pivotX;
diffY = cornerY - pivotY;
distance = Math.sqrt(diffX * diffX + diffY * diffY);
/// find angle from pivot to corner
angle += Math.atan2(diffY, diffX);
/// get new x and y and round it off to integer
x = pivotX + distance * Math.cos(angle);
y = pivotY + distance * Math.sin(angle);
return {x, y};
}
假设场景如下:
其中图像左下角(实线)的坐标为(x_i, y_i)
,容器左下角(虚线)的坐标为(X_c, Y_c)
。此外,图像(宽度 w
和高度 h
)相对于实验室框架逆时针旋转角度 beta
,而容器本身旋转(也是逆时针) 按角度 alpha
.
现在,让我们以右上角为例P
。相对于实验室坐标系(全局canvas),其坐标可以表示为:
R(beta) . ( w, h ) + ( x_i, y_i )
其中.
表示矩阵相乘,R
为逆时针旋转矩阵
R(beta) = [ cos(beta) -sin(beta) ]
[ sin(beta) cos(beta) ]
现在,我们需要将其转换为相对于容器的坐标系。形式上,这意味着我们需要先减去偏移量,然后顺时针旋转 -alpha
(或 alpha
)。因此,一切都在一起:
R(-alpha).( R(beta) . (w, h) + (x_i, y_i) - (X_c, Y_c) )
其他角可以类似处理,只需将 (w, h)
替换为适当的坐标...
就代码而言,可以将这些公式实现为:
//counter-clock-wise rotation by given angle in degrees
function rotateCCWBy(angle, {x, y}) {
const angle_rad = angle * Math.PI / 180;
const cos_a = Math.cos(angle_rad),
sin_a = Math.sin(angle_rad);
return {
x: cos_a * x - sin_a * y,
y: sin_a * x + cos_a * y
};
}
//shift by a multiple fac of an offset {xref, yref}
function offsetBy(fac, {x:xref, y:yref}, {x, y}) {
return {
x: fac*xref + x,
y: fac*yref + y
};
}
const image = {
coords: {x: 200, y: 0}, //lab-frame coordinates
angle: 45, //lab-frame rotation angle
width: 50,
height: 10
};
const container = {
coords: {x: 100, y: 100}, //lab-frame coordinates
angle: 45 //lab-frame rotation angle
};
//calculate the coordinates of the image's top-right corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
offsetBy(
-1, container.coords,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
console.log(corner);
编辑:
如果 y 轴应该指向 "downwards",上面的公式也适用,只需要将角度解释为顺时针而不是逆时针(因此原则上函数rotateCCWBy
应重命名为 rotateCWBy
)。例如,让我们考虑这种情况:
此处,容器的左上角位于位置 (2,1),容器本身旋转了 15 度。宽度为 4、高度为 2 的图像(黑色矩形)旋转了 30 度,其左上角位于位置 (3, 3)。现在,我们要计算点 P 相对于容器的坐标 (x, y)
。
使用:
const image = {
coords: {x: 3, y: 3}, //lab-frame coordinates
angle: 30, //lab-frame rotation angle
width: 4,
height: 2
};
const container = {
coords: {x: 2, y: 1}, //lab-frame coordinates
angle: 15 //lab-frame rotation angle
};
//calculate the coordinates of the image's top-left corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
offsetBy(
-1, container.coords,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
console.log(corner);
产量
{ x: 4.8296291314453415, y: 4.640160440463835 }
从附图中可以(大致)目测验证。
编辑 2:
添加clarification后,图像的坐标不应该是"lab-frame"(即相对于canvas),而是相对于已经旋转的容器.因此,转换需要调整为:
const corner =
offsetBy(
+1, container.coords,
rotateCCWBy(container.angle,
offsetBy(
+1, image.coords,
rotateCCWBy(image.angle,
{x: image.width, y: image.height}
)
)
)
);
function rotateCCWBy(angle, {x, y}) {
const angle_rad = angle * Math.PI / 180;
const cos_a = Math.cos(angle_rad),
sin_a = Math.sin(angle_rad);
return {
x: cos_a * x - sin_a * y,
y: sin_a * x + cos_a * y
};
}