求Hermite曲线算法

fatcatman 2004-05-06 09:24:01
求Hermite曲线算法,谢谢
...全文
756 13 点赞 打赏 收藏 举报
写回复
13 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
liushuaiboy 2004-05-06
没听过,楼主,这是作甚么地?
  • 打赏
  • 举报
回复
Johnnyxy 2004-05-06
热,顶你,给我分!
  • 打赏
  • 举报
回复
fatcatman 2004-05-06
  • 打赏
  • 举报
回复
fatcatman 2004-05-06
  • 打赏
  • 举报
回复
freefalcon 2004-05-06
因为屏幕坐标系的y轴正方向是向下的
你将y去负值,在考虑加上一个偏移量(比如屏幕的高度)就可以了
  • 打赏
  • 举报
回复
fatcatman 2004-05-06
请问用这void DrawHermiteCurve画出来的图和实际想要的上下是颠倒的啊?这是为什么啊?
  • 打赏
  • 举报
回复
fatcatman 2004-05-06
请问用这个算法画出来的图和实际想要的上下是颠倒的啊?这是为什么啊?
#define Iterative 24 /* 曲线仿真的线数(必须小于32) */
#define Iterative2 (Iterative*Iterative)
#define Iterative3 (Iterative2*Iterative)

void DrawHermiteCurve(int x1,int y1,int x2,int y2,int xr1,int yr1,
int xr2,int yr2)
{
/* ------------------------------------------------------------
作用:画出Hermite曲线
输入:x1,y1,x2,y2 = 曲线端点
xr1,yr1,xr2,yr2 = 曲线两参考向量
作者:邱奕南 Chi'u I-Nan
------------------------------------------------------------ */
int i, oldx, oldy, m1, m2, m3, m4, x, y, k1, k2;

oldx = x1;
oldy = y1;
m1 = Iterative3;
m2 = m3 = m4 = 0;
for (i=0; i<Iterative; i++) /* 用Iterative条直线仿真 */
{
k1 = (i << 1) + 1;
k2 = (k1+i)*i + k1;
m4 += (k2 -= (k1 *= Iterative));
m3 += (k1 = k2 - k1) + Iterative2;
m2 -= (k2 += k1);
m1 += k2;
x = (int) (((long) x1*m1 + (long) x2*m2 + (long) xr1*m3 +
(long) xr2*m4) / Iterative3);
y = (int) (((long) y1*m1 + (long) y2*m2 + (long) yr1*m3 +
(long) yr2*m4) / Iterative3);
DrawLine(oldx,oldy,x,y);
oldx = x;
oldy = y;
}
}

void DrawBezierCurve(int x1,int y1,int x2,int y2,int xr1,int yr1,
int xr2,int yr2)
{
/* ------------------------------------------------------------
作用:画出Bezier曲线
输入:x1,y1,x2,y2 = 曲线端点
xr1,yr1,xr2,yr2 = 曲线两参考点
作者:邱奕南 Chi'u I-Nan
------------------------------------------------------------ */
DrawHermiteCurve(x1,y1,x2,y2,3*(xr1-x1),3*(yr1-y1),3*(x2-xr2),3*(y2-yr2));
}
  • 打赏
  • 举报
回复
junnyfeng 2004-05-06
参考
  • 打赏
  • 举报
回复
fatcatman 2004-05-06
谢谢了,我试一下!
  • 打赏
  • 举报
回复
freefalcon 2004-05-06
多谢楼上,我也收藏一下此资料
  • 打赏
  • 举报
回复
happyasen 2004-05-06
发信人: william@cis_nctu (何陋居主), 信区: programming
标 题: [转载] Hermite 与 Bezier 曲线的绘制
发信站: 交大资科_BBS (May 25 00:32:41 1995)
转信站: cis_nctu


From: Chi'u I-Nan * Area: 90 C 语言
To: All Date: 03 May 95 22:37:26
Subj: Hermite 与 Bezier 曲线的绘制

