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