计算椭圆运动轨迹的算法

在中学或大学时代,我们应该在数学中都学过椭圆方程、双曲线方程等等,当然那个时候学习这些知识的目的就是为了考试,为了能够拿个好成绩,上个好大学等。那么除此之外,这些知识对于我们今后的生活或者工作又带来什么便利呢?

巧合的是作为程序员,尤其是偏向算法方面的人员,经常会有这种需求,例如实现一个物体做椭圆运动的效果,或者做一个圆形轨迹的效果,亦或者做一个看似毫无规律的曲线运动,那么这就用到了椭圆方程、圆形方程及贝塞尔曲线方程等等。

在此着重介绍下椭圆方程的应用。

一、 标准椭圆方程公式:

二、 中心点在 ( h , k ),主轴平行于x轴时公式:

三、 常见的名词概念及椭圆形状:

       

          图1                        图2      

  • 长轴:通过连接椭圆上的两个点所能获得的最长线段,对应图2中的major axis。
  • 半长轴:长轴的一半,对应椭圆公式中的a。
  • 短轴:垂直平分长轴的直线所得弦, 对应图2中的minor axis。
  • 半短轴:短轴的一半,对应椭圆公式中的b。
  • 焦点:每个椭圆均有两个焦点,分别上上图中的F1 , F2。
  • 近拱点:指定一个焦点F1 , 距离焦点F1最近点成为近拱点,也就是图中的A。
  • 远拱点:相对于F1焦点而言,距离F1最远点成为远拱点,也就是图中的B。
  • 离心率:用来描述轨道的形状,椭圆的离心率大小区间(0, 1) ,当离心率为0时表示圆。

四、 离心率的计算公式:

  • 根据近拱点和远拱点距离计算:

其中dp表示近拱点的距离,da表示远拱点的距离。

  • 根据半焦距和半长轴计算:

其中c表示半焦距,a表示半长轴。

  • 根据半长轴和半短轴计算:

其中,a表示半长轴,b表示半短轴。

五、 已知椭圆其中一个焦点、近拱点、离心率以及表示椭圆在三维空间的倾向法向量,可以得到此椭圆的公式。

1. 根据焦点和近拱点,得到近拱点到焦点的距离dp。

2. 根据离心率、近拱点距离可以得到远拱点到焦点的距离da。

3. 根据近拱点、焦点以及远拱点距离,可以得到远拱点的坐标值。

4. 根据近拱点、远拱点即可得到椭圆的中心点坐标center。

5. 根据公式:半短轴 = 近拱点距离 * 远拱点距离,即可得到半长轴b的长度。

6. 根据代表椭圆倾向的法向量n和长轴方向的单位向量,两者叉乘即可得到短轴方向上的单位向量,并且根据半短轴的长度,即可得到半短轴向量。

7. 已知半短轴向量、半长轴向量,根据椭圆的参数方程,即可得到椭圆上任一点的坐标值。

具体代码如下:

 1 //mDirection代表点在椭圆上的运动方向是逆时针还是顺时针,angle用于计算椭圆参数方程的角度
 2 double angle = (mDirection == OrbitDirection.CLOCKWISE ? -1 : 1) * mAngle * time * MathUtil.PRE_PI_DIV_180;
 3
 4 //计算近拱点到焦点的距离
 5 double periapsisRadius = mPeriapsis.distanceTo(mFocalPoint);
 6 //根据离心率、近拱点到焦点的距离、远拱点到焦点三者的公式即可得到远拱点距离(近拱点到远拱点的距离是椭圆的长轴)
 7 double apoapsisRadius = periapsisRadius * (1 + mEccentricity) / (1 - mEccentricity);
 8
 9 // 计算近拱点到焦点的单位向量,注意此处乘以1e8 和除以1e8的目的是 去掉第8个小数点后最不重要的数字,以降低计算误差。
