如何在笛卡尔坐标系中绘制一个n边形?

33

我一直在尝试想出如何编写一个简单的程序来计算创建n边形的x,y点。有人可以给我一些代码示例,不使用绘制多边形的预先存在的函数?我想要理解这个过程,我认为是这样的:

  1. 选择一个角度,从半径和中心点开始
  2. 以某种方式计算距离中心那么远的x,y位置(如何?)
  3. 将360除以边数,移动该距离,并从第一个x,y点绘制下一条线
  4. 继续,直到角度=该数字除以360。

假设我的假设是正确的,主要是要理解如何计算x,y点。

首选以Visual Basic(甚至是旧版Microsoft / Atari / Commodore BASIC)或英语可读的一组步骤回答。如果您必须用数学公式回答,请用计算机语言进行回答,以便我可以阅读它,在C或C ++中我可以弄清楚,但我不知道如何阅读数学符号。我使用的语言类似于Visual Basic,除了绘制线之外,几乎没有图形原语。


相关:https://math.stackexchange.com/questions/1982828/the-coordinates-of-vertices-of-regular-polygon - Amit Tomar
6个回答

55

假设您想绘制一个半径为r,以(0,0)为中心的N边形。然后n个顶点如下:

x[n] = r * cos(2*pi*n/N)
y[n] = r * sin(2*pi*n/N)

其中 0 <= n < N。请注意,这里的cossin使用的是弧度制而不是角度制(这在大多数编程语言中都很常见)。

如果您想要不同的中心,则只需将中心点的坐标添加到每个(x [n], y [n])。 如果要不同的方向,则只需要添加一个常数角度。 因此,一般形式为:

x[n] = r * cos(2*pi*n/N + theta) + x_centre
y[n] = r * sin(2*pi*n/N + theta) + y_centre

谢谢您提供的信息,但纹理坐标是什么? - Quintin Balsdon
1
@QuintinBalsdon:什么纹理坐标? - Oliver Charlesworth
嗨,我在这里提出了问题:http://stackoverflow.com/questions/15552521/how-to-determine-uv-texture-coordinates-for-n-sided-polygon基本上问题可以归结为:在OpenGL|ES情况下,如果这是我的顶点,我必须以什么顺序为UV纹理映射对这些顶点排序。 - Quintin Balsdon
如何在不知道半径的情况下完成这个操作?例如,我可能不想要一个对称的多边形,而是一个由宽度和高度定义的多边形(其中宽度是对象的最大宽度,高度是对象的最大高度)? - Gustav
1
@Gustav:这取决于你所说的“宽度”和“高度”的含义。一个天真的方法是简单地使用x[n] = width * ...; y[n] = height * ...; - Oliver Charlesworth
@OliverCharlesworth 我所说的宽度和高度是指在这张图片中显示的灰色边框的宽度和高度:[链接](http://i.imgur.com/xbG9xtG.png?1) 我之所以问这个问题,是因为我正在开展一个项目,其中我会获得这种格式的形状数据,并需要在画布上显示它们(我当前使用kinetic.js)。我会获得关于边数、边框宽度和高度、可能的旋转以及画布中边框的x-和y-位置的数据。感谢您的帮助。 - Gustav

9
angle = start_angle
angle_increment = 360 / n_sides
for n_sides:
    x = x_centre + radius * cos(angle)
    y = y_centre + radius * sin(angle)
    angle += angle_increment

在实践中,当绘制线条时,除了计算角点之外,您还需要通过重复第一个点来“连接”多边形。
另外,如果sin()和cos()使用弧度而不是度数,则应该使用2 * PI而不是360。

我有一个问题:如何在不使用余弦和正弦定理的情况下,对斜三角形进行正弦和余弦计算? - lost_in_the_source

2

如果你想以一定的误差累积为代价来提高速度,可以使用一个(复杂的)原始单位根,并对其进行幂运算(可以使用语言内置的复数支持或手动编写乘法代码)。在C语言中:

complex double omega=cexp(2*M_PI*I/n), z;
for (i=0, z=1; i<n; i++, z*=omega) {
    /* do something with z */
}

我不熟悉C语言中的复数函数,omega=2value_of_pii/n和cexp=(2M_PII/n)之间有什么区别吗?看起来你正在将指针z的值赋为omega。你所说的实部和虚部是什么意思?如果要给出一个给我x、y坐标点的表达式(这就是整个问题的关键),它会是什么样子的? - alphablender
在连续的迭代中,z 包含 omega 的幂,其中 omega 是通过复指数函数 cexp 获得的原始第 n 个单位根。 - R.. GitHub STOP HELPING ICE
好的,感谢您尝试解释,但我并不真正理解您所说的大部分内容。能否提供一个从您的for循环返回x和y点的代码示例? - alphablender
顺便说一下,如果你想理解这个答案,在网上查找复数和单位根。维基百科可能是一个好的起点,或者数学自学教程。 - R.. GitHub STOP HELPING ICE
好的,谢谢!我会先查找creal()和cimag(),然后再从那里开始回溯! - alphablender
显示剩余2条评论

2
“for n_sides:”的答案是最简单的。对于那些建议使用复数简化计算的人来说,几乎所有的数学库都有基于表格的cos()和sin()例程,并且具有高效的插值,因此不需要深入研究相对较为模糊的解决方案。通常情况下,一个正n边形可以被初始化,并且OpenGL的硬件缩放可以用于缩放/变换它以适应任何特定的实例。
如果你想更加专业,可以预先生成所有你需要的正n边形,并将它们加载到顶点缓冲区中。
另外,以下是上述解决方案的Lua代码。它只打印出坐标,但你当然可以返回数组/表中的坐标。返回的坐标可以用于初始化OpenGL GL_LINE_LOOP网格原语。
require 'math'

-- computes coordinates for n-sided, regular polygon of given radius and start angle
-- all values are in radians

function polypoints(sides, radius, start)
    local x_center = 0.0
    local y_center = 0.0
    local angle = start
    local angle_increment = 2 * math.pi / sides
    local x=0.0
    local y=0.0

    print(string.format("coordinates for a %d sided regular polygon of radius %d\nVertex",sides,radius),"X"," ","Y")
    for i=1,sides do
        x = x_center + radius * math.cos(angle)
        y = y_center + radius * math.sin(angle)
        print(string.format("%d\t%f\t%f",i,x,y))
        angle = angle + angle_increment
    end
end

-- Generate a regular hexagon inscribed in unit circle 
polypoints(6, 1.0, 0.0)

2

这是一个完整的C++程序,可以打印出正多边形的各个顶点。在本例中,p代表多边形的边数,r代表多边形的半径,d代表第一个顶点相对于中心的方向或角度。希望这能有所帮助。

//g++ ck.cpp -o ck && ./ck
#include <stdio.h>
#include <math.h>

int p=3; //number of sides
double r=1000,d=3/4.0;

int main()
{
 int i=0;
 double x,y,t;
 while(i<p)
 {
  t=2*M_PI*((double)i/p+d);
  x=cos(t)*r;
  y=sin(t)*r;
  printf("x%i:%f y%i:%f\n",i,x,i,y);
  i++;
 }
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接