将一个矩形放入另一个矩形中

6
我经常将一个矩形套进另一个矩形中,以使其完美地居中。 我会在白板上画出一些逻辑,并拍下照片,但现在天色已暗,蜡烛光线不太适合这样做。
无论如何,这很简单易懂。以下是我刚刚再次从头开始编写的函数(这次使用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中。


6
你没有灯光,但有一台电脑可以编程吗? - gbtimmon
3
感谢您的有趣帖子,但我不明白第三个矩形是什么。 - Miserable Variable
1
无论如何,这个算法非常简单明了,容易理解。我想要了解这个算法以及其他版本的它……对于问题,你具体是什么再问一遍好吗? - mbeckish
1
假设大矩形是信纸大小的纸张,小矩形是信封。所以...你想把信封居中放在纸上。那么第三个矩形是什么? - Miserable Variable
1
@gbtimmon 嘿,你应该看到我穿的外套 - 我几乎动不了手打字。 - zaf
显示剩余3条评论
4个回答

12
这是我该如何做:
让我们定义一个术语“肥度”,它等于矩形的宽度与高度之比。 高度为1,宽度为10的矩形的肥度为10。 高度为20,宽度为10的矩形的肥度为0.5。 当你调整矩形大小时,它的肥度不会改变。
当你将矩形2按比例放大或缩小,使其宽度等于矩形1时,只要矩形2比矩形1更胖,它就不会溢出顶部或底部。 如果1比2更胖,则会溢出。 现在你提前知道要调整大小以获得紧凑的宽度还是紧凑的高度。 此外,翻译逻辑在两种情况下都相同,因此可以放在if / else块之外。
伪代码如下:(抱歉,我不懂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)

4
我喜欢“肥胖”这个概念。 - zaf

8
这是一个用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);
}

2

以下是我的做法。(这个算法在处理图像时效果很好。)

假设你有一个矩形和一个容器(也是一个矩形):

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行进行操作。


1
我刚刚处理了类似的问题:我们称矩形2为image,矩形1为window。所以我们的任务是将图像适应到窗口中。
在我的情况下,imagewindow都有一个[-1,1]X[-1,1]的“内部”坐标系统。事实上,在窗口内部,有一个viewport(问题中的矩形3),图像将被投影,因此我们的任务是找到最大的viewport(一个矩形在window内部),其宽高比(宽度/高度)与image相同。

enter image description here

viewport 是由 image 的宽度/高度的一部分来确定的:

viewport_width = scale_w * window_w
viewport_height = scale_h * window_h

所以我们的目标是找到正确的宽度和高度缩放比例,使得window的纵横比(宽度/高度)与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_wscale_h中至少有一个将等于1。因此 - 如果s<1,意味着windowimage更宽,我们将有scale_w=s,scale_h=1(这对应于上面的图,其中scale_w=0.5)。如果s>1,意味着imagewindow更宽,我们将有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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接