我正在制作一个WebGL(带有2D画布回退的照片编辑器)。
我决定将旋转直接纳入裁剪工具中,方式类似于iOS 8照片裁剪器。也就是说,随着您旋转照片,照片的大小和位置会动态更改,以便裁剪区域始终包含在照片本身内。
但是,我遇到了一些数学问题。
我有两个矩形,照片和裁剪区域。
两者都定义为:
var rect = {
x : x,
y : y,
w : width,
h : height
}
照片本身定义的矩形也具有以弧度为单位的旋转属性,这当然描述了照片的角度(以弧度为单位)。
需要注意的是,照片矩形的x和y坐标(而不是裁剪矩形)实际上定义了照片的中心,而不是左上角点。虽然这可能看起来很奇怪,但它使我们在其他地方的计算更容易,并且不应影响到这个问题。为了完整起见,我提一下。
照片的变换原点始终设置为裁剪区域的中心。
当照片的角度为0
且裁剪区域与照片的大小相同时,矩形对齐如下所示:
当我旋转照片时,会应用缩放因子以确保裁剪区域保持在照片的边界内:
这是通过计算裁剪区域的边界框并从中计算出所需的缩放因子来实现的,然后应用于photo
矩形:
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中都是一样的)。
因此,我们目前将x
和y
坐标限制在裁剪区域的边缘,如下所示:
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
的旋转。因此,应正确夹紧(在上面的截图中)x
和y
坐标,以确保最终结果如下:
不幸的是,我不知道从哪里开始数学计算,真的需要一些帮助。
我们目前在旋转和移动photo
矩形时使用相同的夹紧函数,并希望继续这样做,如果可能的话。
add
/sub
center_offset*cos(angle)
和center_offset*sin(angle)
或它们的一半添加到裁剪方程中以匹配所需的输出(center_offset 是旋转中心和裁剪中心之间的差异)。 - Spektre