Discussion Math Function you often need for Orbiter

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
Hello,
i plan to creat and public a class for orbiter with basic and advanced functions / methods witch are often needed by add ons developers.

Let's say thats only the first step, the next step will be to implement some of these functions to an extended vessel class.
For example, so you can say later

Code:
VESSEL->GetBaseDownrange(OBJHANDLE hBase);
So here is the first look:

Code:
// (c) This code is released under the terms of the GNU 1.3 or later.
// see: http://www.gnu.org
#ifndef orbiterMath_h
#define orbiterMath_h

#include <orbitersdk.h>
// Basic math funktion for Orbiter
class ORBITERMATH
{
    private: 
        class SURFACEPOS
        {
            public: 
                bool setPos(double lat,double lng);
                    //Set the position of a SURFACEPOS Object direct (in RAD) for calculations
                bool setPos(OBJHANDLE hobj);
                    //Set the position of a SURFACEPOS Object direct (in RAD) for calculations
                bool setPos(OBJHANDLE hobj, OBJHANDLE href);
                    /*  
                        Set the position of an object on the surface of href. 
                        A planet (OBJHANDLE) is required for distance calculaions,
                        where the radius of the Planet is needed.
                    */ 
                bool setBasePadPos(OBJHANDLE hBase, int basePadID);
                    // Set the position of a VTOL Landing pad for calculations.
                bool setPos(VESSEL* V);
                    // Set the Position of a "Vesselpointer" object for calculations
                double getLat();
                    // Returns the lattitude of the set object
                double getLng();
                    // Returns the longtitude of the set object
            private:
                bool checkSurfaceLatLong(double lat,double lng);
                    //Not created yet
                double plat;
                double plng;
                double prad;
        };

    public:
        double getRadFromGrad(double Grad);
            //Not created yet
        double getGradFromRad(double Grad);
            //Not created yet
        
        class DISTANCE
        {
            public:
                static double getLinearDistance(OBJHANDLE hObj1, OBJHANDLE hObj2); 
                    // Returns the direct distance between two OBJHANDLE - objects in meter
                static double getSurfaceDownrange(OBJHANDLE hObj1, OBJHANDLE hObj2);
                    // Returns the downrange (way over surface) between to OBJHANDLE - objects in meter
                static double getSurfaceDownrangeToPad(VESSEL *V, OBJHANDLE hBase, int padID);
                    /* Returns the downrange (way over surface) between a Vessel and a basepad in meter
                        Errorvalues (TODO):
                        - -1: if hbase is no a base handle
                        - -2: if Vessels reference body is different to the base planet
                    */
            private:
                static double getBaseReferenceRadius(OBJHANDLE hBase);
                    //Returns the radius of the planet where the base is being
                static double getDownrangeBetweenSetObjects(SURFACEPOS *surfacepos1, SURFACEPOS *surfacepos2,double radiusRefPlanet);
                    //Returns the downrange between two set surfacepos object
        };
        
        class DIRECTION
        {
            public:
                static double GetSurfaceDirection(OBJHANDLE hObjFrom, OBJHANDLE hObjTo);
                static double GetSurfaceDirection(OBJHANDLE hObjFrom, OBJHANDLE hObjTo, bool inGRAD);
                /* Returns the direction between two Objects in rad or degrees (degrees is inGRAD is set to true)
                    Errorvalues (TODO):
                    - -1: if hbase is no a base handle
                    - -2: if Vessels reference body is different to the base planet
                */
                static double GetSurfaceBasePadDirection(VESSEL *V, OBJHANDLE hBase, int basePadID);
                static double GetSurfaceBasePadDirection(VESSEL *V, OBJHANDLE hBase, int basePadID, bool inGRAD);
                /* Returns the direction between a vessel and a basepad (hbase + pasepad ID) in rad or degrees (degrees is inGRAD is set to true)
                    Errorvalues (TODO):
                    - -1: if hbase is no a base handle
                    - -2: if Vessels reference body is different to the base planet
                    - -3: if basePad ID > oapiGetBasePadCount(hBase)
                */
            private:
                static double CalcDirectionBetweenSetObjects(SURFACEPOS *surfacepos1, SURFACEPOS *surfacepos2);
        };
};
#endif

Now in the code, you can say for examle:
Code:
#define ORBITER_MODULE
#include "orbitersdk.h"
#include "orbitermath.h"
DLLCLBK void opcPostStep (double ENow, double simdt, double mjd) 
{
    OBJHANDLE hV1 = oapiGetVesselByName("GL-NT");
    OBJHANDLE hBase = oapiGetBaseByName(oapiGetGbodyByName("Moon"),"Brighton Beach");
    char baseName[255];
    oapiGetObjectName(hBase,baseName,255);
    sprintf(oapiDebugString(),"The downrange between GL-NT and Brighton Beach is: %f",ORBITERMATH::DISTANCE::getSurfaceDownrange(hV1,hBase));
}