10 double uAx = (Math.round(mFocalPoint.x * 1e8) - Math.round(mPeriapsis.x * 1e8)) / 1e8;
11 double uAy = (Math.round(mFocalPoint.y * 1e8) - Math.round(mPeriapsis.y * 1e8)) / 1e8;
12 double uAz = (Math.round(mFocalPoint.z * 1e8) - Math.round(mPeriapsis.z * 1e8)) / 1e8;
13 double mod = Math.sqrt(uAx * uAx + uAy * uAy + uAz * uAz);//计算近拱点到焦点的距离
14 if (mod != 0 && mod != 1) {//单位化
15     mod = 1 / mod;
16     uAx *= mod;
17     uAy *= mod;
18     uAz *= mod;
19 }
20
21 double apoapsisDir_x = Math.round(uAx * apoapsisRadius * 1e8) / 1e8;
22 double apoapsisDir_y = Math.round(uAy * apoapsisRadius * 1e8) / 1e8;
23 double apoapsisDir_z = Math.round(uAz * apoapsisRadius * 1e8) / 1e8;
24 //计算远拱点坐标
25 double apoapsisPos_x = Math.round((apoapsisDir_x + mFocalPoint.x) * 1e8) / 1e8;
26 double apoapsisPos_y = Math.round((apoapsisDir_y + mFocalPoint.y) * 1e8) / 1e8;
27 double apoapsisPos_z = Math.round((apoapsisDir_z + mFocalPoint.z) * 1e8) / 1e8;
28
29 //近拱点和远拱点的中心即椭圆的中心
30 double center_x = Math.round(((mPeriapsis.x + apoapsisPos_x) / 2) * 1e8) / 1e8;
31 double center_y = Math.round(((mPeriapsis.y + apoapsisPos_y) / 2) * 1e8) / 1e8;
32 double center_z = Math.round(((mPeriapsis.z + apoapsisPos_z) / 2) * 1e8) / 1e8;
33
34 //计算半短轴的长度
35 double b = Math.sqrt(periapsisRadius * apoapsisRadius);
36
37 //从中心点到近拱点的向量
38 double semimajorAxis_x = Math.round((mPeriapsis.x - center_x) * 1e8) / 1e8;
39 double semimajorAxis_y = Math.round((mPeriapsis.y - center_y) * 1e8) / 1e8;
40 double semimajorAxis_z = Math.round((mPeriapsis.z - center_z) * 1e8) / 1e8;
41
42 //单位化半长轴向量
43 double unitSemiMajorAxis_x = semimajorAxis_x;
44 double unitSemiMajorAxis_y = semimajorAxis_y;
45 double unitSemiMajorAxis_z = semimajorAxis_z;
46 mod = Math.sqrt(semimajorAxis_x * semimajorAxis_x + semimajorAxis_y * semimajorAxis_y + semimajorAxis_z
47         * semimajorAxis_z);
48 if (mod != 0 && mod != 1) {
49     mod = 1 / mod;
50     unitSemiMajorAxis_x *= mod;
51     unitSemiMajorAxis_y *= mod;
52     unitSemiMajorAxis_z *= mod;
53 }
54
55 //将中心点沿法向量方向平移
56 Vector3 unitNormal = mNormal.clone();
57 unitNormal.normalize();
58 double uNx = Math.round(unitNormal.x * 1e8) / 1e8;
59 double uNy = Math.round(unitNormal.y * 1e8) / 1e8;
60 double uNz = Math.round(unitNormal.z * 1e8) / 1e8;
61 double normalCenter_x = center_x + uNx;
62 double normalCenter_y = center_y + uNy;
63 double normalCenter_z = center_z + uNz;
64 mod = Math.sqrt(normalCenter_x * normalCenter_x + normalCenter_y * normalCenter_y + normalCenter_z
65         * normalCenter_z);
66 if (mod != 0 && mod != 1) {
67     mod = 1 / mod;
68     normalCenter_x *= mod;
69     normalCenter_y *= mod;
70     normalCenter_z *= mod;
71 }
72
73 mScratch1.setAll(unitSemiMajorAxis_x, unitSemiMajorAxis_y, unitSemiMajorAxis_z);
74 mScratch2.setAll(normalCenter_x, normalCenter_y, normalCenter_z);
75 //叉乘计算半短轴的单位向量
76 Vector3 semiminorAxis = mScratch3.crossAndSet(mScratch1, mScratch2);
77 //得到半短轴向量
78 semiminorAxis.multiply(b);
79
80 //3D空间椭圆的参数方程
81 double x = center_x + (Math.cos(angle) * semimajorAxis_x) + (Math.sin(angle) * semiminorAxis.x);
82 double y = center_y + (Math.cos(angle) * semimajorAxis_y) + (Math.sin(angle) * semiminorAxis.y);
83 double z = center_z + (Math.cos(angle) * semimajorAxis_z) + (Math.sin(angle) * semiminorAxis.z);
时间: 2024-12-18 13:56:27