**********************************************************************
* Hermite与Bezier曲线绘制方法研究 *
* 作者:邱奕南 (Chi'u I-Nan) *
* 版权声明:以下文章内容本人仅同意供BBS 站上流传学习,但必须完整流传 *
* (含版权声明及程序),其余权利一概保留。任何未经本人同意 *
* ,将本文贩卖、刊登、节录、或其它一切侵害本人著作权之行为 *
* 者,皆需负担刑事责任及民事赔偿责任。 *
**********************************************************************

Hermite及Bezier曲线为三度空间曲线的常用表示法,以下我们先说明一
下这两个曲线的定义:

1.Hermite曲线

Hermite曲线为给定两端点及两端点向量所得的三次曲线。令三次曲线:

3 2
x(t) = Ax * t + Bx * t + Cx * t + d

3 2
y(t) = Ay * t + By * t + Cy * t + d

且令给定的两端点为(x1,y1)、(x2,y2),以及两端点向量(xr1,yr1)、(xr2,yr2),
则:

x(0) = x1, y(0) = y1
x(1) = x2, y(1) = y2
x'(0) = xr1, y'(0) = yr1
x'(1) = xr2, y'(1) = yr2

绘出(x(t),y(t)),0<=t<=1,即为Hermite曲线。

2.Bezier曲线

Bezier曲线为给定两端点及另两参考点所得的三次曲线,它可说是Hermite
曲线的另一种表示方式。假设两端点为P1、P2,以及两参考点Pr1、Pr2,则
Bezier曲线换算成Hermite曲线的方式为:

R1 = 3*(Pr1-P1)
R2 = 3*(P2-Pr2)

R1、R2即为Hermite曲线的两端点向量。

由于Bezier曲线和Hermite曲线可以说是相同的,因此以下之说明我们便以
Hermite曲线为主。由Hermite曲线的定义,首先我们必须求出Ax,Bx...等值。
由定义中的条件:

x(0) = x1, x(1) = x2, x'(0) = xr1, x'(1) = xr2

以及

2
x'(t) = 3 * Ax * t + 2 * Bx * t + Cx

可得:

┌ 0 0 0 1 ┐┌ Ax ┐ ┌ x1 ┐
│ 1 1 1 1 ││ Bx │=│ x2 │
│ 0 0 1 0 ││ Cx │ │ xr1 │
└ 3 2 1 0 ┘└ Dx ┘ └ xr2 ┘

解之得:

┌ Ax ┐ ┌ 2 -2 1 1 ┐┌ x1 ┐
│ Bx │=│ -3 3 -2 1 ││ x2 │
│ Cx │ │ 0 0 1 0 ││ xr1 │
└ Dx ┘ └ 1 0 0 0 ┘└ xr2 ┘

因此

x(t) = (2*t^3 - 3*t^2 + 1) * x1 + (-2*t^3 + 3*t^2) * x2 +
(t^3 - 2*t^2 + t) * xr1 + (t^3 - t^2) * xr2

同理

y(t) = (2*t^3 - 3*t^2 + 1) * y1 + (-2*t^3 + 3*t^2) * y2 +
(t^3 - 2*t^2 + t) * yr1 + (t^3 - t^2) * yr2

上述的公式中,由于t的值是介于0与1之间,这对于我们在实际绘图上较不
方便,而且运算速度也比较慢。因此假设我们以n条直线来仿真Hermite曲线,
则我们必须将t值化成整数,使它成为0<=t<=n(注意n条连续直线需有n+1个点)。
令i=n*t代入上述公式,化简后可得:

x(i) = (m1*x1 + m2*x2 + m3*xr1 + m4*xr2) / n^3
y(i) = (m1*y1 + m2*y2 + m3*yr1 + m4*yr2) / n^3

其中

m1 = 2*i^3 - 3*n*i^2 + n^3 , 0 <= i <= n
m2 = -2*i^3 + 3*n*i^2
m3 = i^3 - 2*n*i^2 + n^2*i
m4 = i^3 - n*i^2

如此我们便能很方便地求出仿真直线的各端点。然而上述公式中的乘法仍相当
多,对于m1~m4的计算上至少需5次乘法、2次移位乘法和6次加法(或4次乘法、
3次移位乘法和7次加法),在计算上仍然会浪费相当多时间(PC上的乘法约为
加法的近20倍,移位乘法则和加法相当),因此有必要再予以化简。如何简化
呢?由上述公式可发现,主要的乘法来自于i^3的计算,因此欲将之简化的最简
单的方式便是由前一个m1~m4值来求得后一个m1~m4值,藉此消减掉这个三次
方值的运算:

m1(i+1) = m1(i) + 6*i^2 + 6*i + 2 - 3*n*(2*i+1)
m2(i+1) = m2(i) - 6*i^2 - 6*i - 2 + 3*n*(2*i+1)
m3(i+1) = m3(i) + 3*i^2 + 3*i + 1 - 2*n*(2i+1) + n^2
m4(i+1) = m4(i) + 3*i^2 + 3*i + 1 - n*(2*i+1)

现在便是要化简各式中后面的计算项次。由于这些项次有相当多的重复,故可
将之写成:

m1(i+1) = m1(i) + a
m2(i+1) = m2(i) - a
m3(i+1) = m3(i) + d - c + n^2
m4(i+1) = m4(i) + d
a = 2*b - 3*c
b = 3*i^2 + 3*i + 1
c = n*(2*i+1)
d = b-c

再进一步简化为:

e = 2*i + 1
c = n*e
b = 3*i^2 + 3*i + 1
= (3*i+1)*i + (2*i+1)
= (e+i)*i + e

整理一下成为(依计算顺序):

e = 2*i + 1
b = (e+i)*i + e
c = n*e
d = b-c
m4 = m4 + d
f = d-c
m3 = m3 + f + n^2
a = d + f
m2 = m2 - a
m1 = m1 + a

共计2次乘法、1次移位乘法和11次加法,等于是以两次加法代替了两次乘法,
其速度必然较快。记得m1~m4的初值为:

m1(0) = n^3
m2(0) = m3(0) = m4(0) = 0

接下来我们要探讨一下模拟线数n的问题。倒底取多少模拟线数较为恰当?
采用的仿真线数太少,曲线将不够平滑,但若模拟线数太多,曲线绘制速度又
会太慢。据作者实际的测试,一般取n=20以上曲线便已相当平滑,但对于弯度
太大的曲线,其转折处仍约略可见,不过并不严重。由于在绘制曲线时,大都
以整数来运算(为求速度),因此仿真线数最好不要超出32,以避免运算结果
超出整数运算的值域。以下便是Hermite曲线和Bezier曲线的绘制程式:


#define Iterative 24 /* 曲线仿真的线数(必须小于32) */
#define Iterative2 (Iterative*Iterative)
#define Iterative3 (Iterative2*Iterative)

void DrawHermiteCurve(int x1,int y1,int x2,int y2,int xr1,int yr1,
int xr2,int yr2)
{
/* ------------------------------------------------------------
作用:画出Hermite曲线
输入:x1,y1,x2,y2 = 曲线端点
xr1,yr1,xr2,yr2 = 曲线两参考向量
作者:邱奕南 Chi'u I-Nan
------------------------------------------------------------ */
int i, oldx, oldy, m1, m2, m3, m4, x, y, k1, k2;

oldx = x1;
oldy = y1;
m1 = Iterative3;
m2 = m3 = m4 = 0;
for (i=0; i<Iterative; i++) /* 用Iterative条直线仿真 */
{
k1 = (i << 1) + 1;
k2 = (k1+i)*i + k1;
m4 += (k2 -= (k1 *= Iterative));
m3 += (k1 = k2 - k1) + Iterative2;
m2 -= (k2 += k1);
m1 += k2;
x = (int) (((long) x1*m1 + (long) x2*m2 + (long) xr1*m3 +
(long) xr2*m4) / Iterative3);
y = (int) (((long) y1*m1 + (long) y2*m2 + (long) yr1*m3 +
(long) yr2*m4) / Iterative3);
DrawLine(oldx,oldy,x,y);
oldx = x;
oldy = y;
}
}

void DrawBezierCurve(int x1,int y1,int x2,int y2,int xr1,int yr1,
int xr2,int yr2)
{
/* ------------------------------------------------------------
作用:画出Bezier曲线
输入:x1,y1,x2,y2 = 曲线端点
xr1,yr1,xr2,yr2 = 曲线两参考点
作者:邱奕南 Chi'u I-Nan
------------------------------------------------------------ */
DrawHermiteCurve(x1,y1,x2,y2,3*(xr1-x1),3*(yr1-y1),3*(x2-xr2),3*(y2-yr2));
}

* 青衫诗客 -- 小邱 *

-- Via 中文银版快信 V2.28C
! Origin: 档案货柜, 欢迎您来挖宝, 28800 BPS, 04-230-2080; (90:2010/622)
________________________________________
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
≡ 何陋居 ≡ 中学生以伏案读书为主, 大学生则应起而高瞻远瞩。 Whitehead.
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
  • 打赏
  • 举报
回复
freefalcon 2004-05-06
http://bbs.ee.ntu.edu.tw/boards/Programming/14/7.html
我这里显示有乱码,不过程序还是比较清楚的

1.HermiteΡ絬

HermiteΡ絬倒﹚ㄢ狠翴のㄢ狠翴秖┮眔ΩΡ絬ΩΡ絬

3 2
x(t) = Ax * t + Bx * t + Cx * t + d

3 2
y(t) = Ay * t + By * t + Cy * t + d

倒﹚ㄢ狠翴(x1,y1)(x2,y2)のㄢ狠翴秖(xr1,yr1)(xr2,yr2)
玥

x(0) = x1, y(0) = y1
x(1) = x2, y(1) = y2
x'(0) = xr1, y'(0) = yr1
x'(1) = xr2, y'(1) = yr2

酶(x(t),y(t))0<=t<=1HermiteΡ絬


#define Iterative 24 /* Ρ絬家览絬计(ゲ斗32) */
#define Iterative2 (Iterative*Iterative)
#define Iterative3 (Iterative2*Iterative)

void DrawHermiteCurve(int x1,int y1,int x2,int y2,int xr1,int yr1,
int xr2,int yr2)
{
/* ------------------------------------------------------------
ノ礶HermiteΡ絬
块x1,y1,x2,y2 = Ρ絬狠翴
xr1,yr1,xr2,yr2 = Ρ絬ㄢ把σ秖
玭 Chi'u I-Nan
------------------------------------------------------------ */
int i, oldx, oldy, m1, m2, m3, m4, x, y, k1, k2;

oldx = x1;
oldy = y1;
m1 = Iterative3;
m2 = m3 = m4 = 0;
for (i=0; i<Iterative; i++) /* ノIterative兵絬家览 */
{
k1 = (i << 1) + 1;
k2 = (k1+i)*i + k1;
m4 += (k2 -= (k1 *= Iterative));
m3 += (k1 = k2 - k1) + Iterative2;
m2 -= (k2 += k1);
m1 += k2;
x = (int) (((long) x1*m1 + (long) x2*m2 + (long) xr1*m3 +
(long) xr2*m4) / Iterative3);
y = (int) (((long) y1*m1 + (long) y2*m2 + (long) yr1*m3 +
(long) yr2*m4) / Iterative3);
DrawLine(oldx,oldy,x,y);
oldx = x;
oldy = y;
}
}
  • 打赏
  • 举报
回复
fatcatman 2004-05-06
画曲线的一个算法
  • 打赏
  • 举报
回复
相关推荐
发帖
C语言
加入

6.5w+

社区成员

C语言相关问题讨论
申请成为版主
帖子事件
创建了帖子
2004-05-06 09:24
社区公告
暂无公告