首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将矩形夹在外旋转矩形的边界内?

如何将矩形夹在外旋转矩形的边界内?
EN

Stack Overflow用户
提问于 2014-11-03 22:20:12
回答 3查看 2.6K关注 0票数 18

我正在开发一个WebGL (带有2d画布后备图片编辑器)。

我已经决定将旋转直接纳入作物工具,以类似于iOS 8照片裁剪器的方式。也就是说,照片的大小和位置会随着照片的旋转而发生动态变化,以便使作物区域始终包含在照片本身中。

然而,我正在努力解决一些数学问题。

我有两个长方形,照片和作物面积。

两者都被定义为:

代码语言:javascript
运行
复制
var rect = {
     x : x,
     y : y,
     w : width,
     h : height
}

定义照片本身的矩形还具有一个以弧度表示的rotation属性,当然,该属性描述照片的角度(以弧度表示)。

应该注意的是,照片矩形的xy坐标(而不是,即作物矩形)实际上定义了照片的中心,而不是左上角。虽然这似乎很奇怪,但它使我们在其他地方的计算更容易,不应影响这一问题。为了完整起见,我要提一提。

照片的变换原点总是被设置为耕地的中心

当照片的角度为0,作物面积与照片大小相同时,矩形排列如下:

当我旋转照片时,会对照片矩形应用缩放因子,以确保裁剪区域保持在照片边界内:

这是通过计算作物面积的边框来实现的,并由此计算出适用于photo矩形所需的缩放因子:

代码语言:javascript
运行
复制
TC.UI.PhotoCropper.prototype._GetBoundingBox = function(w,h,rads){
    var c = Math.abs(Math.cos(rads));
    var s = Math.abs(Math.sin(rads));
    return({  w: h * s + w * c,  h: h * c + w * s });
}

var bbox = this._GetBoundingBox(crop.w, crop.h, photo.rotation);
var scale = Math.max(1, Math.max(bbox.w/photo.w, bbox.h/photo.h));

目前,这完全按照预期的工作,照片矩形的宽度是正确的缩放,无论哪里的作物面积(以及由此产生的旋转起源)恰巧。

