我经常把一个长方形装进另一个长方形,使其很好地贴合,并居中.我想在白板上画点东西,然后拍张照片,看看是什么逻辑,但天黑了,烛光使它没有那么有趣。
总之,很直接,很容易理解。这是我刚刚又不得不从头写出来的函数(这次是用PHP写的)。
// Fit rectangle 2 into rectangle 1 to get rectangle 3
// Rectangle 3 must be centered
// Return dimensions of rectangle and position relative to rectangle 1
function fitrect($w1,$h1,$w2,$h2){
// Let's take a chance with rectangle 3 width being equal to rectangle 1 width
$w3=$w1;
$h3=$w3*($h2/$w2);
// Check if height breaks rectangle 1 height
if($h3>$h1){
// Recalculate dimensions and then position
$h3=$h1;
$w3=$h3*($w2/$h2);
$x3=($w1-$w3)/2;
$y3=0;
}else{
// Just calculate position
$y3=($h1-$h3)/2;
$x3=0;
}
// Tidy up
$x3=round($x3);
$y3=round($y3);
$w3=round($w3);
$h3=round($h3);
// Result array
$res=array($x3,$y3,$w3,$h3);
return($res);
}
我想了解这个算法和其他版本的算法,这样我的大脑就能掌握基础,从而再也不用依赖纸笔(或白板)了。
那么,你会怎么做呢?可以去掉哪些绒毛?
编辑:举个例子--比如说我们有矩形1的尺寸是256x256,矩形2的尺寸是44x167。那么我们需要将矩形2缩放为67x256,并将其相对于矩形1定位在94,0处,使其坐在矩形1的最大化和中心化。
我是这样做的。
让我们定义一个术语,胖度,它等于一个矩形的宽度和高度的比值。一个高度为1,宽度为10的矩形,胖度为10。一个高度为20,宽度为10的矩形的胖度为0.5。当你调整一个矩形的大小时,它的肥度不会改变。
当你放大或缩小矩形2的大小,使它的宽度与矩形1相等时,它将会 不 只要长方形2比长方形1大,就会溢出顶部或底部。它 会 溢出,如果 1 比 2 胖,现在您可以提前知道是要调整宽度还是高度。此外,两种情况下的翻译逻辑是一样的,所以可以在ifelse块之外。
伪代码中。(对不起,我不懂PHP)
fatness1 = w1 / h1
fatness2 = w2 / h2
#adjust scaling
if fatness2 >= fatness1:
#scale for a snug width
scaleRatio = w1 / w2
else:
#scale for a snug height
scaleRatio = h1 / h2
w3 = w2 * scaleRatio
h3 = h2 * scaleRatio
#adjust rectangle 3's center so it is the same as 1's center
xCenterOf1 = x1 + (w1 / 2)
yCenterOf1 = y1 + (h1 / 2)
x3 = xCenterOf1 - (w3 / 2)
y3 = yCenterOf1 - (h3 / 2)
return (x3, y3, w3, h3)
在python中测试,假设矩形1在(0,0)。scale(256,256, 44, 167)
返回 (0.0, 94.3, 256.0, 67.4)
.
这是一个用Java写的方便的函数。
public static RectF fitRectWithin(Rect inner, Rect outer) {
float innerAspectRatio = inner.width() / (float) inner.height();
float outerAspectRatio = outer.width() / (float) outer.height();
float resizeFactor = (innerAspectRatio >= outerAspectRatio) ?
(outer.width() / (float) inner.width()) :
(outer.height() / (float) inner.height());
float newWidth = inner.width() * resizeFactor;
float newHeight = inner.height() * resizeFactor;
float newLeft = outer.left + (outer.width() - newWidth) / 2f;
float newTop = outer.top + (outer.height() - newHeight) / 2f;
return new RectF(newLeft, newTop, newWidth + newLeft, newHeight + newTop);
}
下面是我的做法。 (这个算法对图像很有效。)假设你有一个矩形,和一个容器(也是一个矩形)。
aspectRatio = screen.width / screen.height
if (rectangle.width >= rectangle.height)
{
resizeFactor = container.width / rectangle.width
rectangle.width = rectangle.width * resizeFactor
rectangle.height = rectangle.height * resizeFactor * aspectRatio
}
else
{
resizeFactor = container.height / rectangle.height
rectangle.width = rectangle.width * resizeFactor / aspectRatio
rectangle.height = rectangle.height * resizeFactor
}
你可以把第6行改成优化一下这个算法
rectangle.width = container.width
如果你想的话,也可以把第13行也改成这样。
我只是不得不处理类似的事情:让我们把rectangle2称为 image
和矩形1 window
. 所以我们的任务是把图像装进窗口。
另外,在我的方案中,无论是 image
和 window
有一个 "内 "坐标系 [-1,1]X[-1,1]
. 其实,在窗户里面,有一个... viewport
矩形3)中的 image
将会被投射出来,所以我们的任务是找到最大的 viewport
矩形内 window
)的长宽比(宽-高)相同。image
.
该 viewport
是由宽度-高度的一小部分决定的。image
:
viewport_width = scale_w * window_w
viewport_height = scale_h * window_h
因此,我们的目标是找到正确的宽度和高度的缩放比例。window
,从而使 viewport
的长宽比(高宽比)将与 image
:
# goal:
scale_w * window_w == image_w
scale_h * window_h == image_h
也就是说,我们要找的比例尺满足。
(scale_w / scale_h) == ((image_w / image_h) / (window_w / window_h))
让我们把这个等式的右边表示为: s
姑且不论。
由于我们要寻找的是最大的 viewport
至少有一个 scale_w
和 scale_h
将等于1。所以--如果 s<1
意思是 window
宽于 image
,我们将有 scale_w=s, scale_h=1
(这与上图相对应,其中包括 scale_w=0.5
). 而如果 s>1
意思是 image
宽于 window
,我们将有 scale_w=1, scale_h=1/s
.
在python代码中,它看起来像这样。
def compute_viewport_scale(image_size, window_size):
image_w, image_h = image_size
window_w, window_h = window_size
im_ratio, win_ratio = image_w / image_h, window_w / window_h
scale = im_ratio / win_ratio
if scale > 1: # image is wider than screen
scale_w = 1
scale_h = 1 / scale
else: # window is wider then image
scale_w = scale
scale_h = 1
viewport_w, viewport_h = window_w * scale_w, window_h * scale_h
assert (round(viewport_w / viewport_h, 5) == round(image_w / image_h, 5))
return scale_w, scale_h
因为我想绝对确定我已经涵盖了所有的情况,我构建了一个大小的例子列表,以确保这个公式确实是正确的。事实上,如果你运行所有这些行,你将不会得到任何断言错误:)
# aspect ratio = 1
compute_viewport_scale((100, 100), (100, 100))
compute_viewport_scale((100, 100), (200, 200))
compute_viewport_scale((200, 200), (100, 100))
# image is wider than screen: (im_w / im_h) > (win_w / win_h) [ i.e. im_ratio > win_ratio ]
# (im_ratio < 1 and win_ratio > 1 cant happen)
# im_w > win_w and im_h > win_h
compute_viewport_scale((300, 200), (100, 90)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 300), (100, 200)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((300, 200), (100, 150)) # im_ratio > 1 and win_ratio < 1
# im_w > win_w and im_h < win_h
compute_viewport_scale((150, 50), (110, 100)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 300), (100, 400)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((300, 100), (100, 150)) # im_ratio > 1 and win_ratio < 1
# (im_w < win_w and im_h > win_h cant happen)
# im_w < win_w and im_h < win_h
compute_viewport_scale((150, 50), (200, 100)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((90, 100), (100, 200)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((110, 100), (100, 200)) # im_ratio > 1 and win_ratio < 1
# image is wider than screen: (im_w / im_h) < (win_w / win_h) [ i.e. im_ratio < win_ratio ]
# (im_ratio > 1 and win_ratio < 1 cant happen)
# im_w > win_w and im_h > win_h
compute_viewport_scale((300, 200), (100, 50)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 400), (100, 150)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((200, 400), (150, 100)) # im_ratio < 1 and win_ratio > 1
# (im_w > win_w and im_h < win_h cant happen)
# im_w < win_w and im_h > win_h
compute_viewport_scale((150, 100), (200, 50)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 400), (380, 390)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((200, 400), (390, 380)) # im_ratio < 1 and win_ratio > 1
# im_w < win_w and im_h < win_h
compute_viewport_scale((300, 200), (600, 300)) # im_ratio > 1 and win_ratio > 1
compute_viewport_scale((200, 300), (500, 600)) # im_ratio < 1 and win_ratio < 1
compute_viewport_scale((50, 100), (300, 200)) # im_ratio < 1 and win_ratio > 1