【问题标题】:rotate text around its center in pycairo在 pycairo 中围绕其中心旋转文本
【发布时间】:2012-01-17 19:04:50
【问题描述】:

社区。​​p>

我知道这里有很多答案、手册、教程和互联网上的参考资料,以及关于这个问题的更多信息。我也知道需要线性代数的知识。 但是当我考虑到时间去弄清楚所有的理论并在实践中解决练习时 - 我的头晕了,我不能做最简单的事情:(

如果您知道一些快速的解决方案,如何在渲染之前使文本在其中心上旋转 - 请告诉我。

现在我有:

#...
cr.move_to(*text_center)
myX, myY = text_center[0] - (width / 2), text_center[1] + (height / 2)

cr.save()
cr.translate(myX, myY)
cr.rotate(radians(text_angle))
cr.show_text(letter)
cr.restore()
#...

但我的信并没有自转。就像跌到右侧一样:( 我知道我的代码不正确。也许我错过了转型,但我不知道如何让它正确。

更新:很遗憾,文本不受翻译影响,因此

cr.translate(10000, 10000)
cr.rotate(radians(15))
cr.show_text("hello")

将完全一样

cr.rotate(radians(15))
cr.show_text("hello")

而且我不知道如何在不创建新表面或其他东西(如图形处理器中的新层)的情况下使文本在其中心旋转:(

【问题讨论】:

    标签: python graphics rotation cairo pycairo


    【解决方案1】:

    至少在我的机器上可用的 cairo 版本 (1.8.8) 上,以下方法适用于我:

    def text(ctx, string, pos, theta = 0.0, face = 'Georgia', font_size = 18):
        ctx.save()
    
        # build up an appropriate font
        ctx.select_font_face(face , cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
        ctx.set_font_size(font_size)
        fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents()
        x_off, y_off, tw, th = ctx.text_extents(string)[:4]
        nx = -tw/2.0
        ny = fheight/2
    
        ctx.translate(pos[0], pos[1])
        ctx.rotate(theta)
        ctx.translate(nx, ny)
        ctx.move_to(0,0)
        ctx.show_text(string)
        ctx.restore()
    

    可以通过以下方式使用:

    width = 500
    height = 500
    surface = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height)
    ctx = cairo.Context(surface)
    ctx.set_source_rgb(1,1,1)
    rect(ctx, (0,0), (width, height), stroke=False)
    ctx.set_source_rgb(0,0,0)
    for i in xrange(5):
        for j in xrange(5):
            x = 100 * i + 20
            y = 100 * j + 20
            theta = math.pi*0.25*(5*i+j)
            text(ctx, 'hello world', (x, y), theta, font_size=15)
    surface.write_to_png('text-demo.png')
    

    【讨论】:

    • 天才和完美!哦,因为我问了这个问题,所以我冻结了我的项目并打开了数学书直到现在。我知道您的解决方案是我想要的,如果您不介意,我会简单地粘贴我的代码并将您的名字写在 cmets 中。但是数学很棒而且很有趣,所以我会继续学习新的东西。你能告诉我在数学书中哪里可以找到你的解决方案:它是如何命名的,它是什么?感谢您的帮助。
    • @Schollii 是正确的,但事实证明,Cairo API 的一些复杂之处使这变得有点有趣。关键是旋转总是围绕原点发生。这意味着您需要将原点转换为要绘制文本的位置。然后你可以做你的旋转。最后,为了确保渲染的文本通过您的点,您需要进行最后一次平移(在旋转的坐标系中)。 move_to 命令确保文本将从原点呈现。
    • 这种数学可以用Transformation Matrices这个词来描述,这实际上只是一种表达坐标变换的方式。从广义上讲,这是一个线性代数问题。这项任务在力学中尤为重要(这反过来对涉及物理、机器人和游戏开发的软件开发人员也很重要)。
    • 当然,Schollii 是对的,但是 python 中的三角函数会大大降低精度。乍一看,您的方法非常精确,而且可能更快。我将在 Web 应用程序中使用此代码,它对于动态图像渲染和浮点运算很重要。多谢一次。线性代数在路上:)
    • 似乎对我不起作用。我的特殊情况可能是我只使用单个字符。有什么想法吗?
    【解决方案2】:

    好的,所以 cairo 允许文本 move_to 和旋转。这意味着您想要找出 move_to (T) 的 (x,y),这样当您旋转 (R) 时,文本的中心点位于您想要的位置,c=(cx,cy):

    所以你必须解方程 Mv = c,其中 v 是相对于文本原点的文本中心:

    M = T*R
    
    T = (1 0 x)
        (0 1 y)
        (0 0 1)
    
    R =  (cos r    -sin r   0)
         (sin r     cos r   0)
         (0            0    1)
    
    v = (w/2, h', 1)
    
    c = (cx, cy, 1)
    
    h' = h/2 - (h - y_bearing)
    

    健全性检查:

    • 当 r 为 0(无旋转)时,得到 x=cx-w/2, y=cy-h',你知道 是正确的答案
    • 当 r=-90(文本横向,“向上”向右)时,您会得到预期的结果, 即 x = cx - h' 和 y = cy + w/2

    对于 python 代码,您必须重写上面的等式,最终得到 A*t=b,其中 t=(x,y),并且您将计算 t = inv(A)*b。然后,您将简单地做

    cr.move_to(x, y)
    cr.rotate(r)
    cr.show_text(yourtext)
    

    请注意,cairo 中的坐标系有 +y 下降,因此将有几个迹象需要修复,也许 y_bearing 不正确,但你明白了。

    【讨论】:

    • "将文本放在 text_center" - 我该怎么做?我只有分离的函数 cr.move_to(x, y) 和分离的 cr.show_text(text)。我什么时候必须做 move_to() - 在翻译和旋转之前或之后和之前放置文本?
    • my text_center 表示原点 x、y 的坐标,用于将文本准确地放置在其(文本)中心(w/2,h/2)与首选点重叠。
    • 这些代码不起作用,也不会起作用,因为旋转总是围绕 current_point 进行。如果我写:cr.move_to(a, b); cr.rotate(rad); cr.show_text(); - 它只会围绕 (a, b) 旋转,并且平移不会影响旋转。但我知道有一些像 [here][1] 这样的公式可以计算新的坐标移动到哪里。 [1]:codeproject.com/KB/GDI/textrotation.aspx?display=PrintAll
    • 非常感谢您的扩展回答。我无法理解其中的一些事情,但我会尝试弄清楚,因为在我自己的头脑中理解所有这些对我来说非常重要 =) 非常感谢!
    • @Крайст 如果你能让每个人都知道这是否是答案(标记为答案),或者至少有用(投票,并评论你的发现),那就太好了。
    【解决方案3】:

    应该

    myX, myY = text_center[0] + (height / 2), text_center[1] - (width / 2)
    

    成为

    myX, myY = text_center[0] - (width / 2), text_center[1] + (height / 2)
    

    ?

    这或许可以解释为什么它掉到右侧

    【讨论】:

    • 哦,拜托,这是我的错。我已经在手机上写了这段代码。在真正的代码上,它就像你的例子一样安静。但是当我回家时,我会检查。你认为翻译是我唯一需要的转变吗?
    • 这不是错误。结果是一样的。也许复杂的东西会解决这种情况?可能是新的转换矩阵或不同的代码顺序?
    【解决方案4】:

    基于上述输入的类函数,支持多行文本。

    def text(self, text, x, y, rotation=0, fontName="Arial", fontSize=10, verticalPadding=0):
    
        rotation = rotation * math.pi / 180
    
        self.ctx.select_font_face(fontName, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
        self.ctx.set_font_size(fontSize)
    
        fascent, fdescent, fheight, fxadvance, fyadvance = self.ctx.font_extents()
    
        self.ctx.save()
        self.ctx.translate(x, y)
        self.ctx.rotate(rotation)
    
        lines = text.split("\n")
    
        for i in xrange(len(lines)):
            line = lines[i]
            xoff, yoff, textWidth, textHeight = self.ctx.text_extents(line)[:4]
    
            offx = -textWidth / 2.0
            offy = (fheight / 2.0) + (fheight + verticalPadding) * i
    
            self.ctx.move_to(offx, offy)
            self.ctx.show_text(line)
    
        self.ctx.restore()
    

    【讨论】:

    • 过去 5 年有什么变化吗?这是我最喜欢的项目,我很久以前就放弃了,开始重新学习数学。从那以后我就再也没有回到这个项目了。不过,我很想再试一次。
    • 12 改为 17。
    • 我的意思是 cairo/pycairo
    猜你喜欢
    • 2014-09-30
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多