How to convert a spherical velocity coordinates into cartesian - math
I have a velocity vector in altitude, longitude, altitude, I would like to convert it to Cartesian coordinates, vx,vy,vz. The format is from WGS84 standard.
here is the formula
//------------------------------------------------------------------------------
template <class T>
TVectorXYZ<T> WGS84::ToCartesian(T latitude, T longitude, T elevation)
//------------------------------------------------------------------------------
{
double sinlat, coslat;
double sinlon, coslon;
sincos_degree(latitude, sinlat, coslat);
sincos_degree(longitude, sinlon, coslon);
const double v = a / sqrt(1 - WGS84::ee * sinlat*sinlat);
TVectorXYZ<T> coord
(
static_cast<T>((v + elevation) * coslat * sinlon),
static_cast<T>(((1 - WGS84::ee) * v + elevation) * sinlat),
static_cast<T>((v + elevation) * coslat * coslon)
);
return coord;
}
OK based on your previous question and long comment flow lets assume your input is:
lon [rad], lat [rad], alt [m] // WGS84 position
vlon [m/s], vlat [m/s], alt [m/s] // speed in WGS84 lon,lat,alt directions but in [m/s]
And want output:
x,y,z // Cartesian position [m/s]
vx,vy,vz // Cartesian velocity [m/s]
And have valid transformation to Cartesian coordinates for positions at your disposal this is mine:
void WGS84toXYZ(double &x,double &y,double &z,double lon,double lat,double alt) // [rad,rad,m] -> [m,m,m]
{
const double _earth_a=6378137.00000; // [m] WGS84 equator radius
const double _earth_b=6356752.31414; // [m] WGS84 epolar radius
const double _earth_e=8.1819190842622e-2; // WGS84 eccentricity
const double _aa=_earth_a*_earth_a;
const double _ee=_earth_e*_earth_e;
double a,b,x,y,z,h,l,c,s;
a=lon;
b=lat;
h=alt;
c=cos(b);
s=sin(b);
// WGS84 from eccentricity
l=_earth_a/sqrt(1.0-(_ee*s*s));
x=(l+h)*c*cos(a);
y=(l+h)*c*sin(a);
z=(((1.0-_ee)*l)+h)*s;
}
And routine for normalize vector to unit size:
void normalize(double &x,double &y,double &z)
{
double l=sqrt(x*x+y*y+z*z);
if (l>1e-6) l=1.0/l;
x*=l; y*=l; z*=l;
}
Yes you can try to derive the formula lihe #MvG suggest but from your rookie mistakes I strongly doubt it would lead to successful result. Instead you can do this:
obtain lon,lat,alt direction vectors for your position (x,y,z)
that is easy just use some small step increment in WGS84 position convert to Cartesian substract and normalize to unit vectors. Let call these direction basis vectors U,V,W.
double Ux,Uy,Uz; // [m]
double Vx,Vy,Vz; // [m]
double Wx,Wy,Wz; // [m]
double da=1.567e-7; // [rad] angular step ~ 1.0 m in lon direction
double dl=1.0; // [m] altitide step 1.0 m
WGS84toXYZ( x, y, z,lon ,lat,alt ); // actual position
WGS84toXYZ(Ux,Uy,Uz,lon+da,lat,alt ); // lon direction Nort
WGS84toXYZ(Vx,Vy,Vz,lon,lat+da,alt ); // lat direction East
WGS84toXYZ(Wx,Wy,Wz,lon,lat ,alt+dl); // alt direction High/Up
Ux-=x; Uy-=y; Uz-=z;
Vx-=x; Vy-=y; Vz-=z;
Wx-=x; Wy-=y; Wz-=z;
normalize(Ux,Uy,Uz);
normalize(Vx,Vy,Vz);
normalize(Wx,Wy,Wz);
convert velocity from lon,lat,alt to vx,vy,vz
vx = vlon*Ux + vlat*Vx + valt*Wx;
vy = vlon*Uy + vlat*Vy + valt*Wy;
vz = vlon*Uz + vlat*Vz + valt*Wz;
Hope it is clear enough. As usual be careful about the units deg/rad and m/ft/km because units matters a lot.
Btw U,V,W basis vectors form NEH reference frame and in the same time are the direction derivates MvG is mentioning.
[Edit1] more precise conversions
//---------------------------------------------------------------------------
//--- WGS84 transformations ver: 1.00 ---------------------------------------
//---------------------------------------------------------------------------
#ifndef _WGS84_h
#define _WGS84_h
//---------------------------------------------------------------------------
// http://www.navipedia.net/index.php/Ellipsoidal_and_Cartesian_Coordinates_Conversion
//---------------------------------------------------------------------------
// WGS84(a,b,h) = (long,lat,alt) [rad,rad,m]
// XYZ(x,y,z) [m]
//---------------------------------------------------------------------------
const double _earth_a=6378137.00000; // [m] WGS84 equator radius
const double _earth_b=6356752.31414; // [m] WGS84 epolar radius
const double _earth_e=8.1819190842622e-2; // WGS84 eccentricity
//const double _earth_e=sqrt(1.0-((_earth_b/_earth_a)*(_earth_b/_earth_a)));
const double _earth_ee=_earth_e*_earth_e;
//---------------------------------------------------------------------------
const double kmh=1.0/3.6; // [km/h] -> [m/s]
//---------------------------------------------------------------------------
void XYZtoWGS84 (double *abh ,double *xyz ); // [m,m,m] -> [rad,rad,m]
void WGS84toXYZ (double *xyz ,double *abh ); // [rad,rad,m] -> [m,m,m]
void WGS84toXYZ_posvel(double *xyzpos,double *xyzvel,double *abhpos,double *abhvel); // [rad,rad,m],[m/s,m/s,m/s] -> [m,m,m],[m/s,m/s,m/s]
void WGS84toNEH (reper &neh ,double *abh ); // [rad,rad,m] -> NEH [m]
void WGS84_m2rad (double &da,double &db,double *abh); // [rad,rad,m] -> [rad],[rad] representing 1m angle step
void XYZ_interpolate (double *pt,double *p0,double *p1,double t); // [m,m,m] pt = p0 + (p1-p0)*t in ellipsoid space t = <0,1>
//---------------------------------------------------------------------------
void XYZtoWGS84(double *abh,double *xyz)
{
int i;
double a,b,h,l,n,db,s;
a=atanxy(xyz[0],xyz[1]);
l=sqrt((xyz[0]*xyz[0])+(xyz[1]*xyz[1]));
// estimate lat
b=atanxy((1.0-_earth_ee)*l,xyz[2]);
// iterate to improve accuracy
for (i=0;i<100;i++)
{
s=sin(b); db=b;
n=divide(_earth_a,sqrt(1.0-(_earth_ee*s*s)));
h=divide(l,cos(b))-n;
b=atanxy((1.0-divide(_earth_ee*n,n+h))*l,xyz[2]);
db=fabs(db-b);
if (db<1e-12) break;
}
if (b>0.5*pi) b-=pi2;
abh[0]=a;
abh[1]=b;
abh[2]=h;
}
//---------------------------------------------------------------------------
void WGS84toXYZ(double *xyz,double *abh)
{
double a,b,h,l,c,s;
a=abh[0];
b=abh[1];
h=abh[2];
c=cos(b);
s=sin(b);
// WGS84 from eccentricity
l=_earth_a/sqrt(1.0-(_earth_ee*s*s));
xyz[0]=(l+h)*c*cos(a);
xyz[1]=(l+h)*c*sin(a);
xyz[2]=(((1.0-_earth_ee)*l)+h)*s;
}
//---------------------------------------------------------------------------
void WGS84toNEH(reper &neh,double *abh)
{
double N[3],E[3],H[3]; // [m]
double p[3],xyzpos[3];
const double da=1.567e-7; // [rad] angular step ~ 1.0 m in lon direction
const double dl=1.0; // [m] altitide step 1.0 m
vector_copy(p,abh);
// actual position
WGS84toXYZ(xyzpos,abh);
// NEH
p[0]+=da; WGS84toXYZ(N,p); p[0]-=da;
p[1]+=da; WGS84toXYZ(E,p); p[1]-=da;
p[2]+=dl; WGS84toXYZ(H,p); p[2]-=dl;
vector_sub(N,N,xyzpos);
vector_sub(E,E,xyzpos);
vector_sub(H,H,xyzpos);
vector_one(N,N);
vector_one(E,E);
vector_one(H,H);
neh._rep=1;
neh._inv=0;
// axis X
neh.rep[ 0]=N[0];
neh.rep[ 1]=N[1];
neh.rep[ 2]=N[2];
// axis Y
neh.rep[ 4]=E[0];
neh.rep[ 5]=E[1];
neh.rep[ 6]=E[2];
// axis Z
neh.rep[ 8]=H[0];
neh.rep[ 9]=H[1];
neh.rep[10]=H[2];
// gpos
neh.rep[12]=xyzpos[0];
neh.rep[13]=xyzpos[1];
neh.rep[14]=xyzpos[2];
neh.orto(1);
}
//---------------------------------------------------------------------------
void WGS84toXYZ_posvel(double *xyzpos,double *xyzvel,double *abhpos,double *abhvel)
{
reper neh;
WGS84toNEH(neh,abhpos);
neh.gpos_get(xyzpos);
neh.l2g_dir(xyzvel,abhvel);
}
//---------------------------------------------------------------------------
void WGS84_m2rad(double &da,double &db,double *abh)
{
// WGS84 from eccentricity
double p[3],rr;
WGS84toXYZ(p,abh);
rr=(p[0]*p[0])+(p[1]*p[1]);
da=divide(1.0,sqrt(rr));
rr+=p[2]*p[2];
db=divide(1.0,sqrt(rr));
}
//---------------------------------------------------------------------------
void XYZ_interpolate(double *pt,double *p0,double *p1,double t)
{
const double mz=_earth_a/_earth_b;
const double _mz=_earth_b/_earth_a;
double p[3],r,r0,r1;
// compute spherical radiuses of input points
r0=sqrt((p0[0]*p0[0])+(p0[1]*p0[1])+(p0[2]*p0[2]*mz*mz));
r1=sqrt((p1[0]*p1[0])+(p1[1]*p1[1])+(p1[2]*p1[2]*mz*mz));
// linear interpolation
r = r0 +(r1 -r0 )*t;
p[0]= p0[0]+(p1[0]-p0[0])*t;
p[1]= p0[1]+(p1[1]-p0[1])*t;
p[2]=(p0[2]+(p1[2]-p0[2])*t)*mz;
// correct radius and rescale back
r/=sqrt((p[0]*p[0])+(p[1]*p[1])+(p[2]*p[2]));
pt[0]=p[0]*r;
pt[1]=p[1]*r;
pt[2]=p[2]*r*_mz;
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
However they require basic 3D vector math see here for equations:
Understanding 4x4 homogenous transform matrices
Take the formula you use to convert positions from geographic to Cartesian coordinates. That's some vector p(λ,φ,h) ∈ ℝ³, i.e. you turn latitude, longitude and altitude into a three-element vector of x,y,z coordinates. Now compute the partial derivatives of this formula with respect to the three parameters. You will get three vectors, which should be orthogonal to one another. The derivative with respect to longitude λ should be pointing locally east, the one with respect to latitude φ pointing north, the one with respect to altitude h pointing up. Multiply these vectors with the velocities you have to obtain a Cartesian velocity vector.
Observe how the units match: the position is in meters, the first two derivatives are meters per degree, and the velocity would be degrees per second. Or something else, perhaps miles and radians.
All of this is fairly easy for the sphere. For the WGS84 ellipsoid the position formula is a bit more involved, and that complexity will carry through the computation.
Related
Lat/Lng to Web Mercator Projection Issues
I've got some simple code in a Qt application which converts from a latitude/longitude coordinate to a web mercator x/y position: // Radius of the Earth in metres const double EARTH_RADIUS = 20037508.34; // Convert from a LL to a QPointF QPointF GeoPoint::toMercator() { double x = this->longitude() * EARTH_RADIUS / 180.0; double y = log(tan((90.0 + this->latitude()) * PI / 360.0)) / (PI / 180.0); y = y * EARTH_RADIUS / 180.0; return QPointF(x, y); } // Convert from a QPointF to a LL GeoPoint GeoPoint::fromMercator(const QPointF &pt) { double lon = (pt.x() / EARTH_RADIUS) * 180.0; double lat = (pt.y() / EARTH_RADIUS) * 180.0; lat = 180.0 / PI * (2 * atan(exp(lat * PI / 180.0)) - PI / 2.0); return GeoPoint(lat, lon); } I'm wanting to get the geographic position of a number of objects which are in metres distance away from a geographic origin, however either my lack of understanding or source code are not correct. Consider the following: GeoPoint pt1(54.253230, -3.006460); QPointF m1 = pt1.toMercator(); qDebug() << m1; // QPointF(-334678,7.21826e+06) // Now I want to add a distance onto the mercator coordinates, i.e. 50 metres m1.rx() += 50.0; qDebug() << m1; // QPointF(-334628,7.21826e+06) // Take this back to a LL GeoPoint pt1a = GeoPoint::fromMercator(m1); qDebug() << pt1a.toString(); // "54.25323°, -3.00601°" If I plot the two LL coordinates into Google Earth, they are not 50m apart as expected, they are about 29.3m apart. I'm perplexed!
Haversine Formula Error - Incorrect Distance - Arduino
Currently taking part in a project that requires to take readings from a gps module and then using these calculate the distance between the readings and a fixed waypoint. The Gps works and gives the values of LAT - 54.9289 and LON - -1.368 this should give a distance of about 3,200 meters. however it gives around 6105. I also have a feeling that 6105 is km to haha. Im wondering if its not taking the negative numbers correctly or if i have some variable conflicts in the code. Any light shed on this would be great, thanks. #include <TinyGPS.h> #include <SoftwareSerial.h> #include <rgb_lcd.h> #include <Wire.h> //Sets TX And RX Pins SoftwareSerial GPS(2,3); TinyGPS gps; void gpsdump(TinyGPS &gps); bool feedgps(); void CheckGPS(); void GetCoords(); long lat, lon; float LAT, LON; // Latitude is gained from GPS and stored in another variable to avoid errors - Should change with changing GPS value - Which would alter distance to waypoint. float LAT1,LON1; rgb_lcd lcd; void setup() { // Sets Baud Rate GPS.begin(9600); Serial.begin(115200); } // Determines The Distance Between Current Location And Waypoint void GetDistance() { // Calculating Distance Between Waypoints double Distance_Lat; // Distance between Lattitude values double Distance_Lon; // Distance between Lonitude values double Distance_Total = 0;// Total Distance double val,val2; // Subsidary variable for holding numbers. - No actual value represented. double fLAT1,fLAT2; double LAT2 = 54.900000; // Waypoint Latitude double LON2 = -1.368072; // Waypoint Longitude // Initialising Calculation Distance_Lat = radians(LAT2-LAT1); // Must be done in radians fLAT1 = radians(LAT1); fLAT2 = radians(LAT2); Distance_Lon = radians((LON2)-(LON1)); // Calculating Distance - Using Haversines Formulae Distance_Total = (sin(Distance_Lat/2.0)*sin(Distance_Lat/2.0)); val = cos(fLAT1); val = val*(cos(fLAT2)); val = val*(sin(Distance_Lon/2.0)); val = val*(sin(Distance_Lon/2.0)); Distance_Total = Distance_Total + val; Distance_Total = 2*atan2(sqrt(Distance_Total),sqrt(1.0-Distance_Total)); Distance_Total = Distance_Total*6371.0000; // Converting to meters. Serial.println("Distance: "); Serial.println(Distance_Total); //--------------------------------------------------------------------------------- } // Returns Latitude And Longitude As Decimal Degrees (DD). void GetCoords() { long lat, lon; CheckGPS(); Serial.print("Latitude : "); Serial.print(LAT/1000000,7); Serial.print(" :: Longitude : "); Serial.println(LON/1000000,7); } void CheckGPS() { bool newdata = false; unsigned long start = millis(); // Every 1 seconds, Print an update while (millis() - start < 1000) { if (feedgps ()) newdata = true; if (newdata) gpsdump(gps); } } // Checks If The GPS Has Any Data To Transmit bool feedgps() { while (GPS.available()) if (gps.encode(GPS.read())) return true; else return false; } // Transmits GPS Data And Gets Latitude And Longitude Positions. void gpsdump(TinyGPS &gps) { gps.get_position(&lat, &lon); LAT = lat; LON = lon; //Keeps The GPS Fed To Avoid Checksum Errors. feedgps(); } void loop() { // Function That Returns The GPS Coordinates In DD. GetCoords(); GetDistance(); }
The haversine formula I'm looking at on Wikipedia at right now, https://en.wikipedia.org/wiki/Haversine_formula, has arcsin(sqrt(Distance_Total)) where you have your atan2.
Projection of a vector in processing using jama
I want to project A vector onto vector a and vector c, in Processing. In my sketch vector a is red and c is blue, I wanted c to be perpendicular to b but this is where i'm having alot of trouble. I'm using the JAMA library to try and make this easier. Any help with this is much appreciated as I have been stumped for about a week now. float X=200; // Origin : Note we have now centred the origin in the X-direction float Y=350; float ax=150; // Vector a resolved into components float ay=-50; float bx=0; // Vector b resolved into components float by=-150; float cx=150; float cy=200; Matrix a; Matrix b; Matrix c; void setup() { size(400,400); // Create a drawing window strokeWeight(3); // Make pen 3 pixels wide for all lines double [][] anums = {{ax}, {ay}}; double [][] bnums = {{bx}, {by}}; double [][] cnums = {{-cy}, {cx}}; a = new Matrix(anums); b = new Matrix(bnums); c = new Matrix(cnums); } void draw() { background(255); // Clear screen // Evaluate equation (1.5) // STEP1: Insert code here that computes a_unit (i.e. the unit vector in the // direction of a double length = a.norm2(); Matrix a_unit= a.times(1/length); // STEP2: Insert code here to compute the dot product of b and a_unit Matrix a_unit_T = a_unit.transpose(); Matrix projection = a_unit_T.times(b); double lp = projection.get(0,0); // STEP3 Insert code here to compute the vector p using equation 1.5 above Matrix p = a_unit.times(lp); float px = (float)p.get(0,0); float py = (float)p.get(1,0); float ax = (float)a.get(0,0); float ay = (float)a.get(1,0); float bx = (float)b.get(0,0); float by = (float)b.get(1,0); float cx = (float)c.get(0,0); float cy = (float)c.get(1,0); // Draw the projection of b onto a stroke(0,0,0); // Use a black pen ellipse(X+px,Y+py,10,10); // point where b projects onto a line(X+px,Y+py,X+bx,Y+by); // line from a to point of projection on b stroke(255,0,0); // Make pen red arrow(X,Y,X+ax,Y+ay); // Draw vector a starting at (X,Y) //stroke(0,0,255); //arrow(X,Y,X-ax,Y+ay); stroke(0,255,0); // Make pen green arrow(X,Y,X+bx,Y+by); // Draw vector b starting at (X,Y) // STEP 4. Insert code here to add a new vector at 90 degrees to the vector a stroke(0,0,255); arrow(X,Y,X+cx,Y+cy); // STEP 5. Insert code here to compute and draw the projection of b onto c double length1 = c.norm2(); Matrix c_unit= c.times(1/length1); // STEP2: Insert code here to compute the dot product of b and a_unit Matrix c_unit_T = c_unit.transpose(); Matrix projection1 = c_unit_T.times(b); double lp1 = projection.get(0,0); // STEP3 Insert code here to compute the vector p using equation 1.5 above Matrix r = c_unit.times(lp1); float rx = (float)r.get(0,0); float ry = (float)r.get(1,0); stroke(0,0,0); // Use a black pen ellipse(X+rx,Y+ry,10,10); // point where b projects onto a line(X+rx,Y+ry,X+bx,Y+by); // line from a to point of projection on b if (mouseButton == RIGHT) { a.set(0,0,(double)mouseX-X); a.set(1,0,(double)mouseY-Y); } if (mouseButton == LEFT) { b.set(0,0,(double)mouseX-X); b.set(1,0,(double)mouseY-Y); } } // Draw an arrow from (x1,y1) to (x2,y2) void arrow(float x1, float y1, float x2, float y2) { line(x1, y1, x2, y2); pushMatrix(); translate(x2, y2); float a = atan2(x1-x2, y2-y1); rotate(a); line(0, 0, -8, -8); line(0, 0, 8, -8); popMatrix(); }
Here is the code mate, float X=200; // Origin : Note we have now centred the origin in the X-direction float Y=350; float ax=300; // Vector a resolved into components float ay=-100; float bx=0; // Vector b resolved into components float by=-300; Matrix a; Matrix b; void setup() { size(400,400); // Create a drawing window strokeWeight(3); // Make pen 3 pixels wide for all lines double [][] anums = {{ax}, {ay}}; double [][] bnums = {{bx}, {by}}; a = new Matrix(anums); b = new Matrix(bnums); } void draw() { background(255); // Clear screen // Evaluate equation (1.5) // STEP1: Insert code here that computes a_unit (i.e. the unit vector in the // direction of a double length = a.norm2(); Matrix a_unit = a.times(1/length); // STEP2: Insert code here to compute the dot product of b and a_unit Matrix a_unit_T = a_unit.transpose(); Matrix projection = a_unit_T.times(b); double lp = projection.get(0,0); // STEP3: Insert code here to compute the vector p using equation 1.5 above Matrix p = a_unit.times(lp); float px = (float)p.get(0,0); float py = (float)p.get(1,0); float ax = (float)a.get(0,0); float ay = (float)a.get(1,0); float bx = (float)b.get(0,0); float by = (float)b.get(1,0); // Draw the projection of b onto a stroke(0,0,0); // Use a black pen ellipse(X+px,Y+py,10,10); // point where b projects onto a line(X+px,Y+py,X+bx,Y+by); // line from a to point of projection on b stroke(255,0,0); // Make pen red arrow(X,Y,X+ax,Y+ay); // Draw vector a starting at (X,Y) stroke(0,255,0); // Make pen green arrow(X,Y,X+bx,Y+by); // Draw vector b starting at (X,Y) // STEP 4. Insert code here to add a new vector at 90 degrees to the vector a double [][] cnums = {{ay}, {-ax}}; Matrix c = new Matrix(cnums); float cx = (float)c.get(0,0); float cy = (float)c.get(1,0); stroke(0,0,255); arrow(X,Y,X+cx,Y+cy); // STEP 5. Insert code here to compute and draw the projection of b onto c double length1 = c.norm2(); Matrix c_unit= c.times(1/length1); Matrix c_unit_T = c_unit.transpose(); Matrix projection1 = c_unit_T.times(b); double lp1 = projection1.get(0,0); Matrix r = c_unit.times(lp1); float rx = (float)r.get(0,0); float ry = (float)r.get(1,0); stroke(0,0,0); // Use a black pen ellipse(X+rx,Y+ry,10,10); // point where b projects onto a line(X+rx,Y+ry,X+bx,Y+by); // line from a to point of projection on b if (mouseButton == RIGHT) { a.set(0,0,(double)mouseX-X); a.set(1,0,(double)mouseY-Y); } if (mouseButton == LEFT) { b.set(0,0,(double)mouseX-X); b.set(1,0,(double)mouseY-Y); } } // Draw an arrow from (x1,y1) to (x2,y2) void arrow(float x1, float y1, float x2, float y2) { line(x1, y1, x2, y2); pushMatrix(); translate(x2, y2); float a = atan2(x1-x2, y2-y1); rotate(a); line(0, 0, -8, -8); line(0, 0, 8, -8); popMatrix(); }
draw flighroute on mercator map how to calculate polyline points with a given longitude
i would like to draw a polyline on a Mercator map between two cities. e.g Startpoints: Location berlin = new Location(52.517, 13.40); Location tokio = new Location(35.70,139.767); it should look like a flight route. so my plan was to go through all longitude values between the two cities and calculate corresponding latitude values: LocationCollection locationCollection = new LocationCollection(); Location next = new Location(berlin.Latitude,berlin.Longitude); //startpunkt for (double x = berlin.Longitude+1; x < tokio.Longitude; x++) { locationCollection.Add(next); next = new Location(???, x); } the question is how can i calculate the latitude for each longitude value for the polyline? Thanks!
From this link: Here's an implementation in C. #define PI 3.14159265358979323846 double degrees_radians(double d) { return d * PI / 180.0; } double radians_degrees(double r) { return r * 180.0 / PI; } double latitude(double lat1, double lon1, double lat2, double lon2, double lon) { return atan((sin(lat1)*cos(lat2)*sin(lon-lon2)-sin(lat2)*cos(lat1)*sin(lon-lon1))/(cos(lat1)*cos(lat2)*sin(lon1-lon2))); } int main() { // start and end in degrees double lat1_d = 52.517; double lon1_d = 13.40; double lat2_d = 35.70; double lon2_d = 139.767; // start and end in radians double lat1_r = degrees_radians(lat1_d); double lon1_r = degrees_radians(lon1_d); double lat2_r = degrees_radians(lat2_d); double lon2_r = degrees_radians(lon2_d); // interpolate latitide at every degree of longitude between 1 and 2 for (double lon = ceil(lon1_d); lon < lon2_d; lon += 1.0) { double lat_r = latitude(lat1_r, lon1_r, lat2_r, lon2_r, degrees_radians(lon)); double lat_d = radians_degrees(lat_r); printf("%.3f , %.3f\n", lat_d, lon); } return 0; } The maximum latitude reached on the great circle between Berlin and Tokyo is then shown to be 66.183° at longitude 68°.
Bounding Spheres move farther than sphere object
I have a program that I'm making with others and I ran into a problem. I'm working on adding in polygon models into our scene in an XNA window. I have that part complete. I also have bounding spheres(I know I tagged as bounding-box but there is no bounding sphere tag) drawing around each polygon. My problem is when I move the polygons around the 3D space the bounding spheres move twice as much as the polygons. I imagine its something within my polygon matrices that I use to create the bounding sphere that makes it move twice as much but that is only speculation. So just to clarify I'll give you an example of my problem. If I hold down D to move a polygon along the X axis. (model.position.X--;) The polygon moves as expected to but the bounding sphere around the polygon moves twice as much. Thanks for the help guys! Here is how I draw the models and the bounding spheres: public void Draw(Matrix view, Matrix projection, bool drawBoundingSphere) { Matrix translateMatrix = Matrix.CreateTranslation(position); Matrix worldMatrix = translateMatrix * Matrix.CreateScale(scaleRatio); foreach (ModelMesh mesh in model.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.World = worldMatrix * modelAbsoluteBoneTransforms[mesh.ParentBone.Index]; effect.View = view; effect.Projection = projection; effect.EnableDefaultLighting(); effect.PreferPerPixelLighting = true; } mesh.Draw(); if (drawBoundingSphere) { // the mesh's BoundingSphere is stored relative to the mesh itself. // (Mesh space). We want to get this BoundingSphere in terms of world // coordinates. To do this, we calculate a matrix that will transform // from coordinates from mesh space into world space.... Matrix world = modelAbsoluteBoneTransforms[mesh.ParentBone.Index] * worldMatrix; // ... and then transform the BoundingSphere using that matrix. BoundingSphere sphere = BoundingSphereRenderer.TransformBoundingSphere(mesh.BoundingSphere, world); // now draw the sphere with our renderer BoundingSphereRenderer.Draw(sphere, view, projection); } } And here is the BoundingSphereRenderer Code: private static VertexBuffer vertexBuffer; private static BasicEffect effect; private static int lineCount; public static void Initialize(GraphicsDevice graphicsDevice, int sphereResolution) { // create our effect effect = new BasicEffect(graphicsDevice); effect.LightingEnabled = false; effect.VertexColorEnabled = true; // calculate the number of lines to draw for all circles lineCount = (sphereResolution + 1) * 3; // we need two vertices per line, so we can allocate our vertices VertexPositionColor[] vertices = new VertexPositionColor[lineCount * 2]; // compute our step around each circle float step = MathHelper.TwoPi / sphereResolution; // used to track the index into our vertex array int index = 0; //create the loop on the XY plane first for (float angle = 0f; angle < MathHelper.TwoPi; angle += step) { vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0f), Color.Blue); vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle + step), (float)Math.Sin(angle + step), 0f), Color.Blue); } //next on the XZ plane for (float angle = 0f; angle < MathHelper.TwoPi; angle += step) { vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle), 0f, (float)Math.Sin(angle)), Color.Red); vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle + step), 0f, (float)Math.Sin(angle + step)), Color.Red); } //finally on the YZ plane for (float angle = 0f; angle < MathHelper.TwoPi; angle += step) { vertices[index++] = new VertexPositionColor(new Vector3(0f, (float)Math.Cos(angle), (float)Math.Sin(angle)), Color.Green); vertices[index++] = new VertexPositionColor(new Vector3(0f, (float)Math.Cos(angle + step), (float)Math.Sin(angle + step)), Color.Green); } // now we create the vertex buffer and put the vertices in it vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(vertices); } public static void Draw(this BoundingSphere sphere, Matrix view, Matrix projection) { if (effect == null) throw new InvalidOperationException("You must call Initialize before you can render any spheres."); // set the vertex buffer effect.GraphicsDevice.SetVertexBuffer(vertexBuffer); // update our effect matrices effect.World = Matrix.CreateScale(sphere.Radius) * Matrix.CreateTranslation(sphere.Center); effect.View = view; effect.Projection = projection; // draw the primitives with our effect effect.CurrentTechnique.Passes[0].Apply(); effect.GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, lineCount); } public static BoundingSphere TransformBoundingSphere(BoundingSphere sphere, Matrix transform) { BoundingSphere transformedSphere; // the transform can contain different scales on the x, y, and z components. // this has the effect of stretching and squishing our bounding sphere along // different axes. Obviously, this is no good: a bounding sphere has to be a // SPHERE. so, the transformed sphere's radius must be the maximum of the // scaled x, y, and z radii. // to calculate how the transform matrix will affect the x, y, and z // components of the sphere, we'll create a vector3 with x y and z equal // to the sphere's radius... Vector3 scale3 = new Vector3(sphere.Radius, sphere.Radius, sphere.Radius); // then transform that vector using the transform matrix. we use // TransformNormal because we don't want to take translation into account. scale3 = Vector3.TransformNormal(scale3, transform); // scale3 contains the x, y, and z radii of a squished and stretched sphere. // we'll set the finished sphere's radius to the maximum of the x y and z // radii, creating a sphere that is large enough to contain the original // squished sphere. transformedSphere.Radius = Math.Max(scale3.X, Math.Max(scale3.Y, scale3.Z)); // transforming the center of the sphere is much easier. we can just use // Vector3.Transform to transform the center vector. notice that we're using // Transform instead of TransformNormal because in this case we DO want to // take translation into account. transformedSphere.Center = Vector3.Transform(sphere.Center, transform); return transformedSphere; }