26

基本上我问这个问题的 JavaScript:Calculate Bounding box coordinates from a rotate rectangle

图表

在这种情况下:

  • iX = 旋转(蓝色)HTML 元素的宽度
  • iY = 旋转(蓝色)HTML 元素的高度
  • bx = 边界框的宽度(红色)
  • by = 边界框的高度(红色)
  • x = Bounding Box 的 X 坐标(红色)
  • y = Bounding Box 的 Y 坐标(红色)
  • iAngle/t = HTML 元素的旋转角度(蓝色;未显示,但在下面的代码中使用),仅供参考:在此示例中为 37 度(与示例无关)

如何通过 JavaScript 计算围绕旋转的 HTML 元素(给定其宽度、高度和旋转角度)的边界框(所有红色数字)的 X、Y、高度和宽度?一个棘手的问题是让旋转的 HTML 元素(蓝色框)的原始 X/Y 坐标以某种方式用作偏移量(这在下面的代码中没有表示)。这可能得看CSS3的transform-origin来确定中心点。

我有一个部分解决方案,但 X/Y 坐标的计算无法正常运行......

var boundingBox = function (iX, iY, iAngle) {
    var x, y, bx, by, t;

    //# Allow for negetive iAngle's that rotate counter clockwise while always ensuring iAngle's < 360
    t = ((iAngle < 0 ? 360 - iAngle : iAngle) % 360);

    //# Calculate the width (bx) and height (by) of the .boundingBox
    //#     NOTE: See https://stackoverflow.com/questions/3231176/how-to-get-size-of-a-rotated-rectangle
    bx = (iX * Math.sin(iAngle) + iY * Math.cos(iAngle));
    by = (iX * Math.cos(iAngle) + iY * Math.sin(iAngle));

    //# This part is wrong, as it's re-calculating the iX/iY of the rotated element (blue)
    //# we want the x/y of the bounding box (red)
    //#     NOTE: See https://stackoverflow.com/questions/9971230/calculate-rotated-rectangle-size-from-known-bounding-box-coordinates
    x = (1 / (Math.pow(Math.cos(t), 2) - Math.pow(Math.sin(t), 2))) * (bx * Math.cos(t) - by * Math.sin(t));
    y = (1 / (Math.pow(Math.cos(t), 2) - Math.pow(Math.sin(t), 2))) * (-bx * Math.sin(t) + by * Math.cos(t));

    //# Return an object to the caller representing the x/y and width/height of the calculated .boundingBox
    return {
        x: parseInt(x), width: parseInt(bx),
        y: parseInt(y), height: parseInt(by)
    }
};

我觉得我很近,但又很远……

非常感谢您提供的任何帮助!

帮助非 JAVASCRIPTERS...

一旦 HTML 元素被旋转,浏览器会返回一个“矩阵变换”或“旋转矩阵”,看起来是这样的:rotate(Xdeg) = matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0); 有关更多信息,请参阅此页面

我有一种感觉,这将启发我们如何仅根据旋转元素(蓝色)的宽度、高度和角度来获取边界框(红色)的 X、Y。

新信息

嗯……有趣……

在此处输入图像描述

从 X/Y 角度来看,每个浏览器似乎处理旋转的方式不同!FF 完全无视它,IE & Opera 绘制边界框(但它的属性没有暴露,即:bx & by)和 Chrome & Safari 旋转矩形!除 FF 外,所有人都正确报告了 X/Y。所以... X/Y 问题似乎只存在于 FF!多么奇怪!

另外值得注意的是,对于旋转的 X/Y 而言,似乎$(document).ready(function () {...});触发得太早了(这是我最初的问题的一部分!)。我在 X/Y 询问调用之前直接旋转元素,$(document).ready(function () {...});但它们似乎直到一段时间后才更新(!?)。

当我有更多时间时,我会用这个例子折腾一个 jFiddle,但我使用的是“jquery-css-transform.js”的修改形式,所以我在 jFiddle 之前有一点点修补......

那么... 怎么了,FireFox?这不酷,伙计!

剧情变厚了……

嗯,FF12 似乎解决了 FF11 的问题,现在就像 IE 和 Opera 一样。但现在我又回到了 X/Y 的方位,但至少我想我现在知道为什么了……

似乎即使浏览器正确报告了旋转对象的 X/Y,但未旋转版本上仍然存在“幽灵”X/Y。似乎这是操作的顺序:

  • 从 X,Y 为 20,20 的未旋转元素开始
  • 旋转所述元素,导致 X,Y 报告为 15,35
  • 通过 JavaScript/CSS 将所述元素移动到 X,Y 10,10
  • 浏览器在逻辑上不旋转元素回到 20,20,移动到 10,10 然后重新旋转,导致 X,Y 为 5,25

