【问题标题】:Calculate coordinates of a regular polygon's vertices计算正多边形顶点的坐标
【发布时间】:2011-03-27 01:45:18
【问题描述】:

我正在编写一个程序,我需要在其中绘制任意数量的边的多边形,每个边都由一个动态变化的给定公式转换。涉及一些相当有趣的数学,但我被困在这个问题上。

如何计算正多边形(所有角度都相等)的顶点坐标,仅考虑边数,并且理想情况下(但不是必须)具有原点在中心?

例如:一个六边形可能有以下几点(都是floats):

( 1.5  ,  0.5 *Math.Sqrt(3) )
( 0    ,  1   *Math.Sqrt(3) )
(-1.5  ,  0.5 *Math.Sqrt(3) )
(-1.5  , -0.5 *Math.Sqrt(3) )
( 0    , -1   *Math.Sqrt(3) )
( 1.5  , -0.5 *Math.Sqrt(3) )

我的方法是这样的:

void InitPolygonVertexCoords(RegularPolygon poly)

并且需要将坐标添加到此(或类似的东西,如列表):

Point[] _polygonVertexPoints;

我主要对这里的算法感兴趣,但 C# 中的示例会很有用。我什至不知道从哪里开始。 我应该如何实现它?有可能吗?!

谢谢。

【问题讨论】:

  • 有趣的附带事实:没有正多边形(正方形除外)具有整数坐标 (proof)
  • 这不是编程/编码,这是几何学!

标签: c# algorithm math geometry polygon


【解决方案1】:
for (i = 0; i < n; i++) {
  printf("%f %f\n",r * Math.cos(2 * Math.PI * i / n), r * Math.sin(2 * Math.PI * i / n));
}

其中r 是外接圆的半径。对不起,错误的语言没有 Habla C#。

基本上任意两个顶点之间的夹角都是2 pi / n,并且所有的顶点都在距离原点r处。

编辑: 如果你想让中心在原点以外的地方,比如 (x,y)

for (i = 0; i < n; i++) {
  printf("%f %f\n",x + r * Math.cos(2 * Math.PI * i / n), y + r * Math.sin(2 * Math.PI * i / n));
}

【讨论】:

  • 概括地说,我会将 XC 和 YC(圆心的坐标)以及第一个顶点 A 的角度添加到 cos/sin 项中:px = xc + r * cos(2 * pi * i / n + A); py = yc + r * sin(2 * pi * i / n + A);
  • 他要求以原点为中心。
  • 哇,没想到这么快就有答案了。好的,所以 r 是从原点到任何顶点的距离,对吧?我假设 n 是边数。我想我明白了......谢谢 - 一流的答案:-)
  • @dentist - 他说“不一定”
  • @rmx:嗯,这是一道数学题,不是编程题。我猜你知道圆的方程是x^2 + y^2 = r^2。但是,要使其成为程序,您必须将xy 分开。这个参数方程是这样做的:{ x = r * cos(theta), y = r * sin(theta), where 0 &lt;= theta &lt; 2 * PI }。要制作一个 n 边多边形,只需为 theta 分配 n 个不同的值。要制作正多边形,只需执行 2 * PI / n * i,其中 0 Parametric equation - Wikipedia。
【解决方案2】:

点数等于边数。

你需要的角度是angle = 2 * pi / numPoints

然后从原点垂直上方开始,多边形的大小由radius 给出:

for (int i = 0; i < numPoints; i++)
{
    x = centreX + radius * sin(i * angle);
    y = centreY + radius * cos(i * angle);
}

如果您的中心是原点,则只需忽略 centreXcentreY 术语,因为它们将为 0,0。

交换cossin 将使第一个点水平指向原点的右侧。

【讨论】:

  • 应该是sin(i + angle),而不是像写的那样!
  • @ysap - 你确定吗?这给出了圆周围 0、角度、2*角度、3*角度等处的点。因此,对于一个正方形(4 个点,角度 = 90),您在 0、90、180 和 270 处得到点。
  • 对不起,我以为我在您的帖子中读到角度是偏移量。重新阅读它(并假设您在我发表评论后没有对其进行编辑),您是对的,它现在的显示方式。无论如何,在 sin/cos 参数中添加一个角度项(实际上是相位)将使第一个点的位置任意。
  • @ysap - 我想我确实对偏移角度有过简短的评论,但意识到它令人困惑并删除了它。
  • 感谢@ChrisF,现在我明白为什么高中数学如此重要了。再次感谢:)
【解决方案3】:

抱歉,我目前没有完整的解决方案,但您应该尝试寻找 2D-Rendering of Circles。 circle(x,y,r) 的所有经典实现都使用您描述的用于绘图的多边形(但有 50 多个边)。

