Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

qtr.cpp

Go to the documentation of this file.
00001 /*
00002  * QTR.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00027 #include "../Include/FlyLegacy.h"
00028 #include "../Include/Globals.h"
00029 #include "../Include/QTR.h"
00030 #include "../Include/Utility.h"
00031 #include "../Include/Endian.h"
00032 
00033 
00034 CQTRFile::CQTRFile (void)
00035 {
00036   header.numNodes = 0;
00037   header.magic = 50;
00038   header.width = 0;
00039   header.height = 0;
00040   header.rasterBytes = 0;
00041   for (int i=0; i<4; i++) header.elev[i] = 0;
00042 }
00043 
00044 CQTRFile::CQTRFile (int index)
00045 {
00046   char qtrFilename[1024];
00047   sprintf (qtrFilename, "DATA\\%03X.QTR", index);
00048   Load (qtrFilename);
00049 }
00050 
00051 CQTRFile::CQTRFile (const char* qtrFilename)
00052 {
00053   Load (qtrFilename);
00054 }
00055 
00056 CQTRFile::~CQTRFile (void)
00057 {
00058   delete[] qtreenode;
00059   delete[] raster;
00060 }
00061 
00062 bool CQTRFile::Load (const char *qtrFilename)
00063 {
00064   int i;
00065   
00066   PODFILE *p = popen (&globals->pfs, qtrFilename);
00067   if (p == NULL) {
00068     fprintf (stderr, "Error opening QTR filename : %s\n", qtrFilename);
00069     return false;
00070   }
00071 
00072   // Read QTR header
00073   size_t nRead = pread (&header, SIZEOF_QTR_HEADER, 1, p);
00074   if (nRead != 1) {
00075     pclose (p);
00076     return false;
00077   }
00078 
00079   // QTR data is stored in little-Endian format
00080   header.numNodes = LittleEndian (header.numNodes);
00081   header.magic = LittleEndian (header.magic);
00082   header.width = LittleEndian (header.width);
00083   header.height = LittleEndian (header.height);
00084   header.rasterBytes = LittleEndian (header.rasterBytes);
00085   for (i=0; i<4; i++) header.elev[i] = LittleEndian (header.elev[i]);
00086 
00087   // Allocate storage for quadtree nodes and read them
00088   qtreenode = new SQTRNode[header.numNodes];
00089   nRead = pread (qtreenode, SIZEOF_QTR_NODE, header.numNodes, p);
00090   if (nRead != header.numNodes) {
00091     pclose (p);
00092     return false;
00093   }
00094 
00095   // QTR data is stored in little-Endian format
00096   for (i=0; i<header.numNodes; i++) {
00097     SQTRNode *node = &qtreenode[i];
00098 
00099     node->center = LittleEndian (node->center);
00100     switch (node->type) {
00101     case QTR_NODE_BRANCH:
00102       node->branchData.nwNode = LittleEndian (node->branchData.nwNode);
00103       node->branchData.neNode = LittleEndian (node->branchData.neNode);
00104       node->branchData.swNode = LittleEndian (node->branchData.swNode);
00105       node->branchData.seNode = LittleEndian (node->branchData.seNode);
00106       break;
00107 
00108     case QTR_NODE_LEAF:
00109       node->leafData.nwElevation = LittleEndian (node->leafData.nwElevation);
00110       node->leafData.neElevation = LittleEndian (node->leafData.neElevation);
00111       node->leafData.swElevation = LittleEndian (node->leafData.swElevation);
00112       node->leafData.seElevation = LittleEndian (node->leafData.seElevation);
00113       break;
00114 
00115     case QTR_NODE_RASTER_ABS:
00116     case QTR_NODE_RASTER_REL:
00117       node->rasterData.offset = LittleEndian (node->rasterData.offset);
00118       node->rasterData.dummy = LittleEndian (node->rasterData.dummy);
00119       break;
00120     }
00121   }
00122 
00123   // Allocate storage for raster data and read it
00124   raster = new char[header.rasterBytes];
00125   nRead = pread (raster, sizeof(char), header.rasterBytes, p);
00126   if (nRead != header.rasterBytes) {
00127     pclose (p);
00128     return false;
00129   }
00130 
00131   pclose (p);
00132   return true;
00133 }
00134 
00135 /*
00136  * CQTRFile loader for standard (non-POD filesystem) I/O
00137  *
00138 
00139 bool CQTRFile::Load (const char *qtrFilename)
00140 {
00141   FILE *fQTR = fopen (qtrFilename, "rb");
00142   if (fQTR == NULL) {
00143     fprintf (stderr, "Error opening QTR filename : %s\n", qtrFilename);
00144     return false;
00145   }
00146 
00147   // Read QTR header
00148   size_t nRead = fread (&header, sizeof(SQTRHeader), 1, fQTR);
00149   if (nRead != 1) {
00150     fclose (fQTR);
00151     return false;
00152   }
00153 
00154   // Allocate storage for quadtree nodes and read them
00155   qtreenode = new SQTRNode[header.numNodes];
00156   nRead = fread (qtreenode, sizeof(SQTRNode), header.numNodes, fQTR);
00157   if (nRead != header.numNodes) {
00158     fclose (fQTR);
00159     return false;
00160   }
00161 
00162   // Allocate storage for raster data and read it
00163   raster = new char[header.rasterBytes];
00164   nRead = fread (raster, sizeof(char), header.rasterBytes, fQTR);
00165   if (nRead != header.rasterBytes) {
00166     fclose (fQTR);
00167     return false;
00168   }
00169 
00170   fclose (fQTR);
00171   return true;
00172 }
00173 */
00174 
00175 bool CQTRFile::Save (const char *qtrFilename)
00176 {
00177   FILE *fQTR = fopen (qtrFilename, "wb");
00178   if (fQTR == NULL) {
00179     fprintf (stderr, "Error opening QTR filename : %s\n", qtrFilename);
00180     return false;
00181   }
00182 
00184   // Write QTR header
00185   size_t nWrite = fwrite (&header, sizeof(SQTRHeader), 1, fQTR);
00186   if (nWrite != 1) {
00187     fclose (fQTR);
00188     return false;
00189   }
00190 
00191   // Write quadtree nodes
00192   nWrite = fwrite (qtreenode, sizeof(SQTRNode), header.numNodes, fQTR);
00193   if (nWrite != header.numNodes) {
00194     fclose (fQTR);
00195     return false;
00196   }
00197 
00198   // Write raster data
00199   nWrite = fwrite (raster, sizeof(char), header.rasterBytes, fQTR);
00200   if (nWrite != header.rasterBytes) {
00201     fclose (fQTR);
00202     return false;
00203   }
00204 
00205   fclose (fQTR);
00206   return true;
00207 }
00208 
00209 unsigned short CQTRFile::NumQuadtreeNodes (void)
00210 {
00211   return header.numNodes;
00212 }
00213 
00214 SQTRNode *CQTRFile::GetQuadtreeNode (unsigned short i)
00215 {
00216   SQTRNode *rc = NULL;
00217   if (i < header.numNodes) {
00218     rc = &qtreenode[i];
00219   }
00220   return rc;
00221 }
00222 
00223 char* CQTRFile::GetRasterData (unsigned long offset)
00224 {
00225   char* rc = NULL;
00226   if (offset <= header.rasterBytes) {
00227     rc = &raster[offset];
00228   }
00229   return rc;
00230 }
00231 
00232 //
00233 // Extract a single value from an 8x8 relative raster data block.
00234 //
00235 float CQTRFile::ExtractRelativeData (char* data, int x, int z)
00236 {
00237   short *pBase = (short *)data;
00238   short base = *pBase;
00239   data += sizeof(short);
00240   unsigned char offset = data[(z * 8) + x];
00241   short metres = base + (offset * 16);
00242   return MetresToFeet ((float)metres);
00243 }
00244 
00245 //
00246 // Extract a single value from an 8x8 absolute raster data block.
00247 //
00248 float CQTRFile::ExtractAbsoluteData (short* data, int x, int z)
00249 {
00250   float metres = (float)(data[(z * 8) + x]);
00251   return MetresToFeet (metres);
00252 }
00253 
00254 //
00255 // Search the quadtree starting at the given node, at the given level
00256 //
00257 // Parameters:
00258 //   level    Depth to which to search, the root node is at level zero
00259 //   x        x (east/west) index
00260 //   z        z (north/south) index
00261 //
00262 // Return Value:
00263 //   float    Elevation value in feet MSL
00264 //
00265 float CQTRFile::Search (int level, unsigned short node, int x, int z)
00266 {
00267   float rc = 0.0f;
00268 
00269   SQTRNode *qtrnode = GetQuadtreeNode (node);
00270 
00271   if (level == 0) {
00272     // Desired search level has been reached
00273     rc = qtrnode->center;
00274   } else {
00275     // Determine quadrant
00276     //   NW = 00 = 0     NE = 01 = 1
00277     //   SW = 10 = 2     SE = 11 = 3
00278     int half = 1 << (level - 1);
00279     int qx = (x / half) % 2;
00280     int qz = (z / half) % 2;
00281     int quadrant = qx * 2 + qz;
00282     int xNew = x % half;
00283     int zNew = z % half;
00284 
00285     // Check node type
00286     switch (qtrnode->type) {
00287     case QTR_NODE_LEAF:
00288       // Return elevation from the proper quadrant
00289       switch (quadrant) {
00290       case 0:
00291         rc = qtrnode->leafData.nwElevation;
00292         break;
00293       case 1:
00294         rc = qtrnode->leafData.neElevation;
00295         break;
00296       case 2:
00297         rc = qtrnode->leafData.swElevation;
00298         break;
00299       case 3:
00300         rc = qtrnode->leafData.seElevation;
00301         break;
00302       default:
00303         gtfo ("CQTRFile::Search : Invalid quadrant");
00304       }
00305       break;
00306 
00307     case QTR_NODE_BRANCH:
00308       // Recursively traverse down one level
00309       switch (quadrant) {
00310       case 0:
00311         rc = Search (level-1, qtrnode->branchData.nwNode, xNew, zNew);
00312         break;
00313       case 1:
00314         rc = Search (level-1, qtrnode->branchData.swNode, xNew, zNew);
00315         break;
00316       case 2:
00317         rc = Search (level-1, qtrnode->branchData.neNode, xNew, zNew);
00318         break;
00319       case 3:
00320         rc = Search (level-1, qtrnode->branchData.seNode, xNew, zNew);
00321         break;
00322       default:
00323         gtfo ("CQTRFile::Search : Invalid quadrant");
00324       }
00325       break;
00326 
00327     case QTR_NODE_RASTER_REL:
00328       {
00329         // Extract elevation from relative raster data block
00330         if (level != 3) {
00331           gtfo ("CQTRFile : Attempt to traverse relative raster data block at level %d",
00332             level);
00333         }
00334         int rasterSize = 1 << level;
00335         int xr = x % rasterSize;
00336         int zr = z % rasterSize;
00337         rc = ExtractRelativeData (GetRasterData(qtrnode->rasterData.offset), xr, zr);
00338       }
00339       break;
00340 
00341     case QTR_NODE_RASTER_ABS:
00342       {
00343         // Extract elevation from absolute raster data block
00344         if (level != 3) {
00345           gtfo ("CQTRFile : Attempt to traverse absolute raster data block at level %d",
00346             level);
00347         }
00348         int rasterSize = 1 << level;
00349         int xr = x % rasterSize;
00350         int zr = z % rasterSize;
00351         rc = ExtractAbsoluteData ((short *)GetRasterData(qtrnode->rasterData.offset),
00352           xr, zr);
00353       }
00354       break;
00355     }
00356   }
00357 
00358   return rc;
00359 }
00360 
00361 //
00362 // Dump contents to a text file
00363 //
00364 void CQTRFile::Dump (const char* txtFilename)
00365 {
00366   FILE *fOut = fopen (txtFilename, "w");
00367 
00368   int nBranchNodes = 0;
00369   int nLeafNodes = 0;
00370   int nRelativeNodes = 0;
00371   int nAbsoluteNodes = 0;
00372 
00373   // Display QTR header
00374   fprintf (fOut, "QTR Header:\n\n");
00375   fprintf (fOut, "  numNodes   : %d\n", header.numNodes);
00376   fprintf (fOut, "  dimensions : %d x %d\n", header.width, header.height);
00377   fprintf (fOut, "  elevations : NW=%d NE=%d SW=%d SE=%d\n",
00378     header.elev[0], header.elev[1], header.elev[2], header.elev[3]);
00379   fprintf (fOut, "  rasterBytes: %d\n", header.rasterBytes);
00380   fprintf (fOut, "\n");
00381 
00382   // Display quadtree nodes
00383   for (unsigned short i=0; i<header.numNodes; i++) {
00384     // Get node data
00385     SQTRNode *node = &qtreenode[i];
00386 
00387     fprintf (fOut, "Node %05d: ", i);
00388     switch (node->type) {
00389     case QTR_NODE_BRANCH:
00390       {
00391         nBranchNodes++;
00392 
00393         fprintf (fOut, "BRANCH    center=%5d  NW=%05d NE=%05d SW=%05d SE=%05d\n",
00394           node->center,
00395           node->branchData.nwNode,
00396           node->branchData.neNode,
00397           node->branchData.swNode,
00398           node->branchData.seNode);
00399       }
00400       break;
00401     case QTR_NODE_LEAF:
00402       {
00403         nLeafNodes++;
00404 
00405         fprintf (fOut, "LEAF      center=%05d  NW=%05d NE=%05d SW=%05d SE=%05d\n",
00406           node->center,
00407           node->leafData.nwElevation,
00408           node->leafData.neElevation,
00409           node->leafData.swElevation,
00410           node->leafData.seElevation);
00411       }
00412       break;
00413     case QTR_NODE_RASTER_REL:
00414       {
00415         nRelativeNodes++;
00416 
00417         char *pData = GetRasterData (node->rasterData.offset);
00418         short base = *((short *)pData);
00419         pData += sizeof(short);
00420 
00421         fprintf (fOut, "RELATIVE  center=%5d offset=0x%08X dummy=0x%08X base=%5d\n",
00422           node->center,
00423           node->rasterData.offset,
00424           node->rasterData.dummy,
00425           base);
00426         for (int row=0; row<8; row++) {
00427           fprintf (fOut, "           ");
00428           for (int col=0; col<8; col++) {
00429             unsigned char c = pData[row * 8 + col];
00430             fprintf (fOut, "%5d  ", c);
00431           }
00432           fprintf (fOut, "\n");
00433         }
00434       }
00435       break;
00436     case QTR_NODE_RASTER_ABS:
00437       {
00438         nAbsoluteNodes++;
00439 
00440         short *pData = (short *)(GetRasterData (node->rasterData.offset));
00441 
00442         fprintf (fOut, "ABSOLUTE  center=%5d  offset=0x%08X, dummy=0x%08X\n",
00443           node->center,
00444           node->rasterData.offset,
00445           node->rasterData.dummy);
00446         for (int row=0; row<8; row++) {
00447           fprintf (fOut, "           ");
00448           for (int col=0; col<8; col++) {
00449             short s = pData[row * 8 + col];
00450             fprintf (fOut, "%5d  ", s);
00451           }
00452           fprintf (fOut, "\n");
00453         }
00454       }
00455       break;
00456     default:
00457       fprintf (fOut, "*** Unknown node type 0x%02X\n");
00458     }
00459   }
00460 
00461   // Summary statistics
00462   fprintf (fOut, "\n");
00463   fprintf (fOut, "nBranchNodes   = %d\n", nBranchNodes);
00464   fprintf (fOut, "nLeafNodes     = %d\n", nLeafNodes);
00465   fprintf (fOut, "nRelativeNodes = %d\n", nRelativeNodes);
00466   fprintf (fOut, "nAbsoluteNodes = %d\n", nAbsoluteNodes);
00467 
00468   fclose (fOut);
00469 }
00470 
00471 
SourceForge.net Logo Documentation generated by doxygen