【问题标题】:How to rotate a vertex around a certain point?如何围绕某个点旋转顶点?
【发布时间】:2012-08-28 14:16:05
【问题描述】:

假设您在二维空间中有两个点,您需要将其中一个点旋转 X 度,另一个点作为中心。

float distX = Math.abs( centerX -point2X );
float distY = Math.abs( centerY -point2Y );

float dist = FloatMath.sqrt( distX*distX + distY*distY );

到目前为止,我只是找到了两点之间的距离......我应该从哪里开始?

【问题讨论】:

标签: java math geometry


【解决方案1】:

最简单的方法是组合三个转换:

  1. 将点 1 带到原点的翻译
  2. 绕原点旋转所需角度​​
  3. 将点 1 带回其原始位置的翻译

当你完成这一切时,你最终会得到以下转换(其中x 是所需的旋转角度,以弧度为单位):

newX = centerX + (point2x-centerX)*Math.cos(x) - (point2y-centerY)*Math.sin(x);

newY = centerY + (point2x-centerX)*Math.sin(x) + (point2y-centerY)*Math.cos(x);

请注意,这假设x 的角度对于顺时针旋转为负(所谓的standard or right-hand orientation 用于坐标系)。如果不是这种情况,那么您需要在涉及sin(x) 的条款上颠倒符号。

【讨论】:

  • @mathematician1975 - 逆时针旋转的角度应该是正的,顺时针旋转的角度应该是负的。这几乎是一个通用标准,除非有明确的声明(没有)。不过,我更新了答案以澄清。谢谢。
  • 好吧。只是认为,由于 OP 在此之前可能没有做过类似的事情,他可能不知道这一点,也不会伤害到指定约定。
  • 带有(+x=right, +y=up) 的传统方格纸坐标是带有(+angles=counter-clockwise) 的“右手”。但是(+x=right, +y=down) 的常规屏幕坐标是(+angles=clockwise) 的“左手”。
  • @comingstorm - 好点。我想准确的说法是正旋转角度将 +x 轴移向 +y 轴。
  • 我想构建一个与following page 中显示的类似的功能。我的解决方案是将transform: rotate(120deg) 应用于具有透明背景的圆形图像。图像有heightwidth: 100% 的父级,rotate(120deg) 将围绕它的中心旋转整个图像
【解决方案2】:

你需要一个二维旋转矩阵http://en.wikipedia.org/wiki/Rotation_matrix

你的新观点是

 newX = centerX + ( cosX * (point2X-centerX) + sinX * (point2Y -centerY))
 newY = centerY + ( -sinX * (point2X-centerX) + cosX * (point2Y -centerY))

因为你是顺时针而不是逆时针旋转

