计算画布内旋转元素的边界坐标

Posted 庞永胜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算画布内旋转元素的边界坐标相关的知识,希望对你有一定的参考价值。

svg,dom类的图形编辑器,在画布内编辑元素完成后,为了得到只包含元素的部分,去掉画布的留白,或者进行编组时,往往需要计算元素在画布内的边界坐标,重新生成输出元素的坐标

1、对于无旋转等几何变化的基本元素,计算元素的边界坐标是很容易的(以屏幕坐标为准)

如下图,只需遍历每个元素的四个顶点坐标比较即可;

假设已知元素css属性 left = x,top = y ,width = w ,height = h;

对于任意元素四个顶点坐标分别为,(左上,右上,左下,右下)

\\[pointLT\\ =\\ (x,\\ y),pointRT\\ =\\ (x\\ +\\ w,\\ y) \\]

\\[pointLB\\ =\\ (x,\\ y + h),pointRB\\ =\\ (x+w, y + h) \\]

代码为

let minX = Infinity, minY = Infinity, maxX = -Infinity , maxY = -Infinity;
elements.forEach(ele=>
    const points = [pointLT,pointRT, pointLB, pointRB ];
    points.forEach(point=>
     minX = Math.min(minX, xx);
     maxX = Math.max(maxX, xx);
     minY = Math.min(minY, yy);
     maxY = Math.max(maxY, yy);
    )
)

实际开发中,编辑器往往会对元素会有旋转反转裁剪等几何变化,如下图为实验仪器的组合,其边界可能为最左侧的旋转的玻璃棒和右侧旋转的试管决定

为了需重 新计算单个仪器旋转后的坐标和边界,从而 那么变化后的坐标如何计算呢

2、带有旋转属性的元素坐标计算

以元素中心E点为中心建立坐标系

A\'B\'C\'D\'为ABCD旋转θ ,后的矩形,已A点为例,连接EA,EA\',根据向量的旋转角度公式有

\\[\\overrightarrowEA\'\\ =\\ (A_x*\\cos\\theta\\ -\\ A_y*\\sin\\theta,\\ A_x*\\sin\\theta\\ +\\ A_y*\\cos\\theta) \\]

以上坐标是基于中心点坐标的,so可以用中心点的坐标E表示A\'坐标,从而换算会屏幕坐标,(注意屏幕坐标的基是(0,1)(-1,0),故y需取负值)

\\[A_x(屏幕坐标) = E_x(屏幕坐标) + A_x(对象坐标) \\]

\\[ A\\_y(屏幕坐标) = - E\\_x(屏幕坐标) + A\\_y(对象坐标) \\]

更新上一段代码为:

let minX = Infinity, minY = Infinity, maxX = -Infinity , maxY = -Infinity;
elements.forEach(ele=>
    const vertices = [pointLT,pointRT, pointLB, pointRB ];
    // ...
    vertices.forEach((x,y)=>
     let xm = cx + (x - cx) * cos - (cy - y) * sin;
     let ym = cy - ((x - cx) * sin + (cy - y) * cos);
     minX = Math.min(minX, xm);
     maxX = Math.max(maxX, xm);
     minY = Math.min(minY, ym);
     maxY = Math.max(maxY, ym);
    )
)

HTML5 Canvas 中旋转矩形内的鼠标位置

【中文标题】HTML5 Canvas 中旋转矩形内的鼠标位置【英文标题】:Mouse position within rotated rectangle in HTML5 Canvas 【发布时间】:2012-03-01 09:37:18 【问题描述】:

html5 画布中矩形的旋转以弧度存储。为了确定随后的鼠标点击是否在任何给定的矩形内,我将鼠标 x 和 y 平移到矩形的旋转原点,将旋转的反向应用于鼠标坐标,然后将鼠标坐标平移回来。

这根本行不通 - 鼠标坐标没有按预期转换(也就是说,在旋转矩形的可见边界内单击时,鼠标坐标不在原始矩形的边界内),并且针对矩形边界的测试失败.鼠标点击的检测仅在矩形的最中心区域内起作用。请查看下面的代码 sn-p 并告诉我您是否可以看到这里有什么问题。

 // Our origin of rotation is the center of the rectangle
 // Our rectangle has its upper-left corner defined by x,y, its width
 // defined in w, height in h, and rotation(in radians) in r.  
var originX = this.x + this.w/2, originY = this.y + this.h/2, r = -this.r;

 // Perform origin translation
mouseX -= originX, mouseY -= originY;
// Rotate mouse coordinates by opposite of rectangle rotation
mouseX = mouseX * Math.cos(r) - mouseY * Math.sin(r);
mouseY = mouseY * Math.cos(r) + mouseX * Math.sin(r);
// Reverse translation
mouseX += originX, mouseY += originY;

// Bounds Check
if ((this.x <= mouseX) && (this.x + this.w >= mouseX) && (this.y <= mouseY) && (this.y + this.h >= mouseY))
    return true;

【问题讨论】:

这个问题同:***.com/questions/28706989/… 【参考方案1】:

经过一些进一步的工作,得出了以下解决方案,我想我会在这里为将来可能需要它的任何人转录:

// translate mouse point values to origin
    var dx = mouseX - originX, dy = mouseY - originY;
    // distance between the point and the center of the rectangle
    var h1 = Math.sqrt(dx*dx + dy*dy);
    var currA = Math.atan2(dy,dx);
    // Angle of point rotated around origin of rectangle in opposition
    var newA = currA - this.r;
    // New position of mouse point when rotated
    var x2 = Math.cos(newA) * h1;
    var y2 = Math.sin(newA) * h1;
    // Check relative to center of rectangle
    if (x2 > -0.5 * this.w && x2 < 0.5 * this.w && y2 > -0.5 * this.h && y2 < 0.5 * this.h)
        return true;
    

【讨论】:

以上是关于计算画布内旋转元素的边界坐标的主要内容,如果未能解决你的问题,请参考以下文章

从旋转的矩形计算边界框坐标

从旋转的矩形计算边界框坐标

OBB(定向边界框)算法中的点?

JS中canvas画布绘制中如何实现缩放,位移,旋转

防止 Fabric js 对象超出画布边界

Canvas 交互