区域标签与点标签
标签用于命名已绘制的填色区域或点。标签图层会在所有其他图层之后,由延后处理程序绘制,因此能判断必须避开哪些对象。点标签先于区域标签放置;每个已放置的标签,都会成为后续标签的障碍物。
区域标签
RegionLabelLayer(
region,
text,
short_text=None,
placement="auto",
style=None,
stroke=Stroke(width=0.8),
*,
role="text",
...
)
如果文字放得下,就以极点为中心置于区域内(参见有符号距离与不可及极点);如果长文字放不下,再尝试 short_text。两者都放不下时,以 text 作引线标注。
与 "auto" 相同,但两段文字都放不下时,仍把 short_text(或 text)置中于极点。
一律作引线标注:区域外不加框的文字,以及从极点拉到文字的细引线。
为填色区域命名;区域可以是 FillLayer 的 id,也可以是至少由三点组成的多边形。stroke 设置引线标注的引线样式。
“文字放得下”是指:文字矩形置中于极点、每边留白 2 pt 后,仍位于区域内(参见多边形内的矩形),且不碰到任何线条、标记、文字或其他区域。区域内标签与引线标注。同时呈现这两种结果。
点标签
PointLabelLayer(
point,
text,
style=None,
*,
role="text",
...
)
在点的旁边加上文字为它命名,不使用引线。点的足迹是该处画有标记时的标记,否则就是点本身。
标签在足迹周围尝试 16 个方向,距足迹边缘 4、7、11、16 pt,由近而远。同一距离内根据候选顺序的顺序尝试方向(参见方向的尝试顺序。),第一个不遮盖任何对象的位置胜出;若都不行,选违规数最少者(相同时取较早者),并发出指出该图层的 LayoutWarning。点严格位于其内部(距边缘超过 1.5 px)的区域是标签应在之处,不算障碍物。
定义 · 候选顺序
将方向自 \(+x\) 起逆时针编号为 \(k = 0, \ldots, 15\),角度为 \(2 \pi k / 16\)。点标签按键值 \((\min(s, 16 - s), [s > 8])\)(\(s = (k - 2) \mod 16\))递增的顺序尝试:按与右上方向 \(k = 2\) 的角距离,角距离相同的两个方向则逆时针者优先。
硬性限制
两种标签都遵守同一条规则:不遮盖任何对象。障碍物包括坐标轴上已绘制的内容:路径的线段、标记与文字的矩形,以及填色区域的多边形。以下搜索函数位于 mosaickit.layout.placement;除 place_beside 外,也都由 mosaickit.layout 导出。它们与几何模块一样,以显示像素为单位运算;scale 则将以点为单位的间距换算为像素。
Obstacles 表示标签必须避开的障碍物;Placement 表示标签的放置结果,包括矩形、引线线段(不画引线的标签为 None)及违反的限制数。Obstacles.extended(segments=..., rects=...) 加入刚放置的标签。
定义 · 违规数
对候选矩形 \(R\)、障碍物 \(O\)、绘图区界线 \(B\) 与多边形集合 \(\mathcal{P}\),违规数为
其中 \([\cdot]\) 在条件成立时为 1,否则为 0。\(V(R) = 0\) 时称候选位置不遮盖任何对象。
各项分别由线段与矩形、Rect.intersects 与与多边形重叠的矩形精确计算。
引线标注
place_callout(
polygon,
size,
obstacles,
bounds,
*,
scale=1.0
) -> Placement
在区域周围为给定大小的引线标注搜索位置。从极点 \(o\) 沿 16 个方向 \(r\),把候选矩形放在距离 ray_exit(o, r, P) 再加 12、24 或 40 pt(近环)之处,并以面向极点的边或角对齐,使矩形朝远离区域的方向延伸。引线从极点拉向矩形上的最近点(参见矩形上的最近点),并在距该点 2 pt 处停止。候选位置的代价为 \(V(R)\)(区域本身也列入多边形),中心不在开阔空间时加一,引线离开自身区域后每穿过一条线、一段文字或一个其他区域加一,每位于一个交叉点之外(参见开阔空间与交叉点)再加一。
定义 · 开阔空间与交叉点
开阔空间是在绘图区 4 pt 网格上、面积至少占十分之一的连通空白区域的联集;较小的空白区域称为口袋,例如两个阴影区域间未填色的窄带,文字放在那里看起来像在为口袋命名。区域的交叉点是两条障碍线段真正交叉(各自严格穿过对方)之处,且位于区域边界上或距边界 1.5 px 以内。从极点 \(o\) 看,若 \((p - x) \cdot (x - o) > 0\),则称点 \(p\) 位于 \(x\) 之外。
越过交叉点后,线条朝远离区域的方向分开;若把标签放在那里,看起来会贴近线条的延伸方向,而不是所命名的区域。交叉点本身由方向测试求得。
引理 · 交叉点
若 \([a, b]\) 与 \([c, d]\) 真正交叉,则它们恰交于一点 \(a + t (b - a)\),其中
而 \(u \times v = u_x v_y - u_y v_x\)。
命题 · 引线标注的选择
以键值(代价, 引线长度)按字典序排列候选位置,并逐方向、由近到远的距离枚举。若近环中有代价为 0 的候选,place_callout 返回其中引线最短的第一个;否则再尝试远环(60 与 90 pt),返回两环中键值最小的第一个候选。结果只取决于参数。
返回的代价不为零时,渲染器仍会在该处画出引线标注,并发出指出该图层的 LayoutWarning;放大画布或缩短文字通常就能消除。
fits_inside(
polygon,
size,
obstacles,
bounds
) -> Rect | None
place_point_label(
footprint,
size,
obstacles,
bounds,
*,
scale=1.0
) -> Placement
place_beside(
anchor,
size,
*,
axis,
direction,
reach,
obstacles,
bounds,
scale=1.0
)
其他搜索:置中于极点的矩形,若放得下且除自身区域外不碰到任何对象就返回它;前述的点标签搜索;以及大括号尖端旁的搜索,在尖端外 3 到 45 pt 尝试,并沿跨距以 3 pt 为步长最多滑动 reach,位移小者优先。place_beside 返回矩形与其违规数。大括号标签在该处没有空位时,渲染器改从尖端尝试引线标注,保留违规较少者。