Sure, this is a verry primitiv example!

What do you think about a open library for add on develppers like this?
Or is there allready somethink like this?

What are yours reqired functions (with solution if possible) you often need?
 
Last edited:

Wishbone

Clueless developer
Addon Developer
Joined
Sep 12, 2010
Messages
2,421
Reaction score
1
Points
0
Location
Moscow

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
See my Lua-centered thread here: http://www.orbiter-forum.com/showthread.php?t=18328

For what I'm trying to do right now (SAMs to protect huts from atmospheric recon overflights) there has to be missile guidance (see http://www.codeproject.com/KB/recipes/Missile_Guidance_System.aspx).

Either a conic- or Runge-Kutta-based closest approach calculator (see TransX source at http://transx.svn.sourceforge.net/viewvc/transx/TransX/).
Hmm looks a bit to hard for me to do it fast but i also want to have such functions :)


Ok now i want to show you whats working now:

Code:
DLLCLBK void opcPostStep (double ENow, double simdt, double mjd) 
{
    ADVANCEDVESSELAPI* advancedVessel = ADVANCEDVESSELAPI::getAVAInterface(oapiGetFocusInterface());
    OBJHANDLE hBase = oapiGetBaseByName(oapiGetGbodyByName("Moon"),"Brighton Beach");
    sprintf(oapiDebugString(),"The downrange between focus vessel and Brigthon Beach PAD 1 is: %f",advancedVessel->GetDownrangeToBasePAD(hBase,0));
}

:tiphat:
 

Tommy

Well-known member
Joined
Aug 14, 2008
Messages
2,019
Reaction score
86
Points
48
Location
Here and now
I haven't yet learned C++, but if I do this will surely be a HUGE help.

Some handy things I can think of are functions that could provide:

RVel between self and a target object (or is this already in the API?)

Whether an object is in daylight or not.

Launch Azimuth/Great Circle heading info.

Calculate escape velocity from current orbit.

I'm sure there are more I could think of. Most are small, fairly simple maths, but it would be easier and faster if they existed in a library rather than everybody re-inventing the wheel all the time.
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Launch Azimuth/Great Circle heading info.

I could contribute to this already. Here are mine, apart from my generic simpson integration function:

Basic types:
Code:
struct Spherical
{
  Spherical() { theta = 0; phi = 0; r = 0; }
  double theta;
  double phi;
  double r;
};

struct Geo
{
  Geo() { lat = 0; lon = 0; }
  double lat;
  double lon;
};

typedef union {
    double data[3];
    struct { double x, y, z; };
} Vect3;

struct Point
{
  Point() { x = 0; y = 0; }
  Point( double x, double y ) { this->x = x; this->y = y; }
  double x;
  double y;
};

Basic math functions:
Code:
double inline dot(const Vect3 & a, const Vect3 & b )
{
  return a.x*b.x + b.y*a.y + a.z*b.z;
}

Vect3 inline cross(const Vect3 & a, const Vect3 & b )
{
  Vect3 v;
  v.x = a.y*b.z-b.y*a.z;
  v.y = a.z*b.x-b.z*a.x;
  v.z = a.x*b.y-b.x*a.y;
  return v;
}

double inline len(const Vect3 & v)
{
  return sqrt(v.x * v.x + v.y * v.y + v.z * v.z );
}

Basic conversion functions:
Code:
Vect3 inline DirectAscent::ConvertSpherical2Cartesian( const Spherical & sph )
{
  Vect3 v;
  v.x = sph.r * sin(sph.theta) * cos(sph.phi);
  v.y = sph.r * sin(sph.theta) * sin(sph.phi);
  v.z = sph.r * cos(sph.theta);

  return v;
}

Spherical inline DirectAscent::ConvertCartesian2Spherical( const Vect3 & v )
{
  Spherical sph;
  sph.r = len(v);
  sph.theta = acos(v.z / sph.r);
  sph.phi = atan2(v.y, v.x);

  return sph;
}

Point DirectAscent::ConvertSpherical2Point(const Spherical & sph )
{
  Point p;
  p.x = sph.phi * sph.r;
  p.y = sph.theta * sph.r;

  return p;
}

