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);
  • 相关阅读:
    ubuntu 制做samba
    《Programming WPF》翻译 第4章 前言
    《Programming WPF》翻译 第4章 3.绑定到数据列表
    《Programming WPF》翻译 第4章 4.数据源
    《Programming WPF》翻译 第5章 6.触发器
    《Programming WPF》翻译 第4章 2.数据绑定
    《Programming WPF》翻译 第4章 1.不使用数据绑定
    《Programming WPF》翻译 第5章 7.控件模板
    《Programming WPF》翻译 第5章 8.我们进行到哪里了?
    《Programming WPF》翻译 第5章 5.数据模板和样式
  • 原文地址:https://www.cnblogs.com/calence/p/7525486.html
Copyright © 2011-2022 走看看