以离散步骤绘制弧

时间:2011-06-24 22:07:42

标签: algorithm language-agnostic drawing microcontroller

下午好,

背景
我的问题涉及使用离散步骤在空间中绘制任意弧。然而,它是独一无二的,因为我并没有画出典型意义上的画布。我正在设计的固件是用于CNC铣床的gcode解释器,它将命令转换为步进电机运动。现在,我已经在这个网站上发现了类似的问题,但是建议的方法(Bresenham的算法)似乎无法在空间中移动物体,因为它只依赖于计算圆的一个八分圆然后被镜像关于剩余的对称轴。此外,计算两个任意角度之间的弧的规定方法依赖于三角函数(我在微控制器上实现并且希望避免代价高昂的触发功能,如果可能的话)并且根本不采取超出范围的步骤。最后,该算法仅设计为在一个旋转方向上工作(例如逆时针)。

问题
那么,关于实际的问题:有没有人知道一种通用算法可用于在离散步骤中“绘制”任意弧,同时仍然考虑角度方向(CW / CCW)?最终的实现将在C中完成,但出于问题目的的语言是无关紧要的。

提前谢谢。

参考
S.O使用Bresenham算法绘制一个简单的圆圈:
"Drawing" an arc in discrete x-y steps

Wiki页面描述了Bresenham的圆形算法
http://en.wikipedia.org/wiki/Midpoint_circle_algorithm

要实施的Gcode指令(参见.G2和G3)
http://linuxcnc.org/docs/html/gcode.html

2 个答案:

答案 0 :(得分:8)

通过将任意有理曲线转换为有理Bezier曲线,然后应用de Casteljau算法,您可以准确快速地解决此问题。对圆形和双曲线等圆锥曲线很容易做到这一点:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/NURBS/RB-conics.html

一旦有了理性Bezier曲线,要将曲线重新采样为离散步骤,您应该使用de Casteljau算法。该算法使用动态编程,并且非常快速且数值稳健。如果您之前没有听说过,我建议您继续学习它,因为它是一个相当聪明的小算法:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html

有几种方法可以使用de Casteljau算法对曲线进行离散采样。首先,您可以天真地应用它以统一增量沿其参数空间评估曲线。如果增量需要均匀间隔,则必须将插值坐标更改为弧长单位:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/curves/continuity.html#Arc-Length-Parameterization

此技术的改进是转换为弦长参数化,随着时间的推移接近弧长参数化:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/INT-APP/PARA-chord-length.html

最后,如果你需要在曲线上有很多点,你可以将de Casteljau的算法应用为角切割程序,将初始控制点矢量细化为一个极限多边形,任意近似你想要的曲线,直到某些用户指定公差:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-sub.html

这些笔记来自C.K.教授。 Shene的课程笔记,这是学习样条曲线和细分曲面的重要资源:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/

答案 1 :(得分:0)

这是一个愚蠢的想法,但它可能只是工作 计算计算机上每个可能半径的圆圈,并将此信息保存在微动压缩机内存中 假设您的圆半径为1到1000像素。所有圈子的1000 *(1000 + 1)/ 2 * 2 * pi = 300万点 对于每个点,您实际上只需要从前一点的偏移,有8种情况,这些可以编码为3位
取决于微控制器有多少位,比如8/16位,有2像素/字节或5像素/字
8位微处理器需要1.5MB内存,16位微处理器需要1.2MB内存 你可以存储半径为k像素增量的圆圈,并且只能使用1.5MB / k的内存 另一个优化方法是将圆形建模为具有多个边的多边形,不要将偏移保持到前一个点,而是保持两步或更远的点,并以某种方式插入两者之间的像素。
如果您对两步之外的像素保持偏移,则有16个案例,在4位上编码=> 3/2百万点=> 750KBytes
如果你每隔几步保持像素,你就有了s * 8种可能性,可以用3 + log2(s)比特进行编码 的 LE
像素每32步/ 8mils => 10英寸半径圆10 * 4000 * 2 * pi / 32步* 1字节= 7.85KB, 像素每128步/ 32mils => 10英寸半径圆10 * 4000 * 2 * pi / 128 * 10bits = 19634Kbits = 2.4KB
LLE: 你实际上没有s * 8的可能性,因为放大的圆是一条直线而少于那个 这一切都取决于你如何打包数据,或使用外部存储器 另一个优化:只存储象限或八分圆,并从对称性中找出其余部分 的 LLLE: 每一个