【问题标题】:Preserving constant line width between transforms在变换之间保持恒定的线宽
【发布时间】:2019-07-09 09:14:24
【问题描述】:

我正在尝试通过应用平移、旋转和缩放变换来绘制一些基本形状。

但是,随着坐标系的缩小,线条变得越来越细(我想保持不变):

请参阅下面的附加代码块,它说明了我已经尝试过的内容。

开罗官方教程提供了这样一种更新线宽的方法:

double ux=1, uy=1;
cairo_device_to_user_distance (cr, &ux, &uy);
if (ux < uy)
    ux = uy;
cairo_set_line_width (cr, ux);

(参见https://cairographics.org/tutorial/,“提示和技巧”/“线宽”部分)

import cairo

def rect(ctx, x, y, w, h):
    ctx.move_to(x, y)
    ctx.rel_line_to(w, 0)
    ctx.rel_line_to(0, h)
    ctx.rel_line_to(-w, 0)
    ctx.close_path()
    ctx.stroke()


surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 300, 300)
context = cairo.Context(surface)

context.scale(300, 300)

# background
context.set_source_rgb(0.5, 0.8, 0.8)
context.paint()

# new stroking color is black
context.set_source_rgb(0, 0, 0)

# translating to the center point
context.translate(0.5, 0.5)

# See https://cairographics.org/tutorial/ -> Tips and Tricks -> Line width
context.set_line_width(context.device_to_user_distance(1, 1)[0])

# So far so good, the rect is ok
rect(context, -0.1, -0.1, 0.2, 0.2)

# With each iteration, I rotate the coordinate system 60˚ clockwise, 
#  translate and scale down a bit
for i in range(6):
    scale_factor = 0.5
    angle = np.pi/3.
    dy = -0.3

    context.rotate(angle)
    context.translate(0, dy)
    context.scale(scale_factor, scale_factor)

    old_lw = context.get_line_width()
    dist = context.device_to_user_distance(1, 1)
    print('{0} Old: {1:2.4f}   New: {2:2.4f}'.format(i, old_lw, dist[0]))
    context.set_line_width(dist[0])

    rect(context, -0.05, -0.05, 0.1, 0.1)

    # Scaling and translating back, keeping current rotation cumulative
    context.scale(1/scale_factor, 1/scale_factor)
    context.translate(0, -dy)

surface.write_to_png('test.png')

打印块产生这个:

0 Old: 0.0033   New: 0.0091
1 Old: 0.0091   New: 0.0024
2 Old: 0.0024   New: -0.0067
3 Old: 0.0000   New: -0.0091
4 Old: 0.0000   New: -0.0024
5 Old: 0.0000   New: 0.0067

所以,我认为问题出在这一行:

dist = context.device_to_user_distance(1, 1)

在迭代时,它开始产生负值。这会导致奇怪和错误的结果:。

要绘制我一开始提到的初始图像,只需要在循环内设置线宽来注释行。

我错在哪里?提前致谢。

【问题讨论】:

  • 想象你的距离“向右”移动一个单位。那是(0,1)的距离。现在您将其旋转 180°。现在它“向左”移动一个单位,因此距离变为 (0,-1)。我认为这就是cairo_device_to_user_distance() 给你负值的原因:因为方向“转身”。

标签: python graphics cairo pycairo


【解决方案1】:

更新:device_to_user_distance 返回负值的原因仍然未知,但问题实际上很容易解决。

在应用任何缩放变换之前,我会根据当前值更新线宽,如下所示:

scale_factor = 0.5
current_lw = context.get_line_width()

# so the new line width value is twice as thick as the old one
new_lw = current_lw/scale_factor

context.scale(scale_factor, scale_factor)
context.set_line_width(new_lw)

# do drawing

# restoring back scaling transform and line width
context.set_line_width(new_lw*scale_factor)
context.scale(1./scale_factor, 1./scale_factor)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 2021-09-05
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    相关资源
    最近更新 更多