给定两个顶点围绕中心点旋转线

2022-01-16 00:00:00 python trigonometry rotation

问题描述

我一直在尝试将一堆线旋转 90 度(它们一起形成一条折线).每行包含两个顶点,例如 (x1, y1) 和 (x2, y2).我目前正在尝试做的是围绕线的中心点旋转,给定中心点 |x1 - x2|和 |y1 - y2|.出于某种原因(我不是很精通数学)我无法让线条正确旋转.

I've been trying to rotate a bunch of lines by 90 degrees (that together form a polyline). Each line contains two vertices, say (x1, y1) and (x2, y2). What I'm currently trying to do is rotate around the center point of the line, given center points |x1 - x2| and |y1 - y2|. For some reason (I'm not very mathematically savvy) I can't get the lines to rotate correctly.

有人可以验证这里的数学是正确的吗?我认为这可能是正确的,但是,当我将线的顶点设置为新的旋转顶点时,下一行可能不会从上一行抓取新的 (x2, y2) 顶点,从而导致线旋转不正确.

Could someone verify that the math here is correct? I'm thinking that it could be correct, however, when I set the line's vertices to the new rotated vertices, the next line may not be grabbing the new (x2, y2) vertex from the previous line, causing the lines to rotate incorrectly.

这是我写的:

def rotate_lines(self, deg=-90):
    # Convert from degrees to radians
    theta = math.radians(deg)

    for pl in self.polylines:
        self.curr_pl = pl
        for line in pl.lines:
            # Get the vertices of the line
            # (px, py) = first vertex
            # (ox, oy) = second vertex
            px, ox = line.get_xdata()
            py, oy = line.get_ydata()

            # Get the center of the line
            cx = math.fabs(px-ox)
            cy = math.fabs(py-oy)

            # Rotate line around center point
            p1x = cx - ((px-cx) * math.cos(theta)) - ((py-cy) * math.sin(theta))
            p1y = cy - ((px-cx) * math.sin(theta)) + ((py-cy) * math.cos(theta))

            p2x = cx - ((ox-cx) * math.cos(theta)) - ((oy-cy) * math.sin(theta))
            p2y = cy - ((ox-cx) * math.sin(theta)) + ((oy-cy) * math.cos(theta))

            self.curr_pl.set_line(line, [p1x, p2x], [p1y, p2y])


解决方案

点(x1,y1)和(x2,y2)之间的线段的中心点(cx,cy)坐标为:

The coordinates of the center point (cx,cy) of a line segment between points (x1,y1) and (x2,y2) are:

    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2

换句话说,它只是两对 x 和 y 坐标值的平均值或算术平均值.

In other words it's just the average, or arithmetic mean, of the two pairs of x and y coordinate values.

对于多段线或折线,其逻辑中心点的 x 和 y 坐标只是所有点的 x 和 y 值的相应平均值.平均值只是值的总和除以它们的数量.

For a multi-segmented line, or polyline, its logical center point's x and y coordinates are just the corresponding average of x and y values of all the points. An average is just the sum of the values divided by the number of them.

旋转二维点 (x,y) θ 弧度的一般公式围绕原点 (0,0) 是:

The general formulas to rotate a 2D point (x,y) θ radians around the origin (0,0) are:

    x′ = x * cos(θ) - y * sin(θ)
    y′ = x * sin(θ) + y * cos(θ)

要围绕不同的中心(cx, cy)进行旋转,需要通过首先从该点的坐标中减去所需旋转中心的坐标来调整该点的 x 和 y 值,其效果为移动(在几何学中称为 translating)它在数学上表示如下:

To perform a rotation about a different center (cx, cy), the x and y values of the point need to be adjusted by first subtracting the coordinate of the desired center of rotation from the point's coordinate, which has the effect of moving (known in geometry as translating) it is expressed mathematically like this:

    tx = x - cx
    ty = y - cy

然后将此中间点旋转所需的角度,最后将旋转点的 x 和 y 值返回添加到每个坐标的 x 和 y.在几何术语中,它是以下操作序列:Tʀᴀɴsʟᴀᴛᴇ ─► Rᴏᴛᴀᴛᴇ ─► Uɴᴛʀᴀɴsʟᴀᴛᴇ.

then rotating this intermediate point by the angle desired, and finally adding the x and y values of the point of rotation back to the x and y of each coordinate. In geometric terms, it's the following sequence of operations:  Tʀᴀɴsʟᴀᴛᴇ ─► Rᴏᴛᴀᴛᴇ ─► Uɴᴛʀᴀɴsʟᴀᴛᴇ.

这个概念可以扩展到允许围绕任意点(例如它自己的逻辑中心)旋转整条折线,只需将描述的数学应用于其中每个线段的每个点.

This concept can be extended to allow rotating a whole polyline about any arbitrary point—such as its own logical center—by just applying the math described to each point of each line segment within it.

为了简化这个计算的实现,所有三组计算的数值结果可以用一对同时执行它们的数学公式组合和表达.所以一个新的点 (x′,y′) 可以通过旋转一个现有的点 (x,y) 得到一个新的点 (x',y'), θ 弧度围绕点 (cx, cy) 使用:

To simplify implementation of this computation, the numerical result of all three sets of calculations can be combined and expressed with a pair of mathematical formulas which perform them all simultaneously. So a new point (x′,y′) can be obtained by rotating an existing point (x,y), θ radians around the point (cx, cy) by using:

    x′ = (  (x - cx) * cos(θ) + (y - cy) * sin(θ) ) + cx
    y′ = ( -(x - cx) * sin(θ) + (y - cy) * cos(θ) ) + cy

将此数学/几何概念融入您的函数会产生以下结果:

Incorporating this mathematical/geometrical concept into your function produces the following:

from math import sin, cos, radians

def rotate_lines(self, deg=-90):
    """ Rotate self.polylines the given angle about their centers. """
    theta = radians(deg)  # Convert angle from degrees to radians
    cosang, sinang = cos(theta), sin(theta)

    for pl in self.polylines:
        # Find logical center (avg x and avg y) of entire polyline
        n = len(pl.lines)*2  # Total number of points in polyline
        cx = sum(sum(line.get_xdata()) for line in pl.lines) / n
        cy = sum(sum(line.get_ydata()) for line in pl.lines) / n

        for line in pl.lines:
            # Retrieve vertices of the line
            x1, x2 = line.get_xdata()
            y1, y2 = line.get_ydata()

            # Rotate each around whole polyline's center point
            tx1, ty1 = x1-cx, y1-cy
            p1x = ( tx1*cosang + ty1*sinang) + cx
            p1y = (-tx1*sinang + ty1*cosang) + cy
            tx2, ty2 = x2-cx, y2-cy
            p2x = ( tx2*cosang + ty2*sinang) + cx
            p2y = (-tx2*sinang + ty2*cosang) + cy

            # Replace vertices with updated values
            pl.set_line(line, [p1x, p2x], [p1y, p2y])

相关文章