Haskell Gloss库中是否存在获取Picture对象尺寸的函数?
获取Gloss中Picture对象的尺寸
Gloss库本身没有内置的width或height函数来直接获取Picture的尺寸,不过我们可以通过递归遍历Picture的代数数据类型构造器,自己实现一个计算边界框的函数,再基于边界框得到宽高。
实现思路
- 定义
BoundingBox类型来存储图形的最小/最大x、y坐标 - 写一个递归函数
boundingBox,针对每种Picture构造器计算对应的边界框 - 基于边界框实现
width和height函数,通过坐标差得到尺寸
完整代码实现
import Graphics.Gloss -- 边界框:(最小x, 最小y, 最大x, 最大y) type BoundingBox = (Float, Float, Float, Float) -- 计算Picture的边界框 boundingBox :: Picture -> BoundingBox boundingBox (Circle r) = (-r, -r, r, r) boundingBox (ThickCircle lineWidth r) = let adjustedR = r + lineWidth / 2 -- 考虑线宽的外扩 in (-adjustedR, -adjustedR, adjustedR, adjustedR) boundingBox (Polygon points) = let xs = map fst points ys = map snd points in (minimum xs, minimum ys, maximum xs, maximum ys) boundingBox (Line points) = let xs = map fst points ys = map snd points in (minimum xs, minimum ys, maximum xs, maximum ys) boundingBox (Text str) = -- Gloss未提供精确文本尺寸,这里按每个字符宽10、高20估算,可按需调整 let charWidth = 10 charHeight = 20 totalWidth = fromIntegral (length str) * charWidth in (-totalWidth/2, -charHeight/2, totalWidth/2, charHeight/2) boundingBox (Color _ pic) = boundingBox pic -- 颜色不影响尺寸 boundingBox (Translate dx dy pic) = let (xMin, yMin, xMax, yMax) = boundingBox pic in (xMin + dx, yMin + dy, xMax + dx, yMax + dy) boundingBox (Scale sx sy pic) = let (xMin, yMin, xMax, yMax) = boundingBox pic in (xMin * sx, yMin * sy, xMax * sx, yMax * sy) boundingBox (Rotate angle pic) = -- 旋转后取原边界框的外接正方形(近似值),精确计算需旋转四个顶点再找极值 let (xMin, yMin, xMax, yMax) = boundingBox pic centerX = (xMin + xMax) / 2 centerY = (yMin + yMax) / 2 halfW = (xMax - xMin) / 2 halfH = (yMax - yMin) / 2 -- 原矩形顶点到中心的最大距离 maxDist = sqrt (halfW^2 + halfH^2) in (centerX - maxDist, centerY - maxDist, centerX + maxDist, centerY + maxDist) boundingBox (Pictures pics) = let boxes = map boundingBox pics xMins = map (\(x,_,_,_) -> x) boxes yMins = map (\(_,y,_,_) -> y) boxes xMaxs = map (\(_,_,x,_) -> x) boxes yMaxs = map (\(_,_,_,y) -> y) boxes in (minimum xMins, minimum yMins, maximum xMaxs, maximum yMaxs) boundingBox Blank = (0, 0, 0, 0) -- 获取宽度 width :: Picture -> Float width pic = let (xMin, _, xMax, _) = boundingBox pic in xMax - xMin -- 获取高度 height :: Picture -> Float height pic = let (_, yMin, _, yMax) = boundingBox pic in yMax - yMin
测试你的例子
circ :: Picture circ = circle 100 main = print $ width circ -- 输出 200.0
注意事项
- 对于旋转图形,上面的实现是近似值,若需要精确边界框,需要把原边界框的四个顶点旋转后重新计算极值,逻辑会稍复杂但结果更准确。
- 文本尺寸是粗略估算,Gloss本身不提供精确的文本度量能力,如果需要更精准的文本尺寸,可能需要结合其他字体处理库。
ThickCircle的实现考虑了线宽的外扩,如果你不需要这个逻辑,可以去掉lineWidth / 2的调整。
内容的提问来源于stack exchange,提问作者Lukh
相关产品推荐
相关产品推荐