另外,由于这是一个光刻工具,当然可以修改种植面积的位置。请注意,当修改裁剪区域位置时,我们正在移动photo矩形本身。(作物区始终保持中心,因为我们认为这是更自然的触摸设备,仍然可以接受时,与鼠标.这在iOS和windows 8中都是一样的。

因此,我们目前将xy矩形的坐标夹在裁剪区的边缘,如下所示:

代码语言:javascript
运行
复制
var maxX = crop.x + (crop.w/2) - (photo.w/2);
var maxY = crop.y + (crop.h/2) - (photo.w/2);
var minX = crop.x - (crop.w/2) + (photo.w/2);
var minY = crop.y - (crop.h/2) + (photo.h/2);

photo.x = Math.min(minX, Math.max(maxX, photo.x));
photo.y = Math.min(minY, Math.max(maxY, photo.y));

和这个,是我遇到麻烦的地方。

当作物区域不在照片中的中心位置时,我们最终会看到作物区域在照片的边界外移动,如下所示:

记住,旋转的起源总是种植区的中心。

在上面的照片中,您可以看到所需的宽度被正确地计算出来,并且照片被正确地缩放,以包括作物面积。

然而,由于我们的夹持功能只检查作物区域的边缘,我们结束了我们的作物区域以外的照片边界。

我们想修改我们的夹紧函数,以便它考虑到photo矩形的旋转。因此,应该正确地夹紧xy坐标(在上面的屏幕快照中),以确保最终结果如下所示:

不幸的是,我不知道从哪里开始的数学,并真正需要一些帮助。

我们目前使用相同的夹紧功能,同时旋转和移动photo矩形,并希望继续这样做,如果可能的话。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-11-17 01:09:00

怎么了?

您需要在旋转坐标系中夹紧照片坐标,而不是夹紧原始坐标系中的照片坐标。在旋转坐标系中使用作物面积角的坐标(计算minXmaxXminYmaxY)是没有意义的。

夹紧照片坐标

您需要在旋转坐标系中构造一个轴对齐的作物区域的包围盒,您可以使用它来夹紧。就像这样:

由于我们是围绕作物区域的中心旋转,中心坐标保持不变。然而,宽度和高度将增加。

请注意,您已经计算了这些量来适当地缩放照片。因此,简而言之,您只需替换计算边界框( crop.wbbox.h)时得到的缩放时使用的宽度crop.h和高度crop.h

代码语言:javascript
运行
复制
var maxX = crop.x + (bbox.w/2) - (photo.w/2);
var maxY = crop.y + (bbox.h/2) - (photo.w/2);
var minX = crop.x - (bbox.w/2) + (photo.w/2);
var minY = crop.y - (bbox.h/2) + (photo.h/2);

center = {
    x: Math.min(minX, Math.max(maxX, photo.x)),
    y: Math.min(minY, Math.max(maxY, photo.y))
};

请记住,在最后两条线上获得的坐标只在旋转坐标系中工作。如果您需要它们在原始坐标系中,您仍然必须将它们旋转回来:

代码语言:javascript
运行
复制
var sin = Math.sin(-rotation);
var cos = Math.cos(-rotation);

photo.x = crop.x + cos*(center.x - crop.x) - sin*(center.y - crop.y);
photo.y = crop.y + sin*(center.x - crop.x) + cos*(center.y - crop.y);
票数 4
EN

Stack Overflow用户

发布于 2014-11-10 16:34:53

正如DARK_DUCK所说,有一些方法(非平凡的方法)可以编写一个clamp函数来解决您的问题。但是,当您说“钳子”时,我会自动假设您的解决方案必须限制用户到达某些无效状态,而IMHO不是一个好的解决方案。也许用户会旋转图像通过一些无效的状态,只是为了达到一个有效的状态。

我提出另一种解决办法:

  1. 使用每次更改(旋转、平移、缩放)存储最后一个有效状态。
  2. 当用户完成更改时,如果当前状态有效,则不执行任何操作,或者恢复最后有效状态。

状态将由图像原点(或位置)、旋转和比例组成。

您可以激活从无效状态到持久有效状态的转换。当处于无效状态时,可以通过将作物区边框改为红色通知用户:

有效状态是当作物区域的所有四个角都在图像矩形内时。以下函数将帮助您测试此条件:

代码语言:javascript
运行
复制
//rotate a point around a origin
function RotatePoint(point, angle, origin)
{
    var a = angle * Math.PI / 180.0;
    var sina = Math.sin(a);
    var cosa = Math.cos(a);

    return
    {
        x : origin.x + cosa * (point.x - origin.x) - sina * (point.y - origin.y),
        y : origin.y + sina * (point.x - origin.x) + cosa * (point.y - origin.y)
    }

}

//position of point relative to line defined by a and b
function PointPos(a, b, point)
{
    return Math.sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x));
}

你必须:

  1. 应用旋转和平移计算图像矩形的角点位置
  2. 使用上面提供的第二个函数检查裁剪矩形角是否在图像矩形中。一个点x位于矩形内,如果 PointPos(a,b,x) == -1 & PointPos(b,c,x) == -1 & PointPos(c,d,x) == -1 & PointPos(d,a,x) == -1;

编辑:下面是一个例子:JSFiddle

这两个矩形有不同的起源。外(pictureArea)矩形的旋转原点是内部(cropArea)的原点。

祝好运!

票数 4
EN

Stack Overflow用户

发布于 2014-11-10 09:25:08

实际上,你不能“夹紧”x和y值,因为x和y是相互依赖的。我想说的是,你可以通过改变图像的x值或y值或x和y值的无限线性组合来解决问题(图像超出界限)。

因此,钳位函数将返回一组无限的正确值(如果没有解决方案,则不返回任何值)。如果您想要解决您的问题,您可能应该添加更多的条件,以规范的钳子功能。例如,您可以说箝位函数必须最小化max(displacementX, displacementY)。如果添加此条件,则钳位函数将返回单个或没有解决方案。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26724327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档