所以...我希望元素在旋转后 10,10 处结束,但由于元素(看似)在移动后重新旋转,因此生成的 X,Y 与集合 X,Y 不同。

这是我的问题!所以我真正需要的是一个函数来获取所需的目标坐标 (10,10),并从那里向后工作以获得起始 X、Y 坐标,这将导致元素旋转到 10,10。至少我知道我现在的问题是什么,因为由于浏览器的内部工作原理,旋转元素似乎是 10=5!

4

4 回答 4

20

我知道这有点晚了,但我已经在 HTML5 画布上为这个问题写了一个小提琴:

http://jsfiddle.net/oscarpalacious/ZdQKg/

我希望有人觉得它有用!

我实际上并没有计算容器左上角的 x,y 。它是作为偏移量的结果计算的(来自小提琴示例的代码):

this.w = Math.sin(this.angulo) * rotador.h + Math.cos(this.angulo) * rotador.w;
this.h = Math.sin(this.angulo) * rotador.w + Math.cos(this.angulo) * rotador.h;
// The offset on a canvas for the upper left corner (x, y) is
// given by the first two parameters for the rect() method:
contexto.rect(-(this.w/2), -(this.h/2), this.w, this.h);

干杯

于 2013-07-03T16:49:25.727 回答
6

您是否尝试过使用getBoundingClientRect()

考虑到旋转,此方法返回当前值为“底部、高度、左侧、右侧、顶部、宽度”的对象

于 2012-08-02T04:41:41.593 回答
1

将四个角从中心变成向量,旋转它们,并从中获取新的最小/最大宽度/高度。

编辑:

我知道你现在哪里有问题了。当您需要使用与旋转中心的偏移量进行计算时,您正在使用整个侧面进行计算。是的,这会产生四个旋转点(奇怪的是,这与您开始时的点数完全相同)。它们之间将有一个最小 X、一个最大 X、一个最小 Y 和一个最大 Y。这些是你的界限。

于 2012-05-01T02:03:38.470 回答
0

我的要点可以帮助你

多边形的边界框(矩形、三角形等):

现场演示https://jsfiddle.net/Kolosovsky/tdqv6pk2/

let points = [
    { x: 125, y: 50 },
    { x: 250, y: 65 },
    { x: 300, y: 125 },
    { x: 175, y: 175 },
    { x: 100, y: 125 },
];
let minX = Math.min(...points.map(point => point.x));
let minY = Math.min(...points.map(point => point.y));
let maxX = Math.max(...points.map(point => point.x));
let maxY = Math.max(...points.map(point => point.y));
let pivot = {
    x: maxX - ((maxX - minX) / 2),
    y: maxY - ((maxY - minY) / 2)
};
let degrees = 90;
let radians = degrees * (Math.PI / 180);
let cos = Math.cos(radians);
let sin = Math.sin(radians);

function rotatePoint(pivot, point, cos, sin) {
    return {
        x: (cos * (point.x - pivot.x)) - (sin * (point.y - pivot.y)) + pivot.x,
        y: (sin * (point.x - pivot.x)) + (cos * (point.y - pivot.y)) + pivot.y
    };
}

let boundingBox = {
    x1: Number.POSITIVE_INFINITY,
    y1: Number.POSITIVE_INFINITY,
    x2: Number.NEGATIVE_INFINITY,
    y2: Number.NEGATIVE_INFINITY,
};

points.forEach((point) => {
    let rotatedPoint = rotatePoint(pivot, point, cos, sin);

    boundingBox.x1 = Math.min(boundingBox.x1, rotatedPoint.x);
    boundingBox.y1 = Math.min(boundingBox.y1, rotatedPoint.y);
    boundingBox.x2 = Math.max(boundingBox.x2, rotatedPoint.x);
    boundingBox.y2 = Math.max(boundingBox.y2, rotatedPoint.y);
});

椭圆的边界框:

现场演示https://jsfiddle.net/Kolosovsky/sLc7ynd1/

let centerX = 350;
let centerY = 100;
let radiusX = 100;
let radiusY = 50;
let degrees = 200;

let radians = degrees * (Math.PI / 180);
let radians90 = radians + Math.PI / 2;
let ux = radiusX * Math.cos(radians);
let uy = radiusX * Math.sin(radians);
let vx = radiusY * Math.cos(radians90);
let vy = radiusY * Math.sin(radians90);

let width = Math.sqrt(ux * ux + vx * vx) * 2;
let height = Math.sqrt(uy * uy + vy * vy) * 2;
let x = centerX - (width / 2);
let y = centerY - (height / 2);
于 2018-05-18T09:41:04.500 回答