1. 概述

在计算机图形学和游戏开发中,围绕某个点旋转顶点的基本技能至关重要。本快速教程将探讨使用Java实现定点旋转的不同方法。

2. 理解问题陈述

假设我们在二维平面上有两个点:A点坐标为(x1, y1),B点坐标为(x2, y2)。我们希望将A点绕B点旋转一定角度。如果旋转角度为正,则逆时针旋转;如果旋转角度为负,则顺时针旋转:

上图中,A'点是旋转后的点。从A到A'的旋转是逆时针的,表示旋转角度为45度。

3. 使用原点作为旋转点

在这个方法中,我们将首先将顶点和旋转点转换到原点。转换后,我们将按照所需的角度在原点周围进行旋转。完成旋转后,我们将它们恢复到原始位置。

3.1. 绕原点旋转点P

首先,让我们理解如何绕原点旋转点P。对于旋转,我们将使用涉及三角函数的公式。逆时针旋转点P(x, y)围绕原点(0,0)的新坐标计算公式为:

rotatedXPoint = x * cos(angle) - y * sin(angle)
rotatedYPoint = x * sin(angle) + x * cos(angle)

rotatedXPointrotatedYPoint表示旋转后点P的新坐标。如果需要顺时针旋转,我们需要使用负旋转角度。

3.2. 绕给定点旋转

我们将把旋转点移动到原点,通过从顶点的x坐标中减去旋转点的x坐标,以及从顶点的y坐标中减去旋转点的y坐标。

这些转换后的坐标表示顶点相对于新原点的位置。然后,我们将按照之前描述的方式进行旋转,并应用反向平移,即加上x和y坐标。

现在让我们用这种方法旋转一个顶点:

public Point2D.Double usingOriginAsRotationPoint(Point2D.Double vertex, Point2D.Double rotationPoint, double angle) {
    double translatedToOriginX = vertex.x - rotationPoint.x;
    double translatedToOriginY = vertex.y - rotationPoint.y;

    double rotatedX = translatedToOriginX * Math.cos(angle) - translatedToOriginY * Math.sin(angle);
    double rotatedY = translatedToOriginX * Math.sin(angle) + translatedToOriginY * Math.cos(angle);

    double reverseTranslatedX = rotatedX + rotationPoint.x;
    double reverseTranslatedY = rotatedY + rotationPoint.y;

    return new Point2D.Double(reverseTranslatedX, reverseTranslatedY);
}

让我们测试这个方法来旋转顶点:

void givenRotationPoint_whenUseOrigin_thenRotateVertex() {
    Point2D.Double vertex = new Point2D.Double(2.0, 2.0);
    Point2D.Double rotationPoint = new Point2D.Double(0.0, 1.0);
    double angle = Math.toRadians(45.0);
    Point2D.Double rotatedVertex = VertexRotation.usingOriginAsRotationPoint(vertex, rotationPoint, angle);

    assertEquals(0.707, rotatedVertex.getX(), 0.001);
    assertEquals(3.121, rotatedVertex.getY(), 0.001);
}

4. 使用AffineTransform

在这个方法中,我们将利用java.awt.geom.AffineTransform类,它用于执行诸如平移、缩放、旋转和翻转等几何变换。

首先,我们将使用getRotateInstance()方法根据指定的角度和旋转点创建一个旋转变换矩阵。然后,我们将使用transform()方法对顶点应用变换并进行旋转。让我们看看这个方法:

public Point2D.Double usingAffineTransform(Point2D.Double vertex, Point2D.Double rotationPoint, double angle) {
    AffineTransform affineTransform = AffineTransform.getRotateInstance(angle, rotationPoint.x, rotationPoint.y);
    Point2D.Double rotatedVertex = new Point2D.Double();
    affineTransform.transform(vertex, rotatedVertex);
    return rotatedVertex;
}

让我们测试这个方法来旋转一个顶点:

void givenRotationPoint_whenUseAffineTransform_thenRotateVertex() {
    Point2D.Double vertex = new Point2D.Double(2.0, 2.0);
    Point2D.Double rotationPoint = new Point2D.Double(0.0, 1.0);
    double angle = Math.toRadians(45.0);
    Point2D.Double rotatedVertex = VertexRotation.usingAffineTransform(vertex, rotationPoint, angle);

    assertEquals(0.707, rotatedVertex.getX(), 0.001);
    assertEquals(3.121, rotatedVertex.getY(), 0.001);
}

5. 总结

在这篇教程中,我们讨论了围绕特定点旋转顶点的方法。如往常一样,示例代码可以在GitHub上找到。