zoukankan      html  css  js  c++  java
  • 计算椭圆运动轨迹的算法

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

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

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

    一、 标准椭圆方程公式:

    二、 中心点在 ( 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);
  • 相关阅读:
    phpcms v9 更改首页
    不是技术牛人,如何拿到国内IT巨头的Offer
    超实用的PHP代码片段!
    Android 中的 Service 全面总结
    近期十大优秀jQuery插件推荐
    DIOCP之编写第一个应用程序(二)
    DIOCP之编写第一个应用程序(一)
    DIOCP之DEMO学习顺序及达到要求
    DIOCP之EchoServer分析
    DIOCP之数据接收事件
  • 原文地址:https://www.cnblogs.com/calence/p/7525486.html
Copyright © 2011-2022 走看看