计算椭圆运动轨迹的算法的相关文章

计算星期几的算法

int dayofweek(int y, int m, int d) /* 0 = Sunday */ { static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; } 计算星期几的算法;

关于中缀表达式的计算 和算符优先算法

中缀表达式计算:http://blog.sina.com.cn/s/blog_3fe961ae0100niq3.html 算符优先算法:http://blog.csdn.net/zhibudefeng/article/details/6937375 前中后缀表达式:http://blog.csdn.net/antineutrino/article/details/6763722/

计算字符串相似度算法——Levenshtein http://wdhdmx.iteye.com/blog/1343856

0.这个算法实现起来很简单 1.百度百科介绍: Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数. 许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符. 编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance. 2.用途 模糊查询 3.实现过程 a.首先是有两个字符串,这里写一个简单的 abc和abe b.将字符串想象成下面的结构. A处 是一个标记,为了方便讲解

计算字符串相似度算法——Levenshtein

0.这个算法实现起来很简单 1.百度百科介绍: Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数. 许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符. 编辑距离的算法是首先由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance. 2.用途 模糊查询 3.实现过程 a.首先是有两个字符串,这里写一个简单的 abc和abe b.将字符串想象成下面的结构. A处 是一个标记,为了方便讲解

计算并列排名的算法

最近在搞一个统计,需要计算学生的成绩排名,而且还需要并列的排名,可能这么说大家都不理解啥叫并列排名,举个例子: 小明 100分 小红100分  小芳90分  小李80分 小孙80分 小兰70分 那么最终的排名应该是:小明 1,小红 1,小芳 3,小李4,小孙4,小兰6. 相信通过上面的例子大家应该明白什么叫并列排序了吧,相同的可以并列,但是不同的需要按照人头去计算,话不多说,直接上代码: public static void reckonRanking(){ //这里需要将要排名的数组按照你自己

同步图计算实现最短路径Dijkstra算法

同上篇讲述pageRank一样,考虑一个顶点V. 根据顶点算法通常步骤1) 接收上个超步发出的入邻居的消息2) 计算当前顶点的值3) 向出邻居发消息 1.接受入邻居的消息 2.求其中最小值,即为V的值value 3.向V的出邻居发送消息,消息为value + 到邻居的距离 double val = 0.0; for (每一个入邻居) { val = min(邻居); } sendMesgsToAllNeighbors(val + 出边的值); 算法停止条件是所有顶点的值不再变化.

c++计算 char数组CRC算法

我使用的OS:win7. 我使用的开发环境:VS2010 + sp1 算法源码: unsigned int create_crc_2(unsigned char *parr, unsigned int parr_len) { unsigned char *pbuf = NULL; // 数据长度为奇数,在数据前补0 if (1 == parr_len % 2) { parr_len += 1; pbuf = new(std::nothrow) unsigned char[parr_len]; m

[solution]腾讯TEG_计算广告组_算法题

度娘笔试归来,题目实打实的,感觉真心不易,上百号人就抢那么几个坑......只恨自己平时积累太少啊~ 故曝一道鹅厂面试用的算法题(当时我就死在了这题上),来为度娘家攒一下RP~ 题目: 对于长度为N的一个无序的数组a[1..N],请将a进行排序,要求所有正数都排在0之前,所有负数都排在0之后(如果没有0,则所有正数排在负数前) 要求时间复杂度O(N),空间复杂度O(1) 题目不难,但给思考的时间很短,大约不到5分钟吧.当时脑子比较短路,于是只给出了O(n) O(n)复杂度的算法,然后就被面试官挂

进阶实验6-3.2 社交网络图中结点的“重要性”计算 (30分)-dijkstra算法

解题思路:(邻接矩阵存储) 用dijkstra算法依次求出每个结点到其余结点的最短距离 #include <stdio.h> #include <string.h> #define INF 0x3f3f3f3f #define MaxVex 1000+10 int G[MaxVex][MaxVex]; int visit[MaxVex]; int Nv,Ne; void Init() { memset(G,INF,sizeof(G)); int i; for(i=1; i<=