Great Circle function (for example for drawing it and finding an object on GC, like in direct ascent program)
Code:
//! Calculates a geographical point on a great circle
/*! Calculates a geographical point on a great circle, given ratio (0,1) between starting and ending geographical locations,
as well as those locations. If the distance between them is equal to 90*, you can speed up the calculations by setting
the last parameter to true
  \param angRatio ratio of position between the two defined points (0,1). Use an arch distance here
  \param geoStart starting geographical position
  \param geoEnd ending geographical position
  \param bQuartDistOptimisation set it to true if distance between positions = 90*, which would speed up calculations
  \return geographical location between starting and ending geographical position
  \sa Geo
*/
Geo DirectAscent::CalcPointOnGC(double angRatio, const Geo & geoStart, const Geo & geoEnd, bool bQuartDistOptimisation)
{
  Geo geo;
  const double & lat1 = geoStart.lat;
  const double & lon1 = geoStart.lon;
  const double & lat2 = geoEnd.lat;
  const double & lon2 = geoEnd.lon;
  // borrowed from http://williams.best.vwh.net/avform.htm#Example
  double d; // distance between points
  if ( bQuartDistOptimisation )
    d = PI/2.0;
  else
    d = 2.0*asin(sqrt((sin((lat1-lat2)/2.0))*sin((lat1-lat2)/2.0)+cos(lat1)*cos(lat2)*sin((lon1-lon2)/2.0)*sin((lon1-lon2)/2.0)));
  double A = sin((1-angRatio)*d)/sin(d);
  double B = sin(angRatio*d)/sin(d);
  double x = A*cos(lat1)*cos(lon1) +  B*cos(lat2)*cos(lon2);
  double y = A*cos(lat1)*sin(lon1) +  B*cos(lat2)*sin(lon2);
  double z = A*sin(lat1)           +  B*sin(lat2);
  geo.lat = atan2(z,sqrt(x*x+y*y));
  geo.lon = atan2(y,x);

  return geo;
}

Azimuth functions:
Code:
//! Calculates azimuth, without taking current ship's velocity into account.
/*!
  \param latitude current ship's latitude
  \param inclination required final inclination
  \return azimuth required for this inclination
  \sa CalcTrueAzimuth()
*/
double DirectAscent::CalcAzimuth( double latitude, double inclination )
{
  double azimuth;

  if ( fabs(latitude - inclination) > 0.001)
    azimuth = asin( cos(inclination) / cos(latitude));
  else
    azimuth = PI/2;

  if (azimuth < 0) azimuth += 2*PI;

  return azimuth;
}

//! Calculates azimuth, taking current ship's velocity into account
/*! Uses the simple azimuth which doesn't take velocity into account for initial calculations
and figures out true required azimuth by comparing current ship's and target's velocities.
  \param latitude current ship's latitude
  \param inclination required final inclination
  \param shVel current ship's velocity
  \param mi Standard gravitational parameter = G * body_mass
  \param targetRadius radius of target or just a given target orbit
  \return true azimuth required for this inclination
  \sa CalcAzimuth(), Point
*/
double DirectAscent::CalcTrueAzimuth( double latitude, double inclination, Point shVel, double mi, double targetRadius )
{
  double azimuth = CalcAzimuth( latitude, inclination );
  // target orbit's velocity for this azimuth
  double tgt_orbit_v_module = sqrt(mi/targetRadius);
  double tgt_orbit_v_y = tgt_orbit_v_module * cos(azimuth); // northern velocity
  double tgt_orbit_v_x = tgt_orbit_v_module * sin(azimuth); // eastern velocity

  double lnch_v_y = fabs (tgt_orbit_v_y - shVel.y );
  double lnch_v_x = tgt_orbit_v_x - shVel.x;

  if (lnch_v_y == 0) lnch_v_y = 0.01; //div by zero protection
  double true_azimuth = atan( lnch_v_x / lnch_v_y );

  if (true_azimuth < 0) true_azimuth += 2*PI;

  return true_azimuth;
}
Let the hundreds of launch azimuth calculators appear! :lol:

---------- Post added at 03:05 PM ---------- Previous post was at 12:19 PM ----------

Topper:
I'd refrain from using "bool inGRAD" in an interface. If you need the radians converted to degrees for final GUI, you can just multiply them by DEG, or RAD if you need it the other way around.
 
Last edited:

Wishbone

Clueless developer
Addon Developer
Joined
Sep 12, 2010
Messages
2,421
Reaction score
1
Points
0
Location
Moscow
Topper:
I'd refrain from using "bool inGRAD" in an interface. If you need the radians converted to degrees for final GUI, you can just multiply them by DEG, or RAD if you need it the other way around.

Seconded. For functions that may be called many times, and their results fed back into calculations, performing DEG to RAD conversion and back hundreds or thousands of times risks significant accuracy degradation (and no, am neither a computer nor a rocket scientist :p)
 
Top