【讨论】:

    【解决方案3】:

    假设您正在使用 Java Graphics2D API,请尝试此代码 -

        Point2D result = new Point2D.Double();
        AffineTransform rotation = new AffineTransform();
        double angleInRadians = (angle * Math.PI / 180);
        rotation.rotate(angleInRadians, pivot.getX(), pivot.getY());
        rotation.transform(point, result);
        return result;
    

    其中枢轴是您旋转的点。

    【讨论】:

    • Java 中也有Math.toRadians() ;-)
    【解决方案4】:
    1. 将“1”翻译成0,0

    2. 旋转

      x = sin(角度) * r; y = cos(角度) * r;

    3. 翻译回来

    【讨论】:

    • 不准确。 OP想要围绕特定点旋转。正如@Ted Hopp 所说,必须翻译到原点,应用旋转,然后再次翻译到原始位置。 (没有平移,旋转将围绕屏幕的 0,0)
    • 公平地说,OP确实发布了一张巨幅图片,指示原点为1。
    • 如您所知,要围绕特定点旋转某些东西,您只需将该点翻译为“零”,旋转,然后将其翻译回来......
    • @MarcBollinger - 图片显示点 1 位于旋转中心。 (是的,有坐标轴,但是从什么时候开始标记为“1”的原点?加上措辞,至少应该是一个线索。)
    【解决方案5】:

    这是一个关心旋转方向的版本。右(顺时针)为负,左(逆时针)为正。您可以发送一个点或二维向量并在此方法(最后一行)中设置其基元,以避免为性能分配内存。您可能需要将 vector2 和 mathutils 替换为您使用的库或 java 的内置点类,您可以使用 math.toradians() 代替 mathutils。

    /**
     * rotates the point around a center and returns the new point
     * @param cx x coordinate of the center
     * @param cy y coordinate of the center
     * @param angle in degrees (sign determines the direction + is counter-clockwise - is clockwise)
     * @param px x coordinate of point to rotate 
     * @param py y coordinate of point to rotate 
     * */
    
    public static Vector2 rotate_point(float cx,float cy,float angle,float px,float py){
        float absangl=Math.abs(angle);
        float s = MathUtils.sin(absangl * MathUtils.degreesToRadians);
        float c = MathUtils.cos(absangl * MathUtils.degreesToRadians);
    
        // translate point back to origin:
        px -= cx;
        py -= cy;
    
        // rotate point
        float xnew;
        float ynew;
        if (angle > 0) {
            xnew = px * c - py * s;
            ynew = px * s + py * c;
        }
        else {
            xnew = px * c + py * s;
            ynew = -px * s + py * c;
        }
    
        // translate point back:
        px = xnew + cx;
        py = ynew + cy;
        return new Vector2(px, py);
    }
    

    请注意,这种方式比您在帖子中尝试的方式具有更高的性能。因为您使用的 sqrt 非常昂贵,并且如果您想知道的话,可以通过查找表将角度转换为弧度。因此它具有非常高的性能。

    【讨论】:

      【解决方案6】:

      这是一种在 2D 中围绕任何其他点旋转任意点的方法。请注意,在 3D 中,这可以用作围绕 z 轴的旋转,因为它不会改变,所以被输入点的 z 坐标。也可以轻松实现 3D 中绕 x 轴和 y 轴的旋转。

      代码在 JavaScript 中。开头的注释行是该功能的测试集。它们也可作为使用示例。

      //A = new Array(0,0)
      //S = new Array(-1,0)
      //fi = 90
      //alert("rotujBod: " + rotatePoint(A, S, fi))
      
      function rotatePoint(A, S, fi) {
      /** IN points A - rotated point, S - centre, fi - angle of rotation (rad)
      *    points in format  [Ax, Ay, Az], angle fi (float)
      *       OUT point B
      */
          r = Math.sqrt((A[0] - S[0])*(A[0] - S[0]) + (A[1] - S[1])*(A[1] - S[1]))
          originOfRotation = new Array(S[0] + r, S[1])
          if (A[1] < S[1]) {
              A2 = new Array(A[0], -1*A[1])
              originalAngle = -1*sizeOfAngle(originOfRotation, S, A2)
          } else {
          originalAngle = sizeOfAngle(originOfRotation, S, A)
          }
          x = S[0] + r*Math.cos(fi + originalAngle)
          y = S[1] + r*Math.sin(fi + originalAngle)
          B = new Array(x, y)
          return(B)
      }
      
      function sizeOfAngle(A, S, B) {
          ux = A[0] - S[0]
          uy = A[1] - S[1]
          vx = B[0] - S[0]
          vy = B[1] - S[1]
          if((Math.sqrt(ux*ux + uy*uy)*Math.sqrt(vx*vx + vy*vy)) == 0) {return 0}
          return Math.acos((ux*vx + uy*vy)/(Math.sqrt(ux*ux + uy*uy)*Math.sqrt(vx*vx + vy*vy)))
      }
      

      【讨论】:

      • 你有这个功能的3D版本吗?
      • 我来看看。我确实有它,但我将不得不寻找它。这是一种可怕的递归,有点像牛顿的近似,避免使用矩阵。我想把它贴在 Stack Overflow 的某个地方,但后来找不到了。它应该在我的旧备份中。
      • 不用了,我已经在这里实现了解决方案:stackoverflow.com/questions/59242195/…
      猜你喜欢
      • 1970-01-01
      • 2010-10-11
      • 1970-01-01
      • 2013-01-28
      • 1970-01-01
      • 1970-01-01
      • 2019-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多