【讨论】:

    【解决方案4】:

    假设顶点到原点的距离为 1。假设 (1, 0) 始终是多边形的坐标。

    给定顶点数(例如 n),将 (1, 0) 定位到下一个坐标所需的旋转角度将是 (360/n)。

    这里需要的计算是旋转坐标。这就是它的样子; Rotation Matrix.

    假设 theta = 360/n;

    [cos(theta) -sin(theta)]
    [sin(theta) cos(theta)]
    

    将是您的旋转矩阵。

    如果您了解线性代数,您就已经知道我的意思了。如果不只是看看Matrix Multiplication

    【讨论】:

      【解决方案5】:

      为正多边形生成一组坐标的一种可能实现是:

      定义多边形中心半径第一个顶点1
      将顶点旋转n次2 角度为:360/n。

      在这个实现中,我使用一个向量来存储生成的坐标,并使用一个递归函数来生成它们:

      void generateRegularPolygon(vector<Point>& v, Point& center, int sidesNumber, int radius){
          // converted to radians
          double angRads = 2 * PI / double(sidesNumber);
          // first vertex  
          Point initial(center.x, center.y - radius);
          rotateCoordinate(v, center, initial, angRads, sidesNumber);
      }
      

      地点:

      void rotateCoordinate(vector<Point>& v, Point& axisOfRotation, Point& initial, double angRads, int numberOfRotations){
          // base case: number of transformations < 0
          if(numberOfRotations <= 0) return;
          else{
              // apply rotation to: initial, around pivot point: axisOfRotation
              double x = cos(angRads) * (initial.x - axisOfRotation.x) - sin(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.x;
              double y = sin(angRads) * (initial.x - axisOfRotation.x) + cos(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.y;
              // store the result
              v.push_back(Point(x, y));
              rotateCoordinate(v, axisOfRotation, Point(x,y), angRads, --numberOfRotations);
          }
      }
      

      注意:

      Point 是一个简单的类,用于将坐标包装到单个数据结构中:

      class Point{
      public:
          Point(): x(0), y(0){ }
          Point(int xx, int yy): x(xx), y(yy) { }
      private:
          int x;
          int y; 
      }; 
      

      1 就(相对于)中心、半径而言。在我的例子中,第一个顶点从中心向上平移半径长度。

      2个n正多边形有n个顶点。

      【讨论】:

        【解决方案6】:

        简单的方法是: 让我们取 N-gone(边数)和边 L 的长度。角度将为 T = 360/N。 假设一个顶点位于原点。

        * First vertex = (0,0)
        * Second vertex = (LcosT,LsinT)
        * Third vertex = (LcosT+Lcos2T, LsinT+Lsin2T)
        * Fourth vertex = (LcosT+Lcos2T+Lcos3T, LsinT+Lsin2T+Lsin3T)
        

        你可以在for循环中做

        【讨论】:

          【解决方案7】:

          嗯,如果您测试此处列出的所有版本,您会发现实现并不好。您可以检查从中心到多边形每个生成点的距离:http://www.movable-type.co.uk/scripts/latlong.html

          现在我进行了很多搜索,但找不到使用中心和半径计算多边形的任何好的实现......所以我回到数学书并尝试自己实现它。最后我想出了这个......这是100%的好:

                      List<double[]> coordinates = new List<double[]>();
                      #region create Polygon Coordinates
                      if (!string.IsNullOrWhiteSpace(bus.Latitude) && !string.IsNullOrWhiteSpace(bus.Longitude) && !string.IsNullOrWhiteSpace(bus.ListingRadius))
                      {
                          double lat = DegreeToRadian(Double.Parse(bus.Latitude));
                          double lon = DegreeToRadian(Double.Parse(bus.Longitude));
                          double dist = Double.Parse(bus.ListingRadius);
                          double angle = 36;
          
                          for (double i = 0; i <= 360; i += angle)
                          {
                              var bearing = DegreeToRadian(i);
          
                              var lat2 = Math.Asin(Math.Sin(lat) * Math.Cos(dist / earthRadius) + Math.Cos(lat) * Math.Sin(dist / earthRadius) * Math.Cos(bearing));
                              var lon2 = lon + Math.Atan2(Math.Sin(bearing) * Math.Sin(dist / earthRadius) * Math.Cos(lat),Math.Cos(dist / earthRadius) - Math.Sin(lat) * Math.Sin(lat2));
          
                              coordinates.Add(new double[] { RadianToDegree(lat2), RadianToDegree(lon2) });
          
                          }
          
                          poly.Coordinates = new[] { coordinates.ToArray() };
                      }
                      #endregion
          

          如果您对此进行测试,您会发现所有点都在您给出的确切距离处(半径)。也不要忘记声明 earthRadius。

          private const double earthRadius = 6371.01;
          

          这会计算十边形的坐标。您会看到使用的角度是 36 度。您可以将 360 度拆分为任意数量的边,并将结果放入角度变量中。 无论如何..我希望这可以帮助你@rmx!

          【讨论】:

            猜你喜欢
            • 2015-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-27
            • 1970-01-01
            • 2019-02-14
            • 2015-12-20
            • 2012-09-19
            相关资源
            最近更新 更多