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

时间:2013-02-12 21:22:55

标签: python rotation trigonometry

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

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

这是我写的:

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])

2 个答案:

答案 0 :(得分:21)

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

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

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

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

原点(0,0)周围rotate a 2D point(x,y)θ弧度的通式为:

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

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

    tx = x - cx
    ty = y - cy

然后将此中间点旋转所需的角度,最后将旋转点的x和y值添加到每个坐标的x和y。在几何方面,它是以下操作序列: 翻译旋转不翻译

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

为了简化该计算的实现,所有三组计算的数值结果可以组合并用一对数学公式表示,这些公式同时执行它们。因此,通过使用以下方法旋转现有点(x,y),θ点周围的点(cx,cy),可以获得新点(x',y')

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

将此数学/几何概念合并到您的函数中会产生以下结果:

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])

答案 1 :(得分:2)

您的中心点将是:

centerX = (x2 - x1) / 2 + x1
centerY = (y2 - y1) / 2 + y1

因为你花了一半的长度(x2 - x1) / 2并将它添加到你的线开始到达中间的位置。

作为练习,请走两行:

line1 = (0, 0) -> (5, 5)
then: |x1 - x2| = 5, when the center x value is at 2.5.

line2 = (2, 2) -> (7, 7)
then: |x1 - x2| = 5, which can't be right because that's the center for
the line that's parallel to it but shifted downwards and to the left