如何防止在文本和形状之间绘制额外的线?

How to prevent an extra line to be drawn between text and shape?

我正在为 Cairo 图形库尝试 PyCairo 绑定。混合文本和弧线时遇到问题。在我的代码中,我画了一个圆圈,然后在它附近画了一个文本,在一个循环中绘制了 10 个圆圈及其相关文本。

使用ctx.show_text()绘制文本时,当前位置设置为前进点(应写入下一个字符的位置)。问题是在当前点和后续圆的第一个点之间画了一条线。

我看到的唯一可能是在画圆之前使用ctx.move_to()将当前点移动到圆弧起点。在这种情况下这不是一个大问题,因为第一个点可以很容易地计算出来,而且我已经有一个函数可以将极坐标(角度 0 和距离 = 半径)转换为 move_to() 所需的笛卡尔坐标。我还是宁愿不这样做,因为其他情况可能不那么明显。

我想知道我是否遗漏了什么,是否还有另一种可能性,比如在画圆之前删除当前点的命令。另外,这个问题似乎只与绘制文本有关,因为如果没有绘制文本,则没有连接各个小圆圈的线,尽管它们也是使用多个命令绘制的:

为什么添加文本会产生不需要的线条?我该如何解决?

import math
import cairo

def polar_to_cart(cx, cy, angle, dist):
    x = cx + math.cos(angle) * dist
    y = cy - math.sin(angle) * dist
    return x,y

cx,cy = 150,150
two_pi = 2 * math.pi
radius = 100

# 300x300 px surface
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 2*cx, 2*cy)
ctx = cairo.Context(surface)

# Draw large circle
ctx.set_source_rgb(0,0,0)
ctx.set_line_width(1)
ctx.arc(cx, cy, radius, 0, two_pi)
ctx.stroke()

# Draw small circles
n = 10
for i in range(n):
    # Center location
    x,y = polar_to_cart(cx, cy, two_pi / n * i, radius)

    # Draw an empty circle at x,y
    ctx.arc(x, y, 10, 0, two_pi)    
    ctx.set_source_rgb(1,0,0)
    ctx.set_line_width(1)
    ctx.stroke()

    # Name location (bbox center)
    name = str(i)
    xbbc,ybbc = polar_to_cart(cx, cy, two_pi / n * i, radius + 25)

    # Equivalent reference point location
    x_bearing, y_bearing, width, height = ctx.text_extents(name)[:4]
    xrp = xbbc - width/2 - x_bearing
    yrp = ybbc - height/2 - y_bearing

    # Draw name
    ctx.set_source_rgb(0,0,1)
    ctx.select_font_face("Tahoma", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
    ctx.set_font_size(16)
    ctx.move_to(xrp,yrp)
    ctx.show_text(name)

surface.write_to_png('_temp.png')

正如 cairo_show_text 的文档所解释的那样,

After this call the current point is moved to the origin of where the next glyph would be placed in this same progression. That is, the current point will be at the origin of the final glyph offset by its advance values. This allows for easy display of a single logical string with multiple calls to cairo_show_text().

意思是文字绘制完成后,当前路径由一个点组成。 ctx.arc 方法附加到当前路径,在这种情况下意味着通过直线将该点连接到圆的第一个点。这是不需要的红线。

要解决此问题,您可以将调用 ctx.show_text(name) 替换为

    ctx.text_path(name)
    ctx.fill()

其中ctx.fill()会在执行填充后隐式清除当前路径。 (ctx.stroke() 会绘制字体轮廓。)

或者,您可以添加

   ctx.new_path()

在调用ctx.show_text(name)清空路径后,但是这样有点不优雅。