You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell Gloss库中是否存在获取Picture对象尺寸的函数?

获取Gloss中Picture对象的尺寸

Gloss库本身没有内置的width或height函数来直接获取Picture的尺寸,不过我们可以通过递归遍历Picture的代数数据类型构造器,自己实现一个计算边界框的函数,再基于边界框得到宽高。

实现思路

  1. 定义BoundingBox类型来存储图形的最小/最大x、y坐标
  2. 写一个递归函数boundingBox,针对每种Picture构造器计算对应的边界框
  3. 基于边界框实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 15:55:14