00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00031 #include <math.h>
00032 #include "../Include/Utility.h"
00033 #include "../Include/Globals.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 static double globe_tile_lat_table [129];
00047
00061 void init_globe_tile_table ()
00062 {
00063 int i;
00064
00065 double k = 360.0 / 256.0;
00066 globe_tile_lat_table[0] = 0.0;
00067 for (i=1; i<129; i++) {
00068 double prev = globe_tile_lat_table[i-1];
00069 double prevRad = DegToRad (prev);
00070 globe_tile_lat_table[i] = prev + k * cos(prevRad);
00071 }
00072
00073 #ifdef DUMP_GLOBE_TILE_BOUNDARIES
00074
00075 FILE* f = fopen ("Debug\\LatitudeTable.txt", "w");
00076 fprintf (f, "GT Table:\n\n");
00077 fprintf (f, "Z-Index South Boundary North Boundary\n");
00078 for (i=0; i<256; i++) {
00079 double n, s;
00080 globe_tile_lat_bounds (i, s, n);
00081
00082 SPosition pos;
00083 pos.lon = pos.alt = 0;
00084
00085 pos.lat = s * 3600;
00086 char temp[64];
00087 FormatPosition (pos, temp);
00088 char south[64];
00089 memset (south, 0, 64);
00090 strncpy (south, temp, 16);
00091
00092 pos.lat = n * 3600;
00093 FormatPosition (pos, temp);
00094 char north[64];
00095 memset (north, 0, 64);
00096 strncpy (north, temp, 16);
00097
00098 double refLat;
00099 if (i >= 128) {
00100
00101 refLat = s * 3600;
00102 } else {
00103
00104 refLat = n * 3600;
00105 }
00106 fprintf (f, " %3d %s %s\n", i, south, north);
00107 }
00108
00109
00110 fprintf (f, "\n\n");
00111 fprintf (f, "QGT Table:\n");
00112 fprintf (f, "----------\n");
00113 fprintf (f, "Z-Index South Boundary North Boundary\n");
00114 for (i=0; i<512; i++) {
00115 double n, s;
00116 qgt_lat_bounds (i, s, n);
00117
00118 SPosition pos;
00119 pos.lon = pos.alt = 0;
00120
00121 pos.lat = s * 3600;
00122 char temp[64];
00123 FormatPosition (pos, temp);
00124 char south[64];
00125 memset (south, 0, 64);
00126 strncpy (south, temp, 16);
00127
00128 pos.lat = n * 3600;
00129 FormatPosition (pos, temp);
00130 char north[64];
00131 memset (north, 0, 64);
00132 strncpy (north, temp, 16);
00133
00134 double refLat;
00135 if (i >= 128) {
00136
00137 refLat = s * 3600;
00138 } else {
00139
00140 refLat = n * 3600;
00141 }
00142 fprintf (f, " %3d %s %s\n", i, south, north);
00143 }
00144
00145 fclose (f);
00146 #endif
00147 }
00148
00149
00156 static double globe_tile_lon (int x)
00157 {
00158 return (double)x * 360.0 / 256.0;
00159 }
00160
00171 void qgt_position (SPosition pos, int &qx, int &qz, double &x, double &z)
00172 {
00173
00174 lat_lon_to_qgt (pos.lat, pos.lon, qx, qz);
00175 double w, e, s, n;
00176 qgt_lon_bounds (qx, w, e);
00177 qgt_lat_bounds (qz, s, n);
00178 w *= 3600.0;
00179 e *= 3600.0;
00180 n *= 3600.0;
00181 s *= 3600.0;
00182
00183 double xSpan = (e - w) / 2.0;
00184 double zSpan = (n - s) / 2.0;
00185 double xMid = w + xSpan;
00186 double zMid = s + zSpan;
00187 x = -(pos.lon - xMid) / xSpan;
00188 z = -(pos.lat - zMid) / zSpan;
00189 }
00190
00191 void delta_qgt (SPosition pos, int rx, int rz, double &x, double &z)
00192 {
00193
00194 int px, pz;
00195 qgt_position (pos, px, pz, x, z);
00196
00197 x += (double)(rx - px);
00198 z += (double)(rz - pz);
00199 }
00200
00213 void lat_lon_to_qgt (double latArg, double lonArg, int &x, int &z)
00214 {
00215
00216 latArg /= 3600.0;
00217 lonArg /= 3600.0;
00218
00219 int gtx = 0, gtz = 0;
00220 lat_lon_to_globe_tile (latArg, lonArg, gtx, gtz);
00221
00222
00223
00224 int xOffset = 0;
00225 double w, e;
00226 globe_tile_lon_bounds (gtx, w, e);
00227
00228 if (lonArg > (w + ((e-w)/2.0))) {
00229
00230 xOffset = 1;
00231 }
00232
00233
00234
00235
00236 int zOffset = 0;
00237 double n, s;
00238 globe_tile_lat_bounds (gtz, s, n);
00239 if (latArg > (s + ((n-s)/2))) {
00240
00241 zOffset = 1;
00242 }
00243
00244
00245 x = (gtx * 2) + xOffset;
00246 z = (gtz * 2) + zOffset;
00247 }
00248
00264 void lat_lon_to_globe_tile (double latArg, double lonArg, int &x, int &z)
00265 {
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 double absLat = fabs(latArg);
00281 if ((lonArg < 0.0) || (lonArg > 360.0) || (absLat > globe_tile_lat_table[128])) {
00282
00283 gtfo ("lat_lon_to_globe_tile : Illegal lat/lon lat=%f lon=%f", latArg, lonArg);
00284 }
00285
00286
00287 x = (int)((lonArg / 360.0) * 256.0);
00288
00289
00290 int min = 0;
00291 int max = 128;
00292 while ((max - min) > 1) {
00293 int mid = min + ((max - min) / 2);
00294 if (absLat > globe_tile_lat_table[mid]) {
00295 min = mid;
00296 } else {
00297 max = mid;
00298 }
00299 }
00300
00301 if (latArg > 0.0) {
00302
00303 z = min + 128;
00304 } else {
00305
00306 z = 127 - min;
00307 }
00308 }
00309
00317 void globe_tile_lon_bounds (int x, double &w, double &e)
00318 {
00319 if ((x < 0) || (x > 255)) {
00320
00321 gtfo ("globe_tile_lon_bounds : Illegal GT index x=%d", x);
00322 } else {
00323 w = globe_tile_lon (x);
00324 e = globe_tile_lon (x+1);
00325 }
00326 }
00327
00328
00336 void globe_tile_lat_bounds (int z, double &s, double &n)
00337 {
00338 if (z <= 127) {
00339
00340 n = -globe_tile_lat_table[127 - z];
00341 s = -globe_tile_lat_table[128 - z];
00342 } else if (z <= 255) {
00343
00344 n = globe_tile_lat_table[z - 127];
00345 s = globe_tile_lat_table[z - 128];
00346 } else {
00347
00348 gtfo ("globe_tile_lat_bounds : Illegal GT index z=%d", z);
00349 }
00350 }
00351
00359 void qgt_lon_bounds (int x, double &w, double &e)
00360 {
00361 globe_tile_lon_bounds (x/2, w, e);
00362
00363 double half = w + ((e - w) / 2.0);
00364 if ((x % 2) == 0) {
00365
00366 e = half;
00367 } else {
00368
00369 w = half;
00370 }
00371 }
00372
00380 void qgt_lat_bounds (int z, double &s, double &n)
00381 {
00382 globe_tile_lat_bounds (z/2, s, n);
00383
00384 double half = s + ((n - s) / 2);
00385 if ((z % 2) == 0) {
00386
00387 n = half;
00388 } else {
00389
00390 s = half;
00391 }
00392 }
00393
00394 #define ARCSEC2RAD ((2.0 * PI) / 3600.0)
00395
00396
00397
00398
00399 void FormatPosition (SPosition pos, char* s)
00400 {
00401 double latSec = pos.lat;
00402 char latHemi;
00403 if (latSec >= 0) {
00404 latHemi = 'N';
00405 } else {
00406 latHemi = 'S';
00407 latSec = fabs(latSec);
00408 }
00409
00410 double lonSec = pos.lon;
00411 char lonHemi;
00412 if (lonSec >= (180.0 * 3600)) {
00413 lonHemi = 'W';
00414 lonSec = (360 * 3600) - lonSec;
00415 } else {
00416 lonHemi = 'E';
00417 }
00418
00419 double latDeg = floor (latSec / 3600);
00420 latSec -= (latDeg * 3600);
00421 double latMin = floor (latSec / 60);
00422 latSec -= (latMin * 60);
00423
00424 double lonDeg = floor (lonSec / 3600);
00425 lonSec -= (lonDeg * 3600);
00426 double lonMin = floor (lonSec / 60);
00427 lonSec -= (lonMin * 60);
00428
00429 sprintf (s, "%c %2.0f %2.0f'%7.4f\" %c %2.0f %2.0f'%7.4f\"",
00430 latHemi, latDeg, latMin, latSec, lonHemi, lonDeg, lonMin, lonSec);
00431 }
00432
00433
00434
00435
00436
00437 void FormatRADec (double ra, double dec, char* s)
00438 {
00439 ra = WrapTwoPi (ra) * 24.0 / (2 * SGD_PI);
00440 dec = RadToDeg (dec);
00441
00442
00443 double ra_hr, ra_min, ra_sec;
00444 ra_hr = floor (ra);
00445 ra -= ra_hr;
00446 ra_min = floor (ra * 60);
00447 ra -= ra_min / 60;
00448 ra_sec = ra * 3600;
00449
00450
00451 double dec_deg, dec_min, dec_sec;
00452 dec_deg = floor (dec);
00453 dec -= dec_deg;
00454 dec_min = floor (dec * 60);
00455 dec -= dec_min / 60;
00456 dec_sec = dec * 3600;
00457
00458 sprintf (s, "%2.0fh %2.0fm %7.3fs %3.0fd %2.0fm %7.3fs",
00459 ra_hr, ra_min, ra_sec, dec_deg, dec_min, dec_sec);
00460 }
00461
00462
00463
00464
00465
00466 void FormatSiderealTime (double st, char *s)
00467 {
00468 double st_hr, st_min, st_sec;
00469 st_hr = floor (st);
00470 st -= st_hr;
00471 st_min = floor (st * 60);
00472 st -= st_min / 60;
00473 st_sec = st * 3600;
00474
00475 sprintf (s, "%2.0f:%02.0f:%05.3fs", st_hr, st_min, st_sec);
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 void CIE_Yxy_to_XYZ (const SCIE in, SCIE &out)
00488 {
00489 out.XYZ.X = in.Yxy.x * (in.Yxy.Y / in.Yxy.y);
00490 out.XYZ.Y = in.Yxy.Y;
00491 out.XYZ.Z = (1 - in.Yxy.x - in.Yxy.y) * (in.Yxy.Y / in.Yxy.y);
00492 }
00493
00494
00495
00496
00497
00498 void CIE_XYZ_to_RGB_D65 (const SCIE XYZ, sgdVec3 &RGB)
00499 {
00500
00501 float mWhite[3][3];
00502 mWhite[0][2] = 3.240479;
00503 mWhite[0][1] = -1.537150;
00504 mWhite[0][0] = -0.498535;
00505
00506 mWhite[1][2] = -0.969256;
00507 mWhite[1][1] = 1.875992;
00508 mWhite[1][0] = 0.041556;
00509
00510 mWhite[2][2] = 0.055648;
00511 mWhite[2][1] = -0.204043;
00512 mWhite[2][0] = 1.057311;
00513
00514 RGB[0] = ((mWhite[0][2] * XYZ.XYZ.X) + (mWhite[0][1] * XYZ.XYZ.Y) + (mWhite[0][0] * XYZ.XYZ.Z)) / 100.0;
00515 RGB[1] = ((mWhite[1][2] * XYZ.XYZ.X) + (mWhite[1][1] * XYZ.XYZ.Y) + (mWhite[1][0] * XYZ.XYZ.Z)) / 100.0;
00516 RGB[2] = ((mWhite[2][2] * XYZ.XYZ.X) + (mWhite[2][1] * XYZ.XYZ.Y) + (mWhite[2][0] * XYZ.XYZ.Z)) / 100.0;
00517 }
00518
00519
00520
00521
00522
00523
00524 float TerrainScale (SPosition pos)
00525 {
00526 return cos(DegToRad(pos.lat / 3600.0));
00527 }
00528
00529
00530
00531
00532 float GlobeTileDistance (void)
00533 {
00534 return NmToFeet ((360.0 / 256.0) * 60.0);
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544 SVector PosToFlatCartesian (SPosition pos, int x, int z)
00545 {
00546
00547 double s, n, w, e;
00548 globe_tile_lat_bounds (z, s, n);
00549 globe_tile_lon_bounds (x, w, e);
00550 double latScale = (360.0 / 256.0) / fabs(n - s);
00551 n *= 3600;
00552 s *= 3600;
00553 w *= 3600;
00554 e *= 3600;
00555
00556
00557 double midLon = w + ((e - w) / 2);
00558 double midLat;
00559 if (pos.lat >= 0) {
00560
00561 midLat = s + ((n - s) / 2);
00562 } else {
00563
00564 midLat = n + ((s - n) / 2);
00565 }
00566
00567
00568 double dLon = pos.lon - midLon;
00569 double dLat = pos.lat - midLat;
00570 dLat *= latScale;
00571
00572
00573 double easting = NmToFeet(dLon / 60.0);
00574 double northing = NmToFeet(dLat / 60.0);
00575
00576 SVector v;
00577 v.x = easting;
00578 v.y = northing;
00579 v.z = pos.alt;
00580
00581 return v;
00582 }
00583
00584 SVector PosToFlatCartesian (SPosition pos)
00585 {
00586 int gx, gz;
00587 lat_lon_to_globe_tile (pos.lat/3600.0, pos.lon/3600.0, gx, gz);
00588 return PosToFlatCartesian (pos, gx, gz);
00589 }
00590
00591 SVector PosToScaledFlatCartesian (SPosition pos)
00592 {
00593 SVector v;
00594
00595 int gx, gz;
00596 lat_lon_to_globe_tile (pos.lat/3600.0, pos.lon/3600.0, gx, gz);
00597 v = PosToFlatCartesian (pos, gx, gz);
00598
00599 float scale = TerrainScale (pos);
00600 v.x *= scale;
00601 v.y *= scale;
00602
00603 return v;
00604 }
00605
00606
00607
00608
00609
00610
00611
00612 #define QGT_FLAT_CARTESIAN_BOUND_FT (2.5633E+5)
00613
00614
00623 SVector PosToFlatCartesianQgt (SPosition pos, int x, int z)
00624 {
00625
00626 double s, n, w, e;
00627 qgt_lat_bounds (z, s, n);
00628 qgt_lon_bounds (x, w, e);
00629
00630
00631 double latScale = (360.0 / 256.0) / (2.0 * fabs(n - s));
00632
00633
00634 n *= 3600;
00635 s *= 3600;
00636 w *= 3600;
00637 e *= 3600;
00638
00639
00640 double midLon = w + ((e - w) / 2.0);
00641 double midLat;
00642 if (pos.lat >= 0) {
00643
00644 midLat = s + ((n - s) / 2.0);
00645 } else {
00646
00647 midLat = n + ((s - n) / 2.0);
00648 }
00649
00650
00651 double dLon = pos.lon - midLon;
00652 double dLat = pos.lat - midLat;
00653 dLat *= latScale;
00654
00655
00656 double easting = NmToFeet(dLon / 60.0);
00657 double northing = NmToFeet(dLat / 60.0);
00658
00659 SVector v;
00660 v.x = easting;
00661 v.y = northing;
00662 v.z = pos.alt;
00663
00664 return v;
00665 }
00666
00673 SVector PosToFlatCartesianQgt (SPosition pos)
00674 {
00675 int x, z;
00676 lat_lon_to_qgt (pos.lat, pos.lon, x, z);
00677 return PosToFlatCartesianQgt (pos, x, z);
00678 }
00679
00686 SVector PosToScaledFlatCartesianQgt (SPosition pos)
00687 {
00688 SVector v = PosToFlatCartesianQgt (pos);
00689
00690 float scale = TerrainScale (pos);
00691 v.x *= scale;
00692 v.y *= scale;
00693
00694 return v;
00695 }