計算橢圓運動軌跡的算法


在中學或大學時代,我們應該在數學中都學過橢圓方程、雙曲線方程等等,當然那個時候學習這些知識的目的就是為了考試,為了能夠拿個好成績,上個好大學等。那么除此之外,這些知識對於我們今后的生活或者工作又帶來什么便利呢?

 

巧合的是作為程序員,尤其是偏向算法方面的人員,經常會有這種需求,例如實現一個物體做橢圓運動的效果,或者做一個圓形軌跡的效果,亦或者做一個看似毫無規律的曲線運動,那么這就用到了橢圓方程、圓形方程及貝塞爾曲線方程等等。

 

在此着重介紹下橢圓方程的應用。

 

一、 標准橢圓方程公式:

二、 中心點在 ( 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);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM