简体   繁体   English

如何以任意角度绘制文本并平行于一条线?

[英]How can I draw text at any angle above and parallel to a line?

I want to place a text centrally above the line (controlled with variable distance ).我想在线上方放置一个文本(用可变distance控制)。 There is a method drawLineDescription() for this.为此有一个方法drawLineDescription() This method takes the start and endpoints of the lines and then calculates the center point x, y .此方法获取直线的起点和终点,然后计算中心点x, y I have already worked with angle to ensure that the text is placed correctly.我已经使用angle来确保文本放置正确。 Unfortunately, I can't figure out how to place the text vertically over the line at every angle, ie depending on the rotation the variables x, y have to be able to move.不幸的是,我无法弄清楚如何将文本以每个角度垂直放置在线上,即根据旋转,变量x, y必须能够移动。 How can I supplement this?我该如何补充呢?

def drawLineDescription(canvas, startX, startY, endX, endY, distance):
        lengthX = endX - startX
        lengthY = endY - startY
        x = int(startX+((lengthX)/2))
        y = int(startY+((lengthY)/2))

        angle = math.degrees(math.atan2(lengthY, lengthX)*-1)
        angle = round(angle)
        if angle < -90 or angle > 90:
           angle += 180

        canvas.create_text(x, y, angle=angle, font=("Arial", 12), text="exampleText")

In the end it should look like this (example of multiple lines with text - the lines never cross their text): Example result最后它应该看起来像这样(带有文本的多行示例 - 这些行永远不会交叉它们的文本):示例结果

在此处输入图像描述

lengthX = endX - startX
lengthY = endY - startY
fullLength = math.sqrt(lengthX**2 + lengthY**2)
#unit direction vector
ux = lengthX / fullLength
uy = lengthY / fullLength
#unit normal
if ux < 0:
    nx, ny = -uy, ux
else:
    nx, ny = uy, -ux
#text center point (D at the picture)
cx = x + nx * distance
cy = y + ny * distance

#if you need start of text (S at the picture)
sx = x + nx * distance - ux * halfwidth
sy = y + ny * distance - uy * halfwidth

You can draw rotated text on tkinter if you are using tcl > 8.6 with the following instructions: canvas_item = tk.create_text , and canvas.itemconfig(canvas_item, angle=rotation_angle)如果您使用的是tcl > 8.6 ,则可以在 tkinter 上绘制旋转文本,说明如下: canvas_item = tk.create_textcanvas.itemconfig(canvas_item, angle=rotation_angle)

In order to achieve what you want, you need a little bit of geometry, notably the coordinates of the line segment, its mid point, an offset vector perpendicular to the segment, and the angle of the segment.为了达到你想要的效果,你需要一点几何知识,特别是线段的坐标、它的中点、垂直于线段的偏移向量,以及线段的角度。

I encapsulated the arithmetic necessary to calculate the proper geometric elements in a class point , and in c class Vector .我将计算适当几何元素所需的算法封装在 class point和 c class Vector中。 These classes are not bullet proof, but they give you a starting point for basic geometry.这些课程不是防弹的,但它们为您提供了基本几何的起点。

I added an example of a line defined by two points, with the text placed as you need and rotated to match the direction of the line segment.我添加了一个由两点定义的线示例,根据需要放置文本并旋转以匹配线段的方向。

在此处输入图像描述

import math
import tkinter as tk


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other: 'Vector'):
        return Vector(other.x + self.x, other.y + self.y)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)

    def __iter__(self):
        yield self.x
        yield self.y

    def __str__(self):
        return f'{self.__class__.__name__}({self.x}, {self.y})'


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(other.x + self.x, other.y + self.y)

    def __sub__(self, other):
        return Vector(other.x - self.x, other.y - self.y)

    def scale(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    def normal(self):
        norm = self.norm()
        return Vector(self.x / norm, self.y / norm)

    def norm(self):
        return math.hypot(self.x, self.y)

    def perp(self):
        x, y = self.normal()
        return Vector(y, -x)

    def angle(self):
        return math.atan2(-self.y, self.x) * (180 / math.pi)

    def __iter__(self):
        yield self.x
        yield self.y

    def __str__(self):
        return f'{self.__class__.__name__}({self.x}, {self.y})'


if __name__ == '__main__':

    root = tk.Tk()
    canvas = tk.Canvas(root, width=500, height=500)

    p0, p1 = Point(100, 40), Point(200, 300)
    segment = p1 - p0
    mid_point = segment.scale(0.5) + p0
    # canvas.create_oval(*(mid_point - Vector(2, 2)), *(Vector(2, 2) + mid_point))

    line = canvas.create_line(*p0, *p1)
    offset = segment.perp().scale(20)
    # canvas.create_line(*mid_point, *(mid_point+offset))

    txt = canvas.create_text(*(offset + mid_point), text='example')
    canvas.itemconfig(txt, angle=segment.angle())

    canvas.pack()
    root.mainloop()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM