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

12 投票
2 回答
20304 浏览
提问于 2025-04-17 15:40

我一直在尝试把一堆线旋转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 个回答

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
26

一段线段的中心点坐标(cx, cy)可以通过两个端点(x1, y1)和(x2, y2)来计算:

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

换句话说,这就是两个点的x和y坐标的平均值。

对于一条由多个线段组成的折线,它的逻辑中心点的x和y坐标就是所有点的x和y值的平均值。平均值就是把所有值加起来,然后除以值的数量。

在二维空间中,旋转一个点(x, y)θ弧度的公式是:

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

如果要围绕一个不同的中心点(cx, cy)进行旋转,需要先把这个点的坐标减去旋转中心的坐标,这样就相当于把点“移动”到了新的位置,数学上可以表示为:

    tx = x - cx
    ty = y - cy

然后再按照想要的角度旋转这个中间点,最后再把旋转中心的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])

撰写回答