LCOV - code coverage report
Current view: directory - frmts/leveller - levellerdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 465 159 34.2 %
Date: 2010-01-09 Functions: 55 18 32.7 %

       1                 : /******************************************************************************
       2                 :  * levellerdataset.cpp,v 1.22
       3                 :  *
       4                 :  * Project:  Leveller TER Driver
       5                 :  * Purpose:  Reader for Leveller TER documents
       6                 :  * Author:   Ray Gardener, Daylon Graphics Ltd.
       7                 :  *
       8                 :  * Portions of this module derived from GDAL drivers by 
       9                 :  * Frank Warmerdam, see http://www.gdal.org
      10                 :  *
      11                 :  ******************************************************************************
      12                 :  * Copyright (c) 2005-2007 Daylon Graphics Ltd.
      13                 :  *
      14                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      15                 :  * copy of this software and associated documentation files (the "Software"),
      16                 :  * to deal in the Software without restriction, including without limitation
      17                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18                 :  * and/or sell copies of the Software, and to permit persons to whom the
      19                 :  * Software is furnished to do so, subject to the following conditions:
      20                 :  *
      21                 :  * The above copyright notice and this permission notice shall be included
      22                 :  * in all copies or substantial portions of the Software.
      23                 :  *
      24                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      25                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      27                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      30                 :  * DEALINGS IN THE SOFTWARE.
      31                 :  ****************************************************************************/
      32                 : 
      33                 : 
      34                 : #include "gdal_pam.h"
      35                 : #include "ogr_spatialref.h"
      36                 : 
      37                 : CPL_CVSID("$Id: levellerdataset.cpp 16444 2009-03-01 19:46:43Z rouault $");
      38                 : 
      39                 : CPL_C_START
      40                 : void  GDALRegister_Leveller(void);
      41                 : CPL_C_END
      42                 : 
      43                 : #if 1
      44                 : 
      45                 : #define str_equal(_s1, _s2) (0 == strcmp((_s1),(_s2)))
      46                 : #define array_size(_a)    (sizeof(_a) / sizeof(_a[0]))
      47                 : 
      48                 : /*GDALDataset *LevellerCreateCopy( const char *, GDALDataset *, int, char **,
      49                 :                                 GDALProgressFunc pfnProgress, 
      50                 :                                 void * pProgressData );
      51                 : 
      52                 : */
      53                 : 
      54                 : /************************************************************************/
      55                 : /* ==================================================================== */
      56                 : /*        LevellerDataset       */
      57                 : /* ==================================================================== */
      58                 : /************************************************************************/
      59                 : 
      60                 : static const size_t kMaxTagNameLen = 63;
      61                 : 
      62                 : enum
      63                 : {
      64                 :   // Leveller coordsys types.
      65                 :   LEV_COORDSYS_RASTER = 0,
      66                 :   LEV_COORDSYS_LOCAL,
      67                 :   LEV_COORDSYS_GEO
      68                 : };
      69                 : 
      70                 : enum
      71                 : {
      72                 :   // Leveller digital axis extent styles.
      73                 :   LEV_DA_POSITIONED = 0,
      74                 :   LEV_DA_SIZED,
      75                 :   LEV_DA_PIXEL_SIZED
      76                 : };
      77                 : 
      78                 : typedef enum
      79                 : {
      80                 :   // Measurement unit IDs, OEM version.
      81                 :   UNITLABEL_UNKNOWN = 0x00000000,
      82                 :   UNITLABEL_PIXEL   = 0x70780000,
      83                 :   UNITLABEL_PERCENT = 0x25000000,
      84                 : 
      85                 :   UNITLABEL_RADIAN  = 0x72616400,
      86                 :   UNITLABEL_DEGREE  = 0x64656700,
      87                 :   UNITLABEL_ARCMINUTE = 0x6172636D,
      88                 :   UNITLABEL_ARCSECOND = 0x61726373,
      89                 : 
      90                 :   UNITLABEL_YM    = 0x796D0000,
      91                 :   UNITLABEL_ZM    = 0x7A6D0000,
      92                 :   UNITLABEL_AM    = 0x616D0000,
      93                 :   UNITLABEL_FM    = 0x666D0000,
      94                 :   UNITLABEL_PM    = 0x706D0000,
      95                 :   UNITLABEL_A     = 0x41000000,
      96                 :   UNITLABEL_NM    = 0x6E6D0000,
      97                 :   UNITLABEL_U     = 0x75000000,
      98                 :   UNITLABEL_UM    = 0x756D0000,
      99                 :   UNITLABEL_PPT   = 0x70707400,
     100                 :   UNITLABEL_PT    = 0x70740000,
     101                 :   UNITLABEL_MM    = 0x6D6D0000,
     102                 :   UNITLABEL_P     = 0x70000000,
     103                 :   UNITLABEL_CM    = 0x636D0000,
     104                 :   UNITLABEL_IN    = 0x696E0000,
     105                 :   UNITLABEL_DFT   = 0x64667400,
     106                 :   UNITLABEL_DM    = 0x646D0000,
     107                 :   UNITLABEL_LI    = 0x6C690000,
     108                 :   UNITLABEL_SLI   = 0x736C6900,
     109                 :   UNITLABEL_SP    = 0x73700000,
     110                 :   UNITLABEL_FT    = 0x66740000,
     111                 :   UNITLABEL_SFT   = 0x73667400,
     112                 :   UNITLABEL_YD    = 0x79640000,
     113                 :   UNITLABEL_SYD   = 0x73796400,
     114                 :   UNITLABEL_M     = 0x6D000000,
     115                 :   UNITLABEL_FATH    = 0x66617468,
     116                 :   UNITLABEL_R     = 0x72000000,
     117                 :   UNITLABEL_RD    = UNITLABEL_R,
     118                 :   UNITLABEL_DAM   = 0x64416D00,
     119                 :   UNITLABEL_DKM   = UNITLABEL_DAM,
     120                 :   UNITLABEL_CH    = 0x63680000,
     121                 :   UNITLABEL_SCH   = 0x73636800,
     122                 :   UNITLABEL_HM    = 0x686D0000,
     123                 :   UNITLABEL_F     = 0x66000000,
     124                 :   UNITLABEL_KM    = 0x6B6D0000,
     125                 :   UNITLABEL_MI    = 0x6D690000,
     126                 :   UNITLABEL_SMI   = 0x736D6900,
     127                 :   UNITLABEL_NMI   = 0x6E6D6900,
     128                 :   UNITLABEL_MEGAM   = 0x4D6D0000,
     129                 :   UNITLABEL_LS    = 0x6C730000,
     130                 :   UNITLABEL_GM    = 0x476D0000,
     131                 :   UNITLABEL_LM    = 0x6C6D0000,
     132                 :   UNITLABEL_AU    = 0x41550000,
     133                 :   UNITLABEL_TM    = 0x546D0000,
     134                 :   UNITLABEL_LHR   = 0x6C687200,
     135                 :   UNITLABEL_LD    = 0x6C640000,
     136                 :   UNITLABEL_PETAM   = 0x506D0000,
     137                 :   UNITLABEL_LY    = 0x6C790000,
     138                 :   UNITLABEL_PC    = 0x70630000,
     139                 :   UNITLABEL_EXAM    = 0x456D0000,
     140                 :   UNITLABEL_KLY   = 0x6B6C7900,
     141                 :   UNITLABEL_KPC   = 0x6B706300,
     142                 :   UNITLABEL_ZETTAM  = 0x5A6D0000,
     143                 :   UNITLABEL_MLY   = 0x4D6C7900,
     144                 :   UNITLABEL_MPC   = 0x4D706300,
     145                 :   UNITLABEL_YOTTAM  = 0x596D0000
     146                 : } UNITLABEL;
     147                 : 
     148                 : 
     149                 : typedef struct
     150                 : {
     151                 :   const char* pszID;
     152                 :   double    dScale;
     153                 :   UNITLABEL oemCode;
     154                 : } measurement_unit;
     155                 : 
     156                 : static const double kdays_per_year = 365.25;
     157                 : static const double kdLStoM = 299792458.0;
     158                 : static const double kdLYtoM = kdLStoM * kdays_per_year * 24 * 60 * 60;
     159                 : static const double kdInch = 0.3048 / 12;
     160                 : static const double kPI = 3.1415926535897932384626433832795;
     161                 : 
     162                 : static const int kFirstLinearMeasureIdx = 9;
     163                 : 
     164                 : static const measurement_unit kUnits[] =
     165                 : {
     166                 :   { "", 1.0, UNITLABEL_UNKNOWN },
     167                 :   { "px", 1.0, UNITLABEL_PIXEL },
     168                 :   { "%", 1.0, UNITLABEL_PERCENT }, // not actually used
     169                 : 
     170                 :   { "rad", 1.0, UNITLABEL_RADIAN },
     171                 :   { "°", kPI / 180.0, UNITLABEL_DEGREE },
     172                 :   { "d", kPI / 180.0, UNITLABEL_DEGREE },
     173                 :   { "deg", kPI / 180.0, UNITLABEL_DEGREE },
     174                 :   { "'", kPI / (60.0 * 180.0), UNITLABEL_ARCMINUTE },
     175                 :   { "\"", kPI / (3600.0 * 180.0), UNITLABEL_ARCSECOND },
     176                 : 
     177                 :   { "ym", 1.0e-24, UNITLABEL_YM },
     178                 :   { "zm", 1.0e-21, UNITLABEL_ZM }, 
     179                 :   { "am", 1.0e-18, UNITLABEL_AM },
     180                 :   { "fm", 1.0e-15, UNITLABEL_FM }, 
     181                 :   { "pm", 1.0e-12, UNITLABEL_PM }, 
     182                 :   { "A",  1.0e-10, UNITLABEL_A }, 
     183                 :   { "nm", 1.0e-9, UNITLABEL_NM }, 
     184                 :   { "u",  1.0e-6, UNITLABEL_U }, 
     185                 :   { "um", 1.0e-6, UNITLABEL_UM }, 
     186                 :   { "ppt", kdInch / 72.27, UNITLABEL_PPT }, 
     187                 :   { "pt", kdInch / 72.0, UNITLABEL_PT }, 
     188                 :     { "mm", 1.0e-3, UNITLABEL_MM }, 
     189                 :   { "p", kdInch / 6.0, UNITLABEL_P }, 
     190                 :   { "cm", 1.0e-2, UNITLABEL_CM }, 
     191                 :   { "in", kdInch, UNITLABEL_IN }, 
     192                 :   { "dft", 0.03048, UNITLABEL_DFT }, 
     193                 :   { "dm", 0.1, UNITLABEL_DM }, 
     194                 :   { "li", 0.2011684 /* GDAL 0.20116684023368047 ? */, UNITLABEL_LI },  
     195                 :   { "sli", 0.201168402336805, UNITLABEL_SLI }, 
     196                 :   { "sp", 0.2286, UNITLABEL_SP }, 
     197                 :   { "ft", 0.3048, UNITLABEL_FT }, 
     198                 :   { "sft", 1200.0 / 3937.0, UNITLABEL_SFT }, 
     199                 :     { "yd", 0.9144, UNITLABEL_YD }, 
     200                 :   { "syd", 0.914401828803658, UNITLABEL_SYD }, 
     201                 :   { "m", 1.0, UNITLABEL_M }, 
     202                 :   { "fath", 1.8288, UNITLABEL_FATH }, 
     203                 :   { "rd", 5.02921, UNITLABEL_RD }, 
     204                 :   { "dam", 10.0, UNITLABEL_DAM }, 
     205                 :   { "dkm", 10.0, UNITLABEL_DKM }, 
     206                 :   { "ch", 20.1168 /* GDAL: 2.0116684023368047 ? */, UNITLABEL_CH },  
     207                 :   { "sch", 20.1168402336805, UNITLABEL_SCH }, 
     208                 :   { "hm", 100.0, UNITLABEL_HM },
     209                 :   { "f", 201.168, UNITLABEL_F }, 
     210                 :   { "km", 1000.0, UNITLABEL_KM }, 
     211                 :   { "mi", 1609.344, UNITLABEL_MI }, 
     212                 :   { "smi", 1609.34721869444, UNITLABEL_SMI }, 
     213                 :   { "nmi", 1853.0, UNITLABEL_NMI }, 
     214                 :   { "Mm", 1.0e+6, UNITLABEL_MEGAM }, 
     215                 :     { "ls", kdLStoM, UNITLABEL_LS }, 
     216                 :   { "Gm", 1.0e+9, UNITLABEL_GM }, 
     217                 :   { "lm", kdLStoM * 60, UNITLABEL_LM }, 
     218                 :   { "AU", 8.317 * kdLStoM * 60, UNITLABEL_AU }, 
     219                 :   { "Tm", 1.0e+12, UNITLABEL_TM }, 
     220                 :   { "lhr", 60.0 * 60.0 * kdLStoM, UNITLABEL_LHR }, 
     221                 :   { "ld", 24 * 60.0 * 60.0 * kdLStoM, UNITLABEL_LD },  
     222                 :   { "Pm", 1.0e+15, UNITLABEL_PETAM }, 
     223                 :   { "ly", kdLYtoM, UNITLABEL_LY }, 
     224                 :   { "pc", 3.2616 * kdLYtoM, UNITLABEL_PC }, 
     225                 :   { "Em", 1.0e+18, UNITLABEL_EXAM }, 
     226                 :   { "kly", 1.0e+3 * kdLYtoM, UNITLABEL_KLY }, 
     227                 :   { "kpc", 3.2616 * 1.0e+3 * kdLYtoM, UNITLABEL_KPC }, 
     228                 :   { "Zm", 1.0e+21, UNITLABEL_ZETTAM }, 
     229                 :   { "Mly", 1.0e+6 * kdLYtoM, UNITLABEL_MLY }, 
     230                 :   { "Mpc", 3.2616 * 1.0e+6 * kdLYtoM, UNITLABEL_MPC }, 
     231                 :   { "Ym", 1.0e+24, UNITLABEL_YOTTAM }
     232                 : };
     233                 : 
     234                 : // ----------------------------------------------------------------
     235                 : 
     236               0 : static bool approx_equal(double a, double b)
     237                 : {
     238               0 :   const double epsilon = 1e-5;
     239               0 :   return (fabs(a-b) <= epsilon);
     240                 : }
     241                 : 
     242                 : 
     243                 : // ----------------------------------------------------------------
     244                 : 
     245                 : class LevellerRasterBand;
     246                 : 
     247                 : class LevellerDataset : public GDALPamDataset
     248                 : {
     249                 :     friend class LevellerRasterBand;
     250                 :   friend class digital_axis;
     251                 : 
     252                 :     int     m_version;
     253                 : 
     254                 :   char*   m_pszFilename;
     255                 :     char*   m_pszProjection;
     256                 : 
     257                 :     char    m_szUnits[8];
     258                 :   char    m_szElevUnits[8];
     259                 :     double    m_dElevScale; // physical-to-logical scaling.
     260                 :     double    m_dElevBase;  // logical offset.
     261                 :     double    m_adfTransform[6];
     262                 :   //double    m_dMeasurePerPixel;
     263                 :   double    m_dLogSpan[2];
     264                 : 
     265                 :     FILE*     m_fp;
     266                 :     vsi_l_offset  m_nDataOffset;
     267                 : 
     268                 :     bool load_from_file(FILE*, const char*);
     269                 : 
     270                 : 
     271                 :     bool locate_data(vsi_l_offset&, size_t&, FILE*, const char*);
     272                 :     bool get(int&, FILE*, const char*);
     273               0 :     bool get(size_t& n, FILE* fp, const char* psz)
     274               0 :     { return this->get((int&)n, fp, psz); }
     275                 :     bool get(double&, FILE*, const char*);
     276                 :     bool get(char*, size_t, FILE*, const char*);
     277                 : 
     278                 :   bool write_header();
     279                 :   bool write_tag(const char*, int);
     280                 :   bool write_tag(const char*, size_t);
     281                 :   bool write_tag(const char*, double);
     282                 :   bool write_tag(const char*, const char*);
     283                 :   bool write_tag_start(const char*, size_t);
     284                 :   bool write(int);
     285                 :   bool write(size_t);
     286                 :   bool write(double);
     287                 :   bool write_byte(size_t);
     288                 : 
     289                 :   const measurement_unit* get_uom(const char*) const;
     290                 :   const measurement_unit* get_uom(UNITLABEL) const;
     291                 :   const measurement_unit* get_uom(double) const;
     292                 : 
     293                 :     bool convert_measure(double, double&, const char* pszUnitsFrom);
     294                 :   bool make_local_coordsys(const char* pszName, const char* pszUnits);
     295                 :   bool make_local_coordsys(const char* pszName, UNITLABEL);
     296                 :   const char* code_to_id(UNITLABEL) const;
     297                 :   UNITLABEL id_to_code(const char*) const;
     298                 :   UNITLABEL meter_measure_to_code(double) const;
     299                 :   bool compute_elev_scaling(const OGRSpatialReference&);
     300                 :   void raw_to_proj(double, double, double&, double&);
     301                 : 
     302                 : public:
     303                 :     LevellerDataset();
     304                 :     ~LevellerDataset();
     305                 :     
     306                 :     static GDALDataset* Open( GDALOpenInfo* );
     307                 :   static int Identify( GDALOpenInfo* );
     308                 :     static GDALDataset* Create( const char* pszFilename,
     309                 :                                 int nXSize, int nYSize, int nBands,
     310                 :                                 GDALDataType eType, char** papszOptions );
     311                 : 
     312                 :     virtual CPLErr  GetGeoTransform( double* );
     313                 :     virtual const char* GetProjectionRef(void);
     314                 : 
     315                 :     virtual CPLErr  SetGeoTransform( double* );
     316                 :     virtual CPLErr  SetProjection(const char*);
     317                 : };
     318                 : 
     319                 : 
     320                 : class digital_axis
     321                 : {
     322                 :   public:
     323               0 :     digital_axis() : m_eStyle(LEV_DA_PIXEL_SIZED) {}
     324                 : 
     325               0 :     bool get(LevellerDataset& ds, FILE* fp, int n)
     326                 :     {
     327                 :       char szTag[32];
     328               0 :       sprintf(szTag, "coordsys_da%d_style", n);
     329               0 :       if(!ds.get(m_eStyle, fp, szTag))
     330               0 :         return false;
     331               0 :       sprintf(szTag, "coordsys_da%d_fixedend", n);
     332               0 :       if(!ds.get(m_fixedEnd, fp, szTag))
     333               0 :         return false;
     334               0 :       sprintf(szTag, "coordsys_da%d_v0", n);
     335               0 :       if(!ds.get(m_d[0], fp, szTag))
     336               0 :         return false;
     337               0 :       sprintf(szTag, "coordsys_da%d_v1", n);
     338               0 :       if(!ds.get(m_d[1], fp, szTag))
     339               0 :         return false;
     340               0 :       return true;
     341                 :     }
     342                 : 
     343               0 :     double origin(size_t pixels) const
     344                 :     {
     345               0 :       if(m_fixedEnd == 1)
     346                 :       {
     347               0 :         switch(m_eStyle)
     348                 :         {
     349                 :           case LEV_DA_SIZED:
     350               0 :             return m_d[1] + m_d[0];
     351                 : 
     352                 :           case LEV_DA_PIXEL_SIZED:
     353               0 :             return m_d[1] + (m_d[0] * (pixels-1));
     354                 :         }         
     355                 :       }
     356               0 :       return m_d[0];
     357                 :     }
     358                 : 
     359               0 :     double scaling(size_t pixels) const
     360                 :     {
     361                 :       CPLAssert(pixels > 1);
     362               0 :       if(m_eStyle == LEV_DA_PIXEL_SIZED)
     363               0 :         return m_d[1 - m_fixedEnd];
     364                 : 
     365               0 :       return this->length(pixels) / (pixels - 1);
     366                 :     }
     367                 : 
     368               0 :     double length(int pixels) const
     369                 :     {
     370                 :       // Return the signed length of the axis.
     371                 : 
     372               0 :       switch(m_eStyle)
     373                 :       {
     374                 :         case LEV_DA_POSITIONED:
     375               0 :           return m_d[1] - m_d[0];
     376                 : 
     377                 :         case LEV_DA_SIZED:
     378               0 :           return m_d[1 - m_fixedEnd];
     379                 : 
     380                 :         case LEV_DA_PIXEL_SIZED:
     381               0 :           return m_d[1 - m_fixedEnd] * (pixels-1);
     382                 :           
     383                 :       }
     384                 :       CPLAssert(FALSE);
     385               0 :       return 0.0;
     386                 :     }
     387                 : 
     388                 : 
     389                 :   protected:
     390                 :     int   m_eStyle;
     391                 :     size_t  m_fixedEnd;
     392                 :     double  m_d[2];
     393                 : };
     394                 : 
     395                 : 
     396                 : /************************************************************************/
     397                 : /* ==================================================================== */
     398                 : /*                            LevellerRasterBand                        */
     399                 : /* ==================================================================== */
     400                 : /************************************************************************/
     401                 : 
     402                 : class LevellerRasterBand : public GDALPamRasterBand
     403                 : {
     404                 :     friend class LevellerDataset;
     405                 : 
     406                 :   float*  m_pLine;
     407                 :   bool  m_bFirstTime;
     408                 : 
     409                 : public:
     410                 : 
     411                 :     LevellerRasterBand(LevellerDataset*);
     412                 :     ~LevellerRasterBand();
     413                 :     
     414                 :     // Geomeasure support.
     415                 :     virtual const char* GetUnitType();
     416                 :     virtual double GetScale(int* pbSuccess = NULL);
     417                 :     virtual double GetOffset(int* pbSuccess = NULL);
     418                 : 
     419                 :     virtual CPLErr IReadBlock( int, int, void * );
     420                 :     virtual CPLErr IWriteBlock( int, int, void * );
     421                 :   virtual CPLErr SetUnitType( const char* );
     422                 : };
     423                 : 
     424                 : 
     425                 : /************************************************************************/
     426                 : /*                         LevellerRasterBand()                         */
     427                 : /************************************************************************/
     428                 : 
     429               1 : LevellerRasterBand::LevellerRasterBand( LevellerDataset *poDS )
     430                 :   :
     431                 :   m_pLine(NULL),
     432               1 :   m_bFirstTime(true)
     433                 : {
     434               1 :     this->poDS = poDS;
     435               1 :     this->nBand = 1;
     436                 : 
     437               1 :     eDataType = GDT_Float32;
     438                 : 
     439               1 :     nBlockXSize = poDS->GetRasterXSize();
     440               1 :     nBlockYSize = 1;//poDS->GetRasterYSize();
     441                 : 
     442               1 :   m_pLine = (float*)CPLMalloc(sizeof(float) * nBlockXSize);
     443               1 : }
     444                 : 
     445                 : 
     446               2 : LevellerRasterBand::~LevellerRasterBand()
     447                 : {
     448               1 :   if(m_pLine != NULL)
     449               1 :     CPLFree(m_pLine);
     450               2 : }
     451                 : 
     452                 : /************************************************************************/
     453                 : /*                             IWriteBlock()                            */
     454                 : /************************************************************************/
     455                 : 
     456               0 : CPLErr LevellerRasterBand::IWriteBlock
     457                 : ( 
     458                 :   int nBlockXOff, 
     459                 :   int nBlockYOff,
     460                 :     void* pImage
     461                 : )
     462                 : {
     463                 :     CPLAssert( nBlockXOff == 0  );
     464                 :     CPLAssert( pImage != NULL );
     465                 :   CPLAssert( m_pLine != NULL );
     466                 : 
     467                 : /*  #define sgn(_n) ((_n) < 0 ? -1 : ((_n) > 0 ? 1 : 0) )
     468                 :   #define sround(_f)  \
     469                 :     (int)((_f) + (0.5 * sgn(_f)))
     470                 : */
     471               0 :   const size_t pixelsize = sizeof(float);
     472                 : 
     473               0 :   LevellerDataset& ds = *(LevellerDataset*)poDS;
     474               0 :   if(m_bFirstTime)
     475                 :   {
     476               0 :     m_bFirstTime = false;
     477               0 :     if(!ds.write_header())
     478               0 :       return CE_Failure;
     479               0 :     ds.m_nDataOffset = VSIFTellL(ds.m_fp);
     480                 :   }
     481               0 :   const size_t rowbytes = nBlockXSize * pixelsize;
     482               0 :   const float* pfImage = (float*)pImage;
     483                 : 
     484               0 :   if(0 == VSIFSeekL(
     485                 :        ds.m_fp, ds.m_nDataOffset + nBlockYOff * rowbytes, 
     486                 :        SEEK_SET))
     487                 :   {
     488               0 :     for(size_t x = 0; x < (size_t)nBlockXSize; x++)
     489                 :     {
     490                 :       // Convert logical elevations to physical.
     491               0 :       m_pLine[x] = 
     492               0 :         (pfImage[x] - ds.m_dElevBase) / ds.m_dElevScale;
     493                 :     }
     494                 : 
     495                 : #ifdef CPL_MSB 
     496                 :     GDALSwapWords( m_pLine, pixelsize, nBlockXSize, pixelsize );
     497                 : #endif    
     498               0 :     if(1 == VSIFWriteL(m_pLine, rowbytes, 1, ds.m_fp))
     499               0 :       return CE_None;
     500                 :   }
     501                 : 
     502               0 :   return CE_Failure;
     503                 : }
     504                 : 
     505                 : 
     506               0 : CPLErr LevellerRasterBand::SetUnitType( const char* psz )
     507                 : {
     508               0 :   LevellerDataset& ds = *(LevellerDataset*)poDS;
     509                 : 
     510               0 :   if(strlen(psz) >= sizeof(ds.m_szElevUnits))
     511               0 :     return CE_Failure;
     512                 : 
     513               0 :   strcpy(ds.m_szElevUnits, psz);
     514                 : 
     515               0 :   return CE_None;
     516                 : }
     517                 : 
     518                 : 
     519                 : /************************************************************************/
     520                 : /*                             IReadBlock()                             */
     521                 : /************************************************************************/
     522                 : 
     523              96 : CPLErr LevellerRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     524                 :                                        void* pImage )
     525                 : 
     526                 : {
     527                 :     CPLAssert( sizeof(float) == sizeof(GInt32) );
     528                 :     CPLAssert( nBlockXOff == 0  );
     529                 :     CPLAssert( pImage != NULL );
     530                 : 
     531              96 :     LevellerDataset *poGDS = (LevellerDataset *) poDS;
     532                 : 
     533                 : /* -------------------------------------------------------------------- */
     534                 : /*      Seek to scanline.                                               */
     535                 : /* -------------------------------------------------------------------- */
     536              96 :     const size_t rowbytes = nBlockXSize * sizeof(float);
     537                 : 
     538              96 :     if(0 != VSIFSeekL(
     539                 :            poGDS->m_fp, 
     540                 :            poGDS->m_nDataOffset + nBlockYOff * rowbytes, 
     541                 :            SEEK_SET))
     542                 :     {
     543                 :         CPLError( CE_Failure, CPLE_FileIO, 
     544               0 :                   ".bt Seek failed:%s", VSIStrerror( errno ) );
     545               0 :         return CE_Failure;
     546                 :     }
     547                 : 
     548                 : 
     549                 : /* -------------------------------------------------------------------- */
     550                 : /*      Read the scanline into the image buffer.                        */
     551                 : /* -------------------------------------------------------------------- */
     552                 : 
     553              96 :     if( VSIFReadL( pImage, rowbytes, 1, poGDS->m_fp ) != 1 )
     554                 :     {
     555                 :         CPLError( CE_Failure, CPLE_FileIO, 
     556               0 :                   "Leveller read failed:%s", VSIStrerror( errno ) );
     557               0 :         return CE_Failure;
     558                 :     }
     559                 : 
     560                 : /* -------------------------------------------------------------------- */
     561                 : /*      Swap on MSB platforms.                                          */
     562                 : /* -------------------------------------------------------------------- */
     563                 : #ifdef CPL_MSB 
     564                 :     GDALSwapWords( pImage, 4, nRasterXSize, 4 );
     565                 : #endif    
     566                 : 
     567                 : /* -------------------------------------------------------------------- */
     568                 : /*      Convert from legacy-format fixed-point if necessary.            */
     569                 : /* -------------------------------------------------------------------- */
     570              96 :     float* pf = (float*)pImage;
     571                 :   
     572              96 :     if(poGDS->m_version < 6)
     573                 :     {
     574               0 :         GInt32* pi = (int*)pImage;
     575               0 :         for(size_t i = 0; i < (size_t)nBlockXSize; i++)
     576               0 :             pf[i] = (float)pi[i] / 65536;
     577                 :     }
     578                 : 
     579                 : 
     580                 : #if 0
     581                 : /* -------------------------------------------------------------------- */
     582                 : /*      Convert raw elevations to realworld elevs.                      */
     583                 : /* -------------------------------------------------------------------- */
     584                 :     for(size_t i = 0; i < nBlockXSize; i++)
     585                 :         pf[i] *= poGDS->m_dWorldscale; //this->GetScale();
     586                 : #endif
     587                 : 
     588              96 :     return CE_None;
     589                 : }
     590                 : 
     591                 : 
     592                 : 
     593                 : /************************************************************************/
     594                 : /*                            GetUnitType()                             */
     595                 : /************************************************************************/
     596               0 : const char *LevellerRasterBand::GetUnitType()
     597                 : {
     598                 :   // Return elevation units.
     599                 : 
     600               0 :   LevellerDataset *poGDS = (LevellerDataset *) poDS;
     601                 : 
     602               0 :     return poGDS->m_szElevUnits;
     603                 : }
     604                 : 
     605                 : 
     606                 : /************************************************************************/
     607                 : /*                              GetScale()                              */
     608                 : /************************************************************************/
     609                 : 
     610               0 : double LevellerRasterBand::GetScale(int* pbSuccess)
     611                 : {
     612               0 :     LevellerDataset *poGDS = (LevellerDataset *) poDS;
     613               0 :   if(pbSuccess != NULL)
     614               0 :     *pbSuccess = TRUE;
     615               0 :   return poGDS->m_dElevScale;
     616                 : }
     617                 : 
     618                 : /************************************************************************/
     619                 : /*                             GetOffset()                              */
     620                 : /************************************************************************/
     621                 : 
     622               0 : double LevellerRasterBand::GetOffset(int* pbSuccess)
     623                 : {
     624               0 :     LevellerDataset *poGDS = (LevellerDataset *) poDS;
     625               0 :   if(pbSuccess != NULL)
     626               0 :     *pbSuccess = TRUE;
     627               0 :   return poGDS->m_dElevBase;
     628                 : }
     629                 : 
     630                 : 
     631                 : /************************************************************************/
     632                 : /* ==================================================================== */
     633                 : /*        LevellerDataset                   */
     634                 : /* ==================================================================== */
     635                 : /************************************************************************/
     636                 : 
     637                 : /************************************************************************/
     638                 : /*                          LevellerDataset()                           */
     639                 : /************************************************************************/
     640                 : 
     641               3 : LevellerDataset::LevellerDataset()
     642                 : {
     643               3 :     m_fp = NULL;
     644               3 :     m_pszProjection = NULL;
     645               3 :     m_pszFilename = NULL;
     646               3 : }
     647                 : 
     648                 : /************************************************************************/
     649                 : /*                          ~LevellerDataset()                          */
     650                 : /************************************************************************/
     651                 : 
     652               6 : LevellerDataset::~LevellerDataset()
     653                 : {
     654               3 :     FlushCache();
     655                 : 
     656               3 :     CPLFree(m_pszProjection);
     657               3 :     CPLFree(m_pszFilename);
     658                 : 
     659               3 :     if( m_fp != NULL )
     660               3 :         VSIFCloseL( m_fp );
     661               6 : }
     662                 : 
     663               0 : static double degrees_to_radians(double d) 
     664                 : {
     665               0 :   return (d * 0.017453292);
     666                 : }
     667                 : 
     668                 : 
     669               0 : static double average(double a, double b)
     670                 : {
     671               0 :   return 0.5 * (a + b);
     672                 : }
     673                 : 
     674                 : 
     675               0 : void LevellerDataset::raw_to_proj(double x, double y, double& xp, double& yp)
     676                 : {
     677               0 :   xp = x * m_adfTransform[1] + m_adfTransform[0];
     678               0 :   yp = y * m_adfTransform[5] + m_adfTransform[3];
     679               0 : }
     680                 : 
     681                 : 
     682               0 : bool LevellerDataset::compute_elev_scaling
     683                 : (
     684                 :   const OGRSpatialReference& sr
     685                 : )
     686                 : {
     687                 :   const char* pszGroundUnits;
     688                 : 
     689               0 :   if(!sr.IsGeographic())
     690                 :   {
     691                 :     // For projected or local CS, the elev scale is
     692                 :     // the average ground scale.
     693               0 :     m_dElevScale = average(m_adfTransform[1], m_adfTransform[5]);
     694                 : 
     695               0 :     const double dfLinear = sr.GetLinearUnits();
     696               0 :     const measurement_unit* pu = this->get_uom(dfLinear);
     697               0 :     if(pu == NULL)
     698               0 :       return false;
     699                 : 
     700               0 :     pszGroundUnits = pu->pszID;
     701                 :   }
     702                 :   else
     703                 :   {
     704               0 :     pszGroundUnits = "m";
     705                 : 
     706               0 :     const double kdEarthCircumPolar = 40007849;
     707               0 :     const double kdEarthCircumEquat = 40075004;
     708                 : 
     709                 :     double xr, yr;
     710               0 :     xr = 0.5 * this->nRasterXSize;
     711               0 :     yr = 0.5 * this->nRasterYSize;
     712                 : 
     713                 :     double xg[2], yg[2];
     714               0 :     this->raw_to_proj(xr, yr, xg[0], yg[0]);
     715               0 :     this->raw_to_proj(xr+1, yr+1, xg[1], yg[1]);
     716                 :     
     717                 :     // The earths' circumference shrinks using a sin()
     718                 :     // curve as we go up in latitude.
     719                 :     const double dLatCircum = kdEarthCircumEquat 
     720               0 :       * sin(degrees_to_radians(90.0 - yg[0]));
     721                 : 
     722                 :     // Derive meter distance between geolongitudes
     723                 :     // in xg[0] and xg[1].
     724               0 :     double dx = fabs(xg[1] - xg[0]) / 360.0 * dLatCircum;
     725               0 :     double dy = fabs(yg[1] - yg[0]) / 360.0 * kdEarthCircumPolar;
     726                 : 
     727               0 :     m_dElevScale = average(dx, dy);
     728                 :   }
     729                 : 
     730               0 :   m_dElevBase = m_dLogSpan[0];
     731                 : 
     732                 :   // Convert from ground units to elev units.
     733               0 :   const measurement_unit* puG = this->get_uom(pszGroundUnits);
     734               0 :   const measurement_unit* puE = this->get_uom(m_szElevUnits);
     735                 : 
     736               0 :   if(puG == NULL || puE == NULL)
     737               0 :     return false;
     738                 : 
     739               0 :   const double g_to_e = puG->dScale / puE->dScale;
     740                 : 
     741               0 :   m_dElevScale *= g_to_e;
     742               0 :   return true;
     743                 : }
     744                 : 
     745                 : 
     746               0 : bool LevellerDataset::write_header()
     747                 : {
     748                 :   char szHeader[5];
     749               0 :   strcpy(szHeader, "trrn");
     750               0 :   szHeader[4] = 7; // TER v7 introduced w/ Lev 2.6.
     751                 : 
     752               0 :   if(1 != VSIFWriteL(szHeader, 5, 1, m_fp)
     753                 :     || !this->write_tag("hf_w", (size_t)nRasterXSize)
     754                 :     || !this->write_tag("hf_b", (size_t)nRasterYSize))
     755                 :   {
     756               0 :         CPLError( CE_Failure, CPLE_FileIO, "Could not write header" );
     757               0 :         return false;
     758                 :   }
     759                 : 
     760               0 :   m_dElevBase = 0.0;
     761               0 :   m_dElevScale = 1.0;
     762                 : 
     763               0 :   if(m_pszProjection == NULL || m_pszProjection[0] == 0)
     764                 :   {
     765               0 :     this->write_tag("csclass", LEV_COORDSYS_RASTER);
     766                 :   }
     767                 :   else
     768                 :   {
     769               0 :     this->write_tag("coordsys_wkt", m_pszProjection);
     770               0 :     const UNITLABEL units_elev = this->id_to_code(m_szElevUnits);
     771                 :     
     772                 :     const int bHasECS = 
     773               0 :       (units_elev != UNITLABEL_PIXEL && units_elev != UNITLABEL_UNKNOWN);
     774                 : 
     775               0 :     this->write_tag("coordsys_haselevm", bHasECS);
     776                 : 
     777               0 :       OGRSpatialReference sr(m_pszProjection);
     778                 : 
     779               0 :     if(bHasECS)
     780                 :     {
     781               0 :       if(!this->compute_elev_scaling(sr))
     782               0 :         return false;
     783                 : 
     784                 :       // Raw-to-real units scaling.
     785               0 :       this->write_tag("coordsys_em_scale", m_dElevScale);
     786                 : 
     787                 :       //elev offset, in real units.
     788               0 :       this->write_tag("coordsys_em_base", m_dElevBase);
     789                 :         
     790               0 :       this->write_tag("coordsys_em_units", units_elev);
     791                 :     }
     792                 : 
     793                 : 
     794               0 :     if(sr.IsLocal())
     795                 :     {
     796               0 :       this->write_tag("csclass", LEV_COORDSYS_LOCAL);
     797                 : 
     798               0 :       const double dfLinear = sr.GetLinearUnits();
     799               0 :       const int n = this->meter_measure_to_code(dfLinear);
     800               0 :       this->write_tag("coordsys_units", n);
     801                 :     }
     802                 :     else
     803                 :     {
     804               0 :       this->write_tag("csclass", LEV_COORDSYS_GEO);
     805                 :     }
     806                 : 
     807               0 :     if( m_adfTransform[2] != 0.0 || m_adfTransform[4] != 0.0)
     808                 :     {
     809                 :       CPLError( CE_Failure, CPLE_IllegalArg, 
     810               0 :         "Cannot handle rotated geotransform" );
     811               0 :       return false;
     812                 :     }
     813                 : 
     814                 :     // todo: GDAL gridpost spacing is based on extent / rastersize
     815                 :     // instead of extent / (rastersize-1) like Leveller.
     816                 :     // We need to look into this and adjust accordingly.
     817                 : 
     818                 :     // Write north-south digital axis.
     819               0 :     this->write_tag("coordsys_da0_style", LEV_DA_PIXEL_SIZED);
     820               0 :     this->write_tag("coordsys_da0_fixedend", 0);
     821               0 :     this->write_tag("coordsys_da0_v0", m_adfTransform[3]);
     822               0 :     this->write_tag("coordsys_da0_v1", m_adfTransform[5]);
     823                 : 
     824                 :     // Write east-west digital axis.
     825               0 :     this->write_tag("coordsys_da1_style", LEV_DA_PIXEL_SIZED);
     826               0 :     this->write_tag("coordsys_da1_fixedend", 0);
     827               0 :     this->write_tag("coordsys_da1_v0", m_adfTransform[0]);
     828               0 :     this->write_tag("coordsys_da1_v1", m_adfTransform[1]);
     829                 :   }
     830                 : 
     831                 : 
     832                 :   this->write_tag_start("hf_data", 
     833               0 :     sizeof(float) * nRasterXSize * nRasterYSize);
     834                 : 
     835               0 :   return true;
     836                 : }
     837                 : 
     838                 : 
     839                 : /************************************************************************/
     840                 : /*                          SetGeoTransform()                           */
     841                 : /************************************************************************/
     842                 : 
     843               0 : CPLErr LevellerDataset::SetGeoTransform( double *padfGeoTransform )
     844                 : {
     845                 :   memcpy(m_adfTransform, padfGeoTransform, 
     846               0 :     sizeof(m_adfTransform));
     847                 : 
     848               0 :   return CE_None;
     849                 : }
     850                 : 
     851                 : 
     852                 : /************************************************************************/
     853                 : /*                           SetProjection()                            */
     854                 : /************************************************************************/
     855                 : 
     856               0 : CPLErr LevellerDataset::SetProjection( const char * pszNewProjection )
     857                 : {
     858               0 :   if(m_pszProjection != NULL)
     859               0 :     CPLFree(m_pszProjection);
     860                 : 
     861               0 :   m_pszProjection = CPLStrdup(pszNewProjection);
     862                 : 
     863               0 :   return CE_None;
     864                 : }
     865                 : 
     866                 : 
     867                 : /************************************************************************/
     868                 : /*                           Create()                                   */
     869                 : /************************************************************************/
     870              31 : GDALDataset* LevellerDataset::Create
     871                 : (
     872                 :   const char* pszFilename,
     873                 :     int nXSize, int nYSize, int nBands,
     874                 :     GDALDataType eType, char** papszOptions 
     875                 : )
     876                 : {
     877              31 :   if(nBands != 1)
     878                 :   {
     879               9 :     CPLError( CE_Failure, CPLE_IllegalArg, "Band count must be 1" );
     880               9 :     return NULL;
     881                 :   }
     882                 : 
     883              22 :   if(eType != GDT_Float32)
     884                 :   {
     885              20 :     CPLError( CE_Failure, CPLE_IllegalArg, "Pixel type must be Float32" );
     886              20 :     return NULL;
     887                 :   }
     888                 : 
     889               2 :   if(nXSize < 2 || nYSize < 2)
     890                 :   {
     891               0 :     CPLError( CE_Failure, CPLE_IllegalArg, "One or more raster dimensions too small" );
     892               0 :     return NULL;
     893                 :   }
     894                 : 
     895                 : 
     896               2 :   LevellerDataset* poDS = new LevellerDataset;
     897                 : 
     898               2 :     poDS->eAccess = GA_Update;
     899                 :   
     900               2 :   poDS->m_pszFilename = CPLStrdup(pszFilename);
     901                 : 
     902               2 :     poDS->m_fp = VSIFOpenL( pszFilename, "wb+" );
     903                 : 
     904               2 :     if( poDS->m_fp == NULL )
     905                 :     {
     906                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     907                 :                   "Attempt to create file `%s' failed.",
     908               0 :                   pszFilename );
     909               0 :     delete poDS;
     910               0 :         return NULL;
     911                 :     }
     912                 : 
     913                 :   // Header will be written the first time IWriteBlock
     914                 :   // is called.
     915                 : 
     916               2 :     poDS->nRasterXSize = nXSize;
     917               2 :     poDS->nRasterYSize = nYSize;
     918                 : 
     919                 : 
     920                 :     const char* pszValue = CSLFetchNameValue( 
     921               2 :     papszOptions,"MINUSERPIXELVALUE");
     922               2 :     if( pszValue != NULL )
     923               0 :         poDS->m_dLogSpan[0] = atof( pszValue );
     924                 :   else
     925                 :   {
     926               2 :     delete poDS;
     927                 :     CPLError( CE_Failure, CPLE_IllegalArg, 
     928               2 :       "MINUSERPIXELVALUE must be specified." );
     929               2 :     return NULL;
     930                 :   }
     931                 : 
     932                 :     pszValue = CSLFetchNameValue( 
     933               0 :     papszOptions,"MAXUSERPIXELVALUE");
     934               0 :     if( pszValue != NULL )
     935               0 :         poDS->m_dLogSpan[1] = atof( pszValue );
     936                 : 
     937               0 :   if(poDS->m_dLogSpan[1] < poDS->m_dLogSpan[0])
     938                 :   {
     939               0 :     double t = poDS->m_dLogSpan[0];
     940               0 :     poDS->m_dLogSpan[0] = poDS->m_dLogSpan[1];
     941               0 :     poDS->m_dLogSpan[1] = t;
     942                 :   }
     943                 : 
     944                 : // -------------------------------------------------------------------- 
     945                 : //      Instance a band.                                                
     946                 : // -------------------------------------------------------------------- 
     947               0 :     poDS->SetBand( 1, new LevellerRasterBand( poDS ) );
     948                 : 
     949               0 :   return poDS;
     950                 : }               
     951                 : 
     952                 : 
     953               0 : bool LevellerDataset::write_byte(size_t n)
     954                 : {
     955               0 :   unsigned char uch = (unsigned char)n;
     956               0 :   return (1 == VSIFWriteL(&uch, 1, 1, m_fp));
     957                 : }
     958                 : 
     959                 : 
     960               0 : bool LevellerDataset::write(int n)
     961                 : {
     962                 :   CPL_LSBPTR32(&n);
     963               0 :   return (1 == VSIFWriteL(&n, sizeof(n), 1, m_fp));
     964                 : }
     965                 : 
     966                 : 
     967               0 : bool LevellerDataset::write(size_t n)
     968                 : {
     969                 :   CPL_LSBPTR32(&n);
     970               0 :   return (1 == VSIFWriteL(&n, sizeof(n), 1, m_fp));
     971                 : }
     972                 : 
     973                 : 
     974               0 : bool LevellerDataset::write(double d)
     975                 : {
     976                 :   CPL_LSBPTR64(&d);
     977               0 :   return (1 == VSIFWriteL(&d, sizeof(d), 1, m_fp));
     978                 : }
     979                 : 
     980                 : 
     981                 : 
     982               0 : bool LevellerDataset::write_tag_start(const char* pszTag, size_t n)
     983                 : {
     984               0 :   if(this->write_byte(strlen(pszTag)))
     985                 :   {
     986                 :     return (1 == VSIFWriteL(pszTag, strlen(pszTag), 1, m_fp)
     987               0 :       && this->write(n));
     988                 :   }
     989                 :   
     990               0 :   return false;
     991                 : }
     992                 : 
     993                 : 
     994               0 : bool LevellerDataset::write_tag(const char* pszTag, int n)
     995                 : {
     996                 :   return (this->write_tag_start(pszTag, sizeof(n))
     997               0 :       && this->write(n));
     998                 : }
     999                 : 
    1000                 : 
    1001               0 : bool LevellerDataset::write_tag(const char* pszTag, size_t n)
    1002                 : {
    1003                 :   return (this->write_tag_start(pszTag, sizeof(n))
    1004               0 :       && this->write(n));
    1005                 : }
    1006                 : 
    1007                 : 
    1008               0 : bool LevellerDataset::write_tag(const char* pszTag, double d)
    1009                 : {
    1010                 :   return (this->write_tag_start(pszTag, sizeof(d))
    1011               0 :       && this->write(d));
    1012                 : }
    1013                 : 
    1014                 : 
    1015               0 : bool LevellerDataset::write_tag(const char* pszTag, const char* psz)
    1016                 : {
    1017                 :   CPLAssert(strlen(pszTag) <= kMaxTagNameLen);
    1018                 : 
    1019                 :   char sz[kMaxTagNameLen + 1];
    1020               0 :   sprintf(sz, "%sl", pszTag);
    1021               0 :   const size_t len = strlen(psz);
    1022                 : 
    1023               0 :   if(len > 0 && this->write_tag(sz, len))
    1024                 :   {
    1025               0 :     sprintf(sz, "%sd", pszTag);
    1026               0 :     this->write_tag_start(sz, len);
    1027               0 :     return (1 == VSIFWriteL(psz, len, 1, m_fp));
    1028                 :   }
    1029               0 :   return false;
    1030                 : }
    1031                 : 
    1032                 : 
    1033               5 : bool LevellerDataset::locate_data(vsi_l_offset& offset, size_t& len, FILE* fp, const char* pszTag)
    1034                 : {
    1035                 :     // Locate the file offset of the desired tag's data.
    1036                 :     // If it is not available, return false.
    1037                 :     // If the tag is found, leave the filemark at the 
    1038                 :     // start of its data.
    1039                 : 
    1040               5 :     if(0 != VSIFSeekL(fp, 5, SEEK_SET))
    1041               0 :         return false;
    1042                 : 
    1043               5 :     const int kMaxDescLen = 64;
    1044             744 :     for(;;)
    1045                 :     {
    1046                 :         unsigned char c;
    1047             749 :         if(1 != VSIFReadL(&c, sizeof(c), 1, fp))
    1048               0 :             return false;
    1049                 : 
    1050             749 :         const size_t descriptorLen = c;
    1051             749 :         if(descriptorLen == 0 || descriptorLen > (size_t)kMaxDescLen)
    1052               0 :             return false;
    1053                 : 
    1054                 :         char descriptor[kMaxDescLen+1];
    1055             749 :         if(1 != VSIFReadL(descriptor, descriptorLen, 1, fp))
    1056               0 :             return false;
    1057                 : 
    1058                 :         GUInt32 datalen;
    1059             749 :         if(1 != VSIFReadL(&datalen, sizeof(datalen), 1, fp))
    1060               0 :             return false;
    1061                 : 
    1062             749 :         datalen = CPL_LSBWORD32(datalen);
    1063             749 :         descriptor[descriptorLen] = 0;
    1064             749 :         if(str_equal(descriptor, pszTag))
    1065                 :         {
    1066               5 :             len = (size_t)datalen;
    1067               5 :             offset = VSIFTellL(fp);
    1068               5 :             return true;
    1069                 :         }
    1070                 :         else
    1071                 :         {
    1072                 :             // Seek to next tag.
    1073             744 :             if(0 != VSIFSeekL(fp, (vsi_l_offset)datalen, SEEK_CUR))
    1074               0 :                 return false;
    1075                 :         }
    1076                 :     }
    1077                 :     return false;
    1078                 : }
    1079                 : 
    1080                 : /************************************************************************/
    1081                 : /*                                get()                                 */
    1082                 : /************************************************************************/
    1083                 : 
    1084               2 : bool LevellerDataset::get(int& n, FILE* fp, const char* psz)
    1085                 : {
    1086                 :     vsi_l_offset offset;
    1087                 :     size_t     len;
    1088                 : 
    1089               2 :     if(this->locate_data(offset, len, fp, psz))
    1090                 :     {
    1091                 :         GInt32 value;
    1092               2 :         if(1 == VSIFReadL(&value, sizeof(value), 1, fp))
    1093                 :         {
    1094                 :             CPL_LSBPTR32(&value);
    1095               2 :             n = (int)value;
    1096               2 :             return true;
    1097                 :         }
    1098                 :     } 
    1099               0 :     return false;
    1100                 : }
    1101                 : 
    1102                 : /************************************************************************/
    1103                 : /*                                get()                                 */
    1104                 : /************************************************************************/
    1105                 : 
    1106               1 : bool LevellerDataset::get(double& d, FILE* fp, const char* pszTag)
    1107                 : {
    1108                 :     vsi_l_offset offset;
    1109                 :     size_t     len;
    1110                 : 
    1111               1 :     if(this->locate_data(offset, len, fp, pszTag))
    1112                 :     {
    1113               1 :         if(1 == VSIFReadL(&d, sizeof(d), 1, fp))
    1114                 :         {
    1115                 :             CPL_LSBPTR64(&d);
    1116               1 :             return true;
    1117                 :         }
    1118                 :     } 
    1119               0 :     return false;
    1120                 : }
    1121                 : 
    1122                 : 
    1123                 : /************************************************************************/
    1124                 : /*                                get()                                 */
    1125                 : /************************************************************************/
    1126               1 : bool LevellerDataset::get(char* pszValue, size_t maxchars, FILE* fp, const char* pszTag)
    1127                 : {
    1128                 :     char szTag[65];
    1129                 : 
    1130                 :     // We can assume 8-bit encoding, so just go straight
    1131                 :     // to the *_d tag.
    1132               1 :     sprintf(szTag, "%sd", pszTag);
    1133                 : 
    1134                 :     vsi_l_offset offset;
    1135                 :     size_t     len;
    1136                 : 
    1137               1 :     if(this->locate_data(offset, len, fp, szTag))
    1138                 :     {
    1139               1 :         if(len > maxchars)
    1140               0 :             return false;
    1141                 : 
    1142               1 :         if(1 == VSIFReadL(pszValue, len, 1, fp))
    1143                 :         {
    1144               1 :             pszValue[len] = 0; // terminate C-string
    1145               1 :             return true;
    1146                 :         }
    1147                 :     } 
    1148                 : 
    1149               0 :     return false;
    1150                 : }
    1151                 : 
    1152                 : 
    1153                 : 
    1154               0 : UNITLABEL LevellerDataset::meter_measure_to_code(double dM) const
    1155                 : {
    1156                 :   // Convert a meter conversion factor to its UOM OEM code.
    1157                 :   // If the factor is close to the approximation margin, then
    1158                 :   // require exact equality, otherwise be loose.
    1159                 : 
    1160               0 :   const measurement_unit* pu = this->get_uom(dM);
    1161               0 :   return (pu != NULL ? pu->oemCode : UNITLABEL_UNKNOWN);
    1162                 : }
    1163                 : 
    1164                 : 
    1165               0 : UNITLABEL LevellerDataset::id_to_code(const char* pszUnits) const
    1166                 : {
    1167                 :   // Convert a readable UOM to its OEM code. 
    1168                 : 
    1169               0 :   const measurement_unit* pu = this->get_uom(pszUnits);
    1170               0 :   return (pu != NULL ? pu->oemCode : UNITLABEL_UNKNOWN);
    1171                 : }
    1172                 : 
    1173                 : 
    1174               0 : const char* LevellerDataset::code_to_id(UNITLABEL code) const
    1175                 : {
    1176                 :   // Convert a measurement unit's OEM ID to its readable ID. 
    1177                 : 
    1178               0 :   const measurement_unit* pu = this->get_uom(code);
    1179               0 :   return (pu != NULL ? pu->pszID : NULL);
    1180                 : }
    1181                 : 
    1182                 : 
    1183               0 : const measurement_unit* LevellerDataset::get_uom(const char* pszUnits) const
    1184                 : {
    1185               0 :     for(size_t i = 0; i < array_size(kUnits); i++)
    1186                 :     {
    1187               0 :         if(strcmp(pszUnits, kUnits[i].pszID) == 0)
    1188               0 :             return &kUnits[i];
    1189                 :     }
    1190                 :     CPLError( CE_Failure, CPLE_AppDefined, 
    1191               0 :               "Unknown measurement units: %s", pszUnits );
    1192               0 :     return NULL;
    1193                 : }
    1194                 : 
    1195                 : 
    1196               0 : const measurement_unit* LevellerDataset::get_uom(UNITLABEL code) const
    1197                 : {
    1198               0 :     for(size_t i = 0; i < array_size(kUnits); i++)
    1199                 :     {
    1200               0 :         if(kUnits[i].oemCode == code)
    1201               0 :             return &kUnits[i];
    1202                 :     }
    1203                 :     CPLError( CE_Failure, CPLE_AppDefined, 
    1204               0 :               "Unknown measurement unit code: %08x", code );
    1205               0 :     return NULL;
    1206                 : }
    1207                 : 
    1208                 : 
    1209               0 : const measurement_unit* LevellerDataset::get_uom(double dM) const
    1210                 : {
    1211               0 :     for(size_t i = kFirstLinearMeasureIdx; i < array_size(kUnits); i++)
    1212                 :     {
    1213               0 :     if(dM >= 1.0e-4)
    1214                 :     {
    1215               0 :       if(approx_equal(dM, kUnits[i].dScale))
    1216               0 :         return &kUnits[i];
    1217                 :     }
    1218               0 :     else if(dM == kUnits[i].dScale)
    1219               0 :       return &kUnits[i];
    1220                 :     }
    1221                 :     CPLError( CE_Failure, CPLE_AppDefined, 
    1222               0 :               "Unknown measurement conversion factor: %f", dM );
    1223               0 :     return NULL;
    1224                 : }
    1225                 : 
    1226                 : /************************************************************************/
    1227                 : /*                          convert_measure()                           */
    1228                 : /************************************************************************/
    1229                 : 
    1230                 : 
    1231               1 : bool LevellerDataset::convert_measure
    1232                 : (
    1233                 :   double d, 
    1234                 :   double& dResult,
    1235                 :   const char* pszSpace 
    1236                 : )
    1237                 : {
    1238                 :     // Convert a measure to meters.
    1239                 : 
    1240              21 :     for(size_t i = kFirstLinearMeasureIdx; i < array_size(kUnits); i++)
    1241                 :     {
    1242              21 :         if(str_equal(pszSpace, kUnits[i].pszID))
    1243                 :     {
    1244               1 :             dResult = d * kUnits[i].dScale;
    1245               1 :       return true;
    1246                 :     }
    1247                 :     }
    1248                 :     CPLError( CE_Failure, CPLE_FileIO, 
    1249               0 :               "Unknown linear measurement unit: '%s'", pszSpace );
    1250               0 :     return false;
    1251                 : }
    1252                 : 
    1253                 : 
    1254               1 : bool LevellerDataset::make_local_coordsys(const char* pszName, const char* pszUnits)
    1255                 : {
    1256               1 :   OGRSpatialReference sr;
    1257                 : 
    1258               1 :   sr.SetLocalCS(pszName);
    1259                 :   double d;
    1260                 :   return ( this->convert_measure(1.0, d, pszUnits)
    1261                 :     && OGRERR_NONE == sr.SetLinearUnits(pszUnits, d) 
    1262               1 :     && OGRERR_NONE == sr.exportToWkt(&m_pszProjection) );
    1263                 : }
    1264                 : 
    1265                 : 
    1266               0 : bool LevellerDataset::make_local_coordsys(const char* pszName, UNITLABEL code)
    1267                 : {
    1268               0 :   const char* pszUnitID = this->code_to_id(code);
    1269                 :   return ( pszUnitID != NULL
    1270               0 :     && this->make_local_coordsys(pszName, pszUnitID));
    1271                 : }
    1272                 : 
    1273                 : 
    1274                 : 
    1275                 : /************************************************************************/
    1276                 : /*                            load_from_file()                            */
    1277                 : /************************************************************************/
    1278                 : 
    1279               1 : bool LevellerDataset::load_from_file(FILE* file, const char* pszFilename)
    1280                 : {
    1281                 :     // get hf dimensions
    1282               1 :     if(!this->get(nRasterXSize, file, "hf_w"))
    1283                 :   {
    1284                 :     CPLError( CE_Failure, CPLE_OpenFailed,
    1285               0 :             "Cannot determine heightfield width." );
    1286               0 :         return false;
    1287                 :   }
    1288                 : 
    1289               1 :     if(!this->get(nRasterYSize, file, "hf_b"))
    1290                 :   {
    1291                 :     CPLError( CE_Failure, CPLE_OpenFailed,
    1292               0 :             "Cannot determine heightfield breadth." );
    1293               0 :         return false;
    1294                 :   }
    1295                 : 
    1296               1 :   if(nRasterXSize < 2 || nRasterYSize < 2)
    1297                 :   {
    1298                 :     CPLError( CE_Failure, CPLE_OpenFailed,
    1299               0 :             "Heightfield raster dimensions too small." );
    1300               0 :         return false;
    1301                 :   }
    1302                 : 
    1303                 :     // Record start of pixel data
    1304                 :     size_t datalen;
    1305               1 :     if(!this->locate_data(m_nDataOffset, datalen, file, "hf_data"))
    1306                 :   {
    1307                 :     CPLError( CE_Failure, CPLE_OpenFailed,
    1308               0 :             "Cannot locate elevation data." );
    1309               0 :         return false;
    1310                 :   }
    1311                 : 
    1312                 :     // Sanity check: do we have enough pixels?
    1313               1 :     if(datalen != nRasterXSize * nRasterYSize * sizeof(float))
    1314                 :   {
    1315                 :     CPLError( CE_Failure, CPLE_OpenFailed,
    1316               0 :             "File does not have enough data." );
    1317               0 :         return false;
    1318                 :   }
    1319                 : 
    1320                 : 
    1321                 :   // Defaults for raster coordsys.
    1322               1 :     m_adfTransform[0] = 0.0;
    1323               1 :     m_adfTransform[1] = 1.0;
    1324               1 :     m_adfTransform[2] = 0.0;
    1325               1 :     m_adfTransform[3] = 0.0;
    1326               1 :     m_adfTransform[4] = 0.0;
    1327               1 :     m_adfTransform[5] = 1.0;
    1328                 : 
    1329               1 :   m_dElevScale = 1.0;
    1330               1 :     m_dElevBase = 0.0;
    1331               1 :   strcpy(m_szElevUnits, "");
    1332                 : 
    1333               1 :   if(m_version == 7)
    1334                 :   {
    1335                 :     // Read coordsys info.
    1336               0 :     int csclass = LEV_COORDSYS_RASTER;
    1337               0 :       (void)this->get(csclass, file, "csclass");
    1338                 : 
    1339               0 :     if(csclass != LEV_COORDSYS_RASTER)
    1340                 :     {
    1341                 :       // Get projection details and units.
    1342                 : 
    1343                 :       CPLAssert(m_pszProjection == NULL);
    1344                 : 
    1345               0 :       if(csclass == LEV_COORDSYS_LOCAL)
    1346                 :       {
    1347                 :         UNITLABEL unitcode;
    1348                 :         //char szLocalUnits[8];
    1349               0 :         if(!this->get((int&)unitcode, file, "coordsys_units"))
    1350               0 :           unitcode = UNITLABEL_M;
    1351                 : 
    1352               0 :         if(!this->make_local_coordsys("Leveller", unitcode))
    1353                 :         {
    1354                 :           CPLError( CE_Failure, CPLE_OpenFailed,
    1355               0 :                   "Cannot define local coordinate system." );
    1356               0 :           return false;
    1357                 :         }
    1358                 :       }
    1359               0 :       else if(csclass == LEV_COORDSYS_GEO)
    1360                 :       {
    1361                 :         char szWKT[1024];
    1362               0 :         if(!this->get(szWKT, 1023, file, "coordsys_wkt"))
    1363               0 :           return 0;
    1364                 : 
    1365               0 :         m_pszProjection = (char*)CPLMalloc(strlen(szWKT) + 1);
    1366               0 :         strcpy(m_pszProjection, szWKT);
    1367                 :       }
    1368                 :       else
    1369                 :       {
    1370                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    1371                 :               "Unknown coordinate system type in %s.",
    1372               0 :               pszFilename );
    1373               0 :         return false;
    1374                 :       }
    1375                 : 
    1376                 :       // Get ground extents.
    1377               0 :       digital_axis axis_ns, axis_ew;
    1378                 : 
    1379               0 :       if(axis_ns.get(*this, file, 0)
    1380                 :         && axis_ew.get(*this, file, 1))
    1381                 :       {
    1382               0 :         m_adfTransform[0] = axis_ew.origin(nRasterXSize);
    1383               0 :         m_adfTransform[1] = axis_ew.scaling(nRasterXSize);
    1384               0 :         m_adfTransform[2] = 0.0;
    1385                 : 
    1386               0 :         m_adfTransform[3] = axis_ns.origin(nRasterYSize);
    1387               0 :         m_adfTransform[4] = 0.0;
    1388               0 :         m_adfTransform[5] = axis_ns.scaling(nRasterYSize);
    1389                 :       }
    1390                 :     }
    1391                 : 
    1392                 :     // Get vertical (elev) coordsys.
    1393               0 :     int bHasVertCS = FALSE;
    1394               0 :     if(this->get(bHasVertCS, file, "coordsys_haselevm") && bHasVertCS)
    1395                 :     {
    1396               0 :       this->get(m_dElevScale, file, "coordsys_em_scale");
    1397               0 :       this->get(m_dElevBase, file, "coordsys_em_base");
    1398                 :       UNITLABEL unitcode;
    1399               0 :       if(this->get((int&)unitcode, file, "coordsys_em_units"))
    1400                 :       {
    1401               0 :         const char* pszUnitID = this->code_to_id(unitcode);
    1402               0 :         if(pszUnitID != NULL)
    1403               0 :           strcpy(m_szElevUnits, pszUnitID);
    1404                 :         else
    1405                 :         {
    1406                 :           CPLError( CE_Failure, CPLE_OpenFailed,
    1407                 :                   "Unknown OEM elevation unit of measure (%d)",
    1408               0 :                   unitcode );
    1409               0 :           return false;
    1410                 :         }
    1411                 :       }
    1412                 :       // datum and localcs are currently unused.
    1413                 :     }
    1414                 :   }
    1415                 :   else
    1416                 :   {
    1417                 :     // Legacy files use world units.
    1418                 :       char szWorldUnits[32];
    1419               1 :     strcpy(szWorldUnits, "m");
    1420                 : 
    1421               1 :       double dWorldscale = 1.0;
    1422                 : 
    1423               1 :     if(this->get(dWorldscale, file, "hf_worldspacing"))
    1424                 :     {
    1425                 :       //m_bHasWorldscale = true;
    1426               1 :       if(this->get(szWorldUnits, sizeof(szWorldUnits)-1, file, 
    1427                 :         "hf_worldspacinglabel"))
    1428                 :       {
    1429                 :         // Drop long name, if present.
    1430               1 :         char* p = strchr(szWorldUnits, ' ');
    1431               1 :         if(p != NULL)
    1432               1 :           *p = 0;
    1433                 :       }
    1434                 : 
    1435                 : #if 0
    1436                 :       // If the units are something besides m/ft/sft, 
    1437                 :       // then convert them to meters.
    1438                 : 
    1439                 :       if(!str_equal("m", szWorldUnits)
    1440                 :          && !str_equal("ft", szWorldUnits)
    1441                 :          && !str_equal("sft", szWorldUnits))
    1442                 :       {
    1443                 :         dWorldscale = this->convert_measure(dWorldscale, szWorldUnits);
    1444                 :         strcpy(szWorldUnits, "m");
    1445                 :       }
    1446                 : #endif
    1447                 : 
    1448                 :       // Our extents are such that the origin is at the 
    1449                 :       // center of the heightfield.
    1450               1 :       m_adfTransform[0] = -0.5 * dWorldscale * (nRasterXSize-1);
    1451               1 :       m_adfTransform[3] = -0.5 * dWorldscale * (nRasterYSize-1);
    1452               1 :       m_adfTransform[1] = dWorldscale;
    1453               1 :       m_adfTransform[5] = dWorldscale;
    1454                 :     }
    1455               1 :     m_dElevScale = dWorldscale; // this was 1.0 before because 
    1456                 :     // we were converting to real elevs ourselves, but
    1457                 :     // some callers may want both the raw pixels and the 
    1458                 :     // transform to get real elevs.
    1459                 : 
    1460               1 :     if(!this->make_local_coordsys("Leveller world space", szWorldUnits))
    1461                 :     {
    1462                 :       CPLError( CE_Failure, CPLE_OpenFailed,
    1463               0 :               "Cannot define local coordinate system." );
    1464               0 :       return false;
    1465                 :     }
    1466                 :   }
    1467                 : 
    1468               1 :     return true;
    1469                 : }
    1470                 : 
    1471                 : /************************************************************************/
    1472                 : /*                          GetProjectionRef()                          */
    1473                 : /************************************************************************/
    1474                 : 
    1475               0 : const char* LevellerDataset::GetProjectionRef(void)
    1476                 : {
    1477               0 :     return (m_pszProjection == NULL ? "" : m_pszProjection);
    1478                 : }
    1479                 : 
    1480                 : /************************************************************************/
    1481                 : /*                          GetGeoTransform()                           */
    1482                 : /************************************************************************/
    1483                 : 
    1484               0 : CPLErr LevellerDataset::GetGeoTransform(double* padfTransform)
    1485                 : 
    1486                 : {
    1487               0 :   memcpy(padfTransform, m_adfTransform, sizeof(m_adfTransform));
    1488               0 :     return CE_None;
    1489                 : }
    1490                 : 
    1491                 : /************************************************************************/
    1492                 : /*                              Identify()                              */
    1493                 : /************************************************************************/
    1494                 : 
    1495            8571 : int LevellerDataset::Identify( GDALOpenInfo * poOpenInfo )
    1496                 : {
    1497            8571 :     if( poOpenInfo->nHeaderBytes < 4 )
    1498            7722 :         return FALSE;
    1499                 : 
    1500             849 :     return EQUALN((const char *) poOpenInfo->pabyHeader, "trrn", 4);
    1501                 : }
    1502                 : 
    1503                 : /************************************************************************/
    1504                 : /*                                Open()                                */
    1505                 : /************************************************************************/
    1506                 : 
    1507            1776 : GDALDataset *LevellerDataset::Open( GDALOpenInfo * poOpenInfo )
    1508                 : {
    1509                 :     // The file should have at least 5 header bytes
    1510                 :     // and hf_w, hf_b, and hf_data tags.
    1511                 : #ifdef DEBUG
    1512                 : 
    1513                 : #endif
    1514            1776 :     if( poOpenInfo->nHeaderBytes < 5+13+13+16 )
    1515             934 :         return NULL;
    1516                 : 
    1517             842 :   if( !LevellerDataset::Identify(poOpenInfo))
    1518             841 :     return NULL;
    1519                 : 
    1520               1 :     const int version = poOpenInfo->pabyHeader[4];
    1521               1 :     if(version < 4 || version > 7)
    1522               0 :         return NULL;
    1523                 : 
    1524                 : 
    1525                 : /* -------------------------------------------------------------------- */
    1526                 : /*      Create a corresponding GDALDataset.                             */
    1527                 : /* -------------------------------------------------------------------- */
    1528                 : 
    1529               1 :   LevellerDataset* poDS = new LevellerDataset();
    1530                 : 
    1531               1 :     poDS->m_version = version;
    1532                 : 
    1533                 :     // Reopen for large file access.
    1534               1 :     if( poOpenInfo->eAccess == GA_Update )
    1535               0 :         poDS->m_fp = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
    1536                 :     else
    1537               1 :         poDS->m_fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
    1538                 : 
    1539               1 :     if( poDS->m_fp == NULL )
    1540                 :     {
    1541                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    1542                 :                   "Failed to re-open %s within Leveller driver.",
    1543               0 :                   poOpenInfo->pszFilename );
    1544               0 :         return NULL;
    1545                 :     }
    1546               1 :     poDS->eAccess = poOpenInfo->eAccess;
    1547                 : 
    1548                 :     
    1549                 : /* -------------------------------------------------------------------- */
    1550                 : /*  Read the file.                                          */
    1551                 : /* -------------------------------------------------------------------- */
    1552               1 :     if( !poDS->load_from_file( poDS->m_fp, poOpenInfo->pszFilename ) )
    1553                 :     {
    1554               0 :         delete poDS;
    1555               0 :         return NULL;
    1556                 :     }
    1557                 : 
    1558                 : /* -------------------------------------------------------------------- */
    1559                 : /*      Create band information objects.                                */
    1560                 : /* -------------------------------------------------------------------- */
    1561               1 :     poDS->SetBand( 1, new LevellerRasterBand( poDS ));
    1562                 : 
    1563               1 :     poDS->SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
    1564                 : 
    1565                 : /* -------------------------------------------------------------------- */
    1566                 : /*      Initialize any PAM information.                                 */
    1567                 : /* -------------------------------------------------------------------- */
    1568               1 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1569               1 :     poDS->TryLoadXML();
    1570                 : 
    1571               1 :     return( poDS );
    1572                 : }
    1573                 : 
    1574                 : #else
    1575                 : // stub so that module compiles
    1576                 : class LevellerDataset : public GDALPamDataset
    1577                 : {
    1578                 :   public:
    1579                 :     static GDALDataset* Open( GDALOpenInfo* ) { return NULL; }
    1580                 : };
    1581                 : #endif
    1582                 : 
    1583                 : /************************************************************************/
    1584                 : /*                        GDALRegister_Leveller()                       */
    1585                 : /************************************************************************/
    1586                 : 
    1587             338 : void GDALRegister_Leveller()
    1588                 : 
    1589                 : {
    1590                 :     GDALDriver  *poDriver;
    1591                 : 
    1592             338 :     if( GDALGetDriverByName( "Leveller" ) == NULL )
    1593                 :     {
    1594             336 :         poDriver = new GDALDriver();
    1595                 :         
    1596             336 :         poDriver->SetDescription( "Leveller" );
    1597                 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, 
    1598             336 :                                    "ter" );
    1599                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1600             336 :                                    "Leveller heightfield" );
    1601                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1602             336 :                                    "frmt_leveller.html" );
    1603                 :         
    1604                 : #if GDAL_VERSION_NUM >= 1500
    1605             336 :         poDriver->pfnIdentify = LevellerDataset::Identify;
    1606                 : #endif
    1607             336 :         poDriver->pfnOpen = LevellerDataset::Open;
    1608             336 :         poDriver->pfnCreate = LevellerDataset::Create;
    1609                 : 
    1610             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1611                 :     }
    1612             338 : }

Generated by: LCOV version 1.7