如何确定适合固定尺寸2D空间的任意数量的等方的大小?

时间:2011-05-28 20:37:50

标签: algorithm

我有一个固定大小的2D空间,我想填充任意数量的相等大小的正方形。我想要一个算法来确定这些方块的确切大小(一边的长度),以便完美地适应给定的空间。

4 个答案:

答案 0 :(得分:4)

请注意,必须有一个整数个正方形,用于填充宽度和高度。因此,纵横比必须是有理数。

输入:width(float或int),height(float或int)

算法:

aspectRatio = RationalNumber(width/height).lowestTerms  #must be rational number

# it must be the case that our return values
# numHorizontalSqaures/numVerticalSquares = aspectRatio

return {
    numHorizontalSquares = aspectRatio.numerator,
    numVerticalSquares = aspectRatio.denominator,
    squareLength = width/aspectRatio.numerator
}

如果宽度/高度是有理数,您的答案只是宽高比的任何倍数! (例如,如果你的纵横比是4/3,你可以用长度为width/4 = height/3的4x3正方形填充它,或者用这个尺寸的一半的8x6正方形填充它,或者用这个尺寸的三分之一的12x9正方形填充它。如果它不是一个有理数,你的任务是不可能的。

通过分解分子和分母,并删除所有重复的因子对,将分数转换为最低项;这相当于只使用最大公约数算法GCD(numer,denom),并将分子和分母除以它。

以下是python3中的示例实现:

from fractions import Fraction
def largestSquareTiling(width, height, maxVerticalSquares=10**6):
    """
        Returns the minimum number (corresponding to largest size) of square
        which will perfectly tile a widthxheight rectangle.

        Return format:
            (numHorizontalTiles, numVerticalTiles), tileLength
    """
    if isinstance(width,int) and isinstance(height,int):
        aspectRatio = Fraction(width, height)
    else:
        aspectRatio = Fraction.from_float(width/height)

    aspectRatio2 = aspectRatio.limit_denominator(max_denominator=maxVerticalSquares)
    if aspectRatio != aspectRatio2:
        raise Exception('too many squares') #optional
    aspectRatio = aspectRatio2

    squareLength = width/aspectRatio.numerator
    return (aspectRatio.numerator, aspectRatio.denominator), squareLength

e.g。

>>> largestSquareTiling(2.25, 11.75)
((9, 47), 0.25)

您可以调整可选参数maxVerticalSquares以使自己比浮点不精确更具鲁棒性(但缺点是操作可能失败),或避免大量垂直方块(例如,如果这是架构代码,你在铺平地板);根据您使用的数字范围,默认值maxVerticalSquares=500可能是合理的或某些(甚至可能不包括异常代码)。

一旦你有这个,以及一系列所需的方形长度(minLength, maxLength),你只需乘以:

# inputs    
desiredTileSizeRange = (0.9, 0.13)
(minHTiles, minVTiles), maxTileSize = largestSquareTiling(2.25, 11.75)

# calculate integral shrinkFactor
shrinkFactorMin = maxTileSize/desiredTileSizeRange[0]
shrinkFactorMax = maxTileSize/desiredTileSizeRange[1]
shrinkFactor = int(scaleFactorMax)
if shrinkFactor<shrinkFactorMin:
    raise Exception('desired tile size range too restrictive; no tiling found')

例如,shrinkFactor现在为2,示例中的新输出值为((9*2,47*2), 0.25/2)

答案 1 :(得分:0)

如果边是整数,你需要找到A和B边之间的Greatest common divisor,这就是你正在寻找的正方形的一面。

答案 2 :(得分:0)

您想要使用空间填充曲线或空间索引。 sfc recursivley将平面细分为4个瓦片,并将2d复杂度降低到1d复杂度。你想寻找尼克的希尔伯特曲线四叉树空间索引博客。

答案 3 :(得分:0)

我认为这就是你想要的。至少它解决了我在谷歌搜索时发现这个问题的问题。

// width = width of area to fill
// height = height of area to fill
// sqareCount = number of sqares to fill the area with
function CalcSquareSide(float width, float height, int squareCount)
{
  return Math.Sqrt((height * width) / squareCount);
}