LTP GCOV extension - code coverage report
Current view: directory - frmts/mrsid_lidar - gdal_MG4Lidar.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 391
Code covered: 69.6 % Executed lines: 272

       1                 : /******************************************************************************
       2                 : * Project:  MG4 Lidar GDAL Plugin
       3                 : * Purpose:  Provide an orthographic view of MG4-encoded Lidar dataset
       4                 : *                   for use with LizardTech Lidar SDK version 1.1.0
       5                 : * Author:   Michael Rosen, mrosen@lizardtech.com
       6                 : *
       7                 : ******************************************************************************
       8                 : * Copyright (c) 2010, LizardTech
       9                 : * All rights reserved.
      10                 : 
      11                 : * Redistribution and use in source and binary forms, with or without 
      12                 : * modification, are permitted provided that the following conditions are met:
      13                 : *
      14                 : *   Redistributions of source code must retain the above copyright notice, 
      15                 : *   this list of conditions and the following disclaimer.
      16                 : * 
      17                 : *   Redistributions in binary form must reproduce the above copyright notice, 
      18                 : *   this list of conditions and the following disclaimer in the documentation
      19                 : *   and/or other materials provided with the distribution.
      20                 : *
      21                 : *   Neither the name of the LizardTech nor the names of its contributors may 
      22                 : *   be used to endorse or promote products derived from this software without 
      23                 : *   specific prior written permission.
      24                 : *
      25                 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
      26                 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
      27                 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
      28                 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
      29                 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
      30                 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
      31                 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
      32                 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
      33                 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
      34                 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
      35                 : * POSSIBILITY OF SUCH DAMAGE.
      36                 : ****************************************************************************/
      37                 : #include "lidar/MG4PointReader.h"
      38                 : #include "lidar/Error.h"
      39                 : #include <float.h>
      40                 : LT_USE_LIDAR_NAMESPACE
      41                 : 
      42                 : #include "gdal_pam.h"
      43                 : // #include "gdal_alg.h" // 1.6 and later have gridding algorithms
      44                 : 
      45                 : CPL_C_START
      46                 : //void __declspec(dllexport) GDALRegister_MG4Lidar(void);
      47                 : void CPL_DLL GDALRegister_MG4Lidar(void);
      48                 : CPL_C_END
      49                 : 
      50                 : /************************************************************************/
      51                 : /* ==================================================================== */
      52                 : /*        MG4LidarDataset       */
      53                 : /* ==================================================================== */
      54                 : /************************************************************************/
      55                 : 
      56                 : // Resolution Ratio between adjacent levels.
      57                 : #define RESOLUTION_RATIO 2.0
      58                 : 
      59                 : class MG4LidarRasterBand;
      60                 : class CropableMG4PointReader : public MG4PointReader
      61                 : {
      62                 :    CONCRETE_OBJECT(CropableMG4PointReader);
      63               1 :    void init (const char *path, Bounds *bounds)

      64                 :    {
      65               1 :       MG4PointReader::init(path);

      66               1 :       if (bounds != NULL)

      67               1 :          setBounds(*bounds);

      68               1 :    }

      69                 : };
      70               1 : CropableMG4PointReader::CropableMG4PointReader() : MG4PointReader() {};   

      71               1 : CropableMG4PointReader::~CropableMG4PointReader() {};   

      72                 : 
      73               1 : IMPLEMENT_OBJECT_CREATE(CropableMG4PointReader);

      74                 : 
      75                 : static double MaxRasterSize = 2048.0;
      76                 : static double MaxBlockSideSize = 1024.0;
      77                 : class MG4LidarDataset : public GDALPamDataset
      78                 : {
      79                 : friend class MG4LidarRasterBand;
      80                 : public:
      81                 :    MG4LidarDataset();
      82                 :    ~MG4LidarDataset();
      83                 :    static GDALDataset *Open( GDALOpenInfo * );
      84                 :    CPLErr   GetGeoTransform( double * padfTransform );
      85                 :    const char *GetProjectionRef();
      86                 : protected:
      87                 :    MG4PointReader *reader;
      88                 :    CPLErr OpenZoomLevel( int Zoom );
      89                 :    PointInfo requiredChannels;
      90                 :    int nOverviewCount;
      91                 :    MG4LidarDataset **papoOverviewDS;
      92                 :    CPLXMLNode *poXMLPCView;
      93                 :    int nBlockXSize, nBlockYSize;
      94                 :    int iLevel;
      95                 : };
      96                 : 
      97                 : /* ========================================  */
      98                 : /*                            MG4LidarRasterBand                                          */
      99                 : /* ========================================  */
     100                 : 
     101                 : class MG4LidarRasterBand : public GDALPamRasterBand
     102                 : {
     103                 :    friend class MG4LidarDataset;
     104                 : 
     105                 : public:
     106                 : 
     107                 :    MG4LidarRasterBand( MG4LidarDataset *, int, CPLXMLNode *, const char * );
     108                 :    ~MG4LidarRasterBand();
     109                 : 
     110                 :    virtual CPLErr GetStatistics( int bApproxOK, int bForce, double *pdfMin, double *pdfMax, double *pdfMean, double *padfStdDev );
     111                 :    virtual int GetOverviewCount();
     112                 :    virtual GDALRasterBand * GetOverview( int i );
     113                 :    virtual CPLErr IReadBlock( int, int, void * );
     114                 :    virtual double GetNoDataValue( int *pbSuccess = NULL );
     115                 : 
     116                 :    protected:
     117                 :    double getMaxValue();
     118                 :    double nodatavalue;
     119                 :    virtual const bool ElementPassesFilter(const PointData &, size_t);
     120                 :    template<typename DTYPE>
     121                 :    CPLErr   doReadBlock(int, int, void *);
     122                 :    CPLXMLNode *poxmlBand;
     123                 :    char **papszFilterClassCodes;
     124                 :    char **papszFilterReturnNums;
     125                 :    const char * Aggregation;
     126                 :    CPLString ChannelName;
     127                 : };
     128                 : 
     129                 : 
     130                 : /************************************************************************/
     131                 : /*                           MG4LidarRasterBand()                            */
     132                 : /************************************************************************/
     133                 : 
     134               2 : MG4LidarRasterBand::MG4LidarRasterBand( MG4LidarDataset *pods, int nband, CPLXMLNode *xmlBand, const char * name )

     135                 : {
     136               2 :    this->poDS = pods;

     137               2 :    this->nBand = nband;

     138               2 :    this->poxmlBand = xmlBand;

     139               2 :    this->ChannelName = name;

     140               2 :    this->Aggregation = NULL;

     141               2 :    nBlockXSize = pods->nBlockXSize;

     142               2 :    nBlockYSize = pods->nBlockYSize;

     143                 : 
     144               2 :    switch(pods->reader->getChannel(name)->getDataType())

     145                 :    {
     146                 : #define DO_CASE(ltdt, gdt) case (ltdt): eDataType = gdt; break;
     147               2 :       DO_CASE(DATATYPE_FLOAT64, GDT_Float64);

     148               0 :       DO_CASE(DATATYPE_FLOAT32, GDT_Float32);

     149               0 :       DO_CASE(DATATYPE_SINT32, GDT_Int32);

     150               0 :       DO_CASE(DATATYPE_UINT32, GDT_UInt32);

     151               0 :       DO_CASE(DATATYPE_SINT16, GDT_Int16);

     152               0 :       DO_CASE(DATATYPE_UINT16, GDT_UInt16);

     153               0 :       DO_CASE(DATATYPE_SINT8, GDT_Byte);

     154               0 :       DO_CASE(DATATYPE_UINT8, GDT_Byte);

     155                 : default:
     156                 :    CPLError(CE_Failure, CPLE_AssertionFailed,
     157               0 :       "Invalid datatype in MG4 file");

     158                 :    break;
     159                 : #undef DO_CASE      
     160                 :    }
     161                 :    // Coerce datatypes as required.
     162               2 :    const char * ForceDataType =  CPLGetXMLValue(pods->poXMLPCView, "Datatype", NULL);

     163                 : 
     164               2 :    if (ForceDataType != NULL)

     165                 :    {
     166               2 :       GDALDataType dt = GDALGetDataTypeByName(ForceDataType);

     167               2 :       if (dt != GDT_Unknown)

     168               2 :          eDataType = dt;

     169                 :    }
     170                 : 
     171               2 :    CPLXMLNode *poxmlFilter = CPLGetXMLNode(poxmlBand, "ClassificationFilter");

     172               2 :    if( poxmlFilter == NULL )

     173               0 :       poxmlFilter = CPLGetXMLNode(pods->poXMLPCView, "ClassificationFilter");

     174               2 :    if (poxmlFilter == NULL || poxmlFilter->psChild == NULL ||

     175                 :        poxmlFilter->psChild->pszValue == NULL)
     176               0 :       papszFilterClassCodes = NULL;

     177                 :    else
     178               2 :       papszFilterClassCodes = CSLTokenizeString(poxmlFilter->psChild->pszValue);

     179                 : 
     180               2 :    poxmlFilter = CPLGetXMLNode(poxmlBand, "ReturnNumberFilter");

     181               2 :    if( poxmlFilter == NULL )

     182               2 :       poxmlFilter = CPLGetXMLNode(pods->poXMLPCView, "ReturnNumberFilter");

     183               4 :    if (poxmlFilter == NULL || poxmlFilter->psChild == NULL ||

     184                 :        poxmlFilter->psChild->pszValue == NULL)
     185               2 :       papszFilterReturnNums = NULL;

     186                 :    else
     187               0 :       papszFilterReturnNums = CSLTokenizeString(poxmlFilter->psChild->pszValue);

     188                 : 
     189                 :    
     190               2 :    CPLXMLNode * poxmlAggregation = CPLGetXMLNode(poxmlBand, "AggregationMethod");

     191               2 :    if( poxmlAggregation == NULL )

     192               2 :       poxmlAggregation = CPLGetXMLNode(pods->poXMLPCView, "AggregationMethod");

     193               4 :    if (poxmlAggregation == NULL || poxmlAggregation->psChild == NULL ||

     194                 :        poxmlAggregation->psChild->pszValue == NULL)
     195               2 :       Aggregation = "Mean";

     196                 :    else
     197               0 :       Aggregation = poxmlAggregation->psChild->pszValue;

     198                 : 
     199               2 :    nodatavalue = getMaxValue();

     200                 : 
     201               2 :    CPLXMLNode * poxmlIntepolation = CPLGetXMLNode(poxmlBand, "InterpolationMethod");

     202               2 :    if( poxmlIntepolation == NULL )

     203               2 :       poxmlIntepolation = CPLGetXMLNode(pods->poXMLPCView, "InterpolationMethod");

     204               2 :    if (poxmlIntepolation != NULL )

     205                 :    {
     206               0 :       CPLXMLNode * poxmlMethod= NULL;

     207               0 :       char ** papszParams = NULL;

     208               0 :       if (((poxmlMethod = CPLSearchXMLNode(poxmlIntepolation, "None")) != NULL) &&

     209                 :           poxmlMethod->psChild != NULL && poxmlMethod->psChild->pszValue != NULL)
     210                 :       {
     211               0 :          papszParams = CSLTokenizeString(poxmlMethod->psChild->pszValue);

     212               0 :          if (!EQUAL(papszParams[0], "MAX"))

     213               0 :             nodatavalue = atof(papszParams[0]);

     214                 :       }
     215                 :       // else if .... Add support for other interpolation methods here.
     216               0 :       CSLDestroy(papszParams);

     217                 :    }
     218               2 :    const char * filter = NULL;

     219               2 :    if (papszFilterClassCodes != NULL && papszFilterReturnNums != NULL)

     220               0 :       filter ="Classification and Return";

     221               2 :    if (papszFilterClassCodes != NULL)

     222               2 :       filter = "Classification";

     223               0 :    else if (papszFilterReturnNums != NULL)

     224               0 :       filter = "Return";

     225               2 :    CPLString osDesc;

     226               2 :    if (filter)

     227               2 :       osDesc.Printf("%s of %s (filtered by %s)", Aggregation, ChannelName.c_str(), filter);

     228                 :    else
     229               0 :       osDesc.Printf("%s of %s", Aggregation, ChannelName.c_str());

     230               2 :    SetDescription(osDesc);

     231               2 : }

     232                 : 
     233                 : /************************************************************************/
     234                 : /*                          ~MG4LidarRasterBand()                            */
     235                 : /************************************************************************/
     236               2 : MG4LidarRasterBand::~MG4LidarRasterBand()

     237                 : {
     238               2 :    CSLDestroy(papszFilterClassCodes);

     239               2 :    CSLDestroy(papszFilterReturnNums);

     240               2 : }

     241                 : 
     242                 : /************************************************************************/
     243                 : /*                          GetOverviewCount()                          */
     244                 : /************************************************************************/
     245                 : 
     246               0 : int MG4LidarRasterBand::GetOverviewCount()

     247                 : {
     248               0 :    MG4LidarDataset *poGDS = (MG4LidarDataset *) poDS;

     249               0 :    return poGDS->nOverviewCount;

     250                 : }
     251                 : 
     252                 : /************************************************************************/
     253                 : /*                            GetOverview()                             */
     254                 : /************************************************************************/
     255               1 : GDALRasterBand *MG4LidarRasterBand::GetOverview( int i )

     256                 : {
     257               1 :    MG4LidarDataset *poGDS = (MG4LidarDataset *) poDS;

     258                 : 
     259               1 :    if( i < 0 || i >= poGDS->nOverviewCount )

     260               0 :       return NULL;

     261                 :    else
     262               1 :       return poGDS->papoOverviewDS[i]->GetRasterBand( nBand );

     263                 : }
     264                 : template<typename DTYPE>
     265          407623 : const DTYPE GetChannelElement(const ChannelData &channel, size_t idx)

     266                 : {
     267          407623 :    DTYPE retval = static_cast<DTYPE>(0);

     268          407623 :    switch (channel.getDataType())

     269                 :    {
     270                 :    case (DATATYPE_FLOAT64):
     271          112133 :       retval = static_cast<DTYPE>(static_cast<const double*>(channel.getData())[idx]);

     272          112133 :       break;

     273                 :    case (DATATYPE_FLOAT32):
     274               0 :       retval = static_cast<DTYPE>(static_cast<const float *>(channel.getData())[idx]);

     275               0 :       break;

     276                 :    case (DATATYPE_SINT32):
     277               0 :       retval = static_cast<DTYPE>(static_cast<const long *>(channel.getData())[idx]);

     278               0 :       break;

     279                 :    case (DATATYPE_UINT32):
     280               0 :       retval = static_cast<DTYPE>(static_cast<const unsigned long *>(channel.getData())[idx]);

     281               0 :       break;

     282                 :    case (DATATYPE_SINT16):
     283               0 :       retval = static_cast<DTYPE>(static_cast<const short *>(channel.getData())[idx]);

     284               0 :       break;

     285                 :    case (DATATYPE_UINT16):
     286               0 :       retval = static_cast<DTYPE>(static_cast<const unsigned short *>(channel.getData())[idx]);

     287               0 :       break;

     288                 :    case (DATATYPE_SINT8):
     289               0 :       retval = static_cast<DTYPE>(static_cast<const char *>(channel.getData())[idx]);

     290               0 :       break;

     291                 :    case (DATATYPE_UINT8):
     292          295490 :       retval = static_cast<DTYPE>(static_cast<const unsigned char *>(channel.getData())[idx]);

     293          295490 :       break;

     294                 :    case (DATATYPE_SINT64):
     295               0 :       retval = static_cast<DTYPE>(static_cast<const GIntBig *>(channel.getData())[idx]);

     296               0 :       break;

     297                 :    case (DATATYPE_UINT64):
     298               0 :       retval = static_cast<DTYPE>(static_cast<const GUIntBig *>(channel.getData())[idx]);

     299                 :       break;
     300                 :    default:
     301                 :       break;
     302                 :    }
     303          407623 :    return retval;

     304                 : }
     305                 : 
     306                 : 
     307          295490 : const bool MG4LidarRasterBand::ElementPassesFilter(const PointData &pointdata, size_t i)

     308                 : {
     309          295490 :    bool bClassificationOK = true;

     310          295490 :    bool bReturnNumOK = true;

     311                 : 
     312                 :    // Check if classification code is ok:  it was requested and it does match one of the requested codes
     313          295490 :    const int classcode = GetChannelElement<int>(*pointdata.getChannel(CHANNEL_NAME_ClassId), i);

     314                 :    char bufCode[16];
     315          295490 :    sprintf(bufCode, "%d", classcode);

     316                 :    bClassificationOK = (papszFilterClassCodes == NULL ? true :
     317          295490 :       (CSLFindString(papszFilterClassCodes,bufCode)!=-1));

     318                 : 
     319          295490 :    if (bClassificationOK)

     320                 :    {
     321                 :       // Check if return num is ok:  it was requested and it does match one of the requested return numbers
     322          112133 :       const long returnnum= static_cast<const unsigned char *>(pointdata.getChannel(CHANNEL_NAME_ReturnNum)->getData())[i];

     323          112133 :       sprintf(bufCode, "%d", (int)returnnum);

     324                 :       bReturnNumOK = (papszFilterReturnNums == NULL ? true :
     325          112133 :          (CSLFindString(papszFilterReturnNums, bufCode)!=-1));

     326          112133 :       if (!bReturnNumOK && CSLFindString(papszFilterReturnNums, "Last")!=-1)

     327                 :       {  // Didn't find an explicit match (e.g. return number "1") so we handle a request for "Last" returns
     328               0 :          const long numreturns= GetChannelElement<long>(*pointdata.getChannel(CHANNEL_NAME_NumReturns), i);

     329               0 :          bReturnNumOK = (returnnum == numreturns);

     330                 :       }
     331                 :    }
     332                 : 
     333          295490 :    return bReturnNumOK && bClassificationOK;

     334                 : 
     335                 : }
     336                 : 
     337                 : 
     338                 : template<typename DTYPE>
     339               2 : CPLErr   MG4LidarRasterBand::doReadBlock(int nBlockXOff, int nBlockYOff, void * pImage)

     340                 : {
     341               2 :    MG4LidarDataset * poGDS = (MG4LidarDataset *)poDS;

     342               2 :    MG4PointReader *reader =poGDS->reader;

     343                 : 
     344                 :    struct Accumulator_t
     345                 :    {
     346                 :       DTYPE value;
     347                 :       int count;
     348                 :    } ;
     349               2 :    Accumulator_t * Accumulator = NULL;

     350               2 :    if (EQUAL(Aggregation, "Mean"))

     351                 :    {
     352               2 :       Accumulator = new Accumulator_t[nBlockXSize*nBlockYSize];

     353               2 :       memset (Accumulator, 0, sizeof(Accumulator_t)*nBlockXSize*nBlockYSize);

     354                 :    }
     355             688 :    for (int i = 0; i < nBlockXSize; i++)

     356                 :    {
     357          247117 :       for (int j = 0; j < nBlockYSize; j++)

     358                 :       {
     359          246431 :          static_cast<DTYPE*>(pImage)[i*nBlockYSize+j] = static_cast<DTYPE>(nodatavalue);

     360                 :       }
     361                 :    }
     362                 : 
     363                 :    double geoTrans[6];
     364               2 :    poGDS->GetGeoTransform(geoTrans);   

     365               2 :    double xres = geoTrans[1];

     366               2 :    double yres = geoTrans[5];

     367                 : 
     368                 :    // Get the extent of the requested block.
     369               2 :    double xmin = geoTrans[0] + (nBlockXOff *nBlockXSize* xres);

     370               2 :    double xmax = xmin + nBlockXSize* xres;

     371               2 :    double ymax = reader->getBounds().y.max - (nBlockYOff * nBlockYSize* -yres);

     372               2 :    double ymin = ymax - nBlockYSize* -yres;

     373               2 :    Bounds bounds(xmin, xmax,  ymin, ymax, -HUGE_VAL, +HUGE_VAL); 

     374               2 :    PointData pointdata;

     375               2 :    pointdata.init(reader->getPointInfo(), 4096);

     376               2 :    double fraction = 1.0/pow(RESOLUTION_RATIO, poGDS->iLevel);

     377               2 :    CPLDebug( "MG4Lidar", "IReadBlock(x=%d y=%d, level=%d, fraction=%f)", nBlockXOff, nBlockYOff, poGDS->iLevel, fraction);

     378               2 :    Scoped<PointIterator> iter(reader->createIterator(bounds, fraction, reader->getPointInfo(), NULL));

     379                 : 
     380               2 :    const double * x = pointdata.getX();

     381               2 :    const double * y = pointdata.getY();

     382                 :    size_t nPoints;
     383              78 :    while ( (nPoints = iter->getNextPoints(pointdata)) != 0)

     384                 :    {
     385          295564 :       for( size_t i = 0; i < nPoints; i++ )

     386                 :       {
     387          295490 :          const ChannelData * channel = pointdata.getChannel(ChannelName);

     388          295490 :          if (papszFilterClassCodes || papszFilterReturnNums)

     389                 :          {
     390          295490 :             if (!ElementPassesFilter(pointdata, i))

     391          183357 :                continue;

     392                 :          }
     393          112133 :          double col = (x[i] - xmin) / xres;

     394          112133 :          double row = (ymax - y[i]) / -yres;

     395          112133 :          col = floor (col);

     396          112133 :          row = floor (row);

     397                 : 
     398          112133 :          if (row < 0) 

     399               0 :             row = 0;

     400          112133 :          else if (row >= nBlockYSize) 

     401               0 :             row = nBlockYSize - 1;

     402          112133 :          if (col < 0) 

     403               0 :             col = 0;

     404          112133 :          else if (col >= nBlockXSize ) 

     405               1 :             col = nBlockXSize - 1;

     406                 : 
     407          112133 :          int iCol = (int) (col);

     408          112133 :          int iRow = (int) (row);

     409          112133 :          const int offset =iRow* nBlockXSize + iCol;

     410          112133 :          if (EQUAL(Aggregation, "Max"))

     411                 :          {
     412               0 :             DTYPE value = GetChannelElement<DTYPE>(*channel, i);

     413               0 :             if (static_cast<DTYPE *>(pImage)[offset] == static_cast<DTYPE>(nodatavalue) ||

     414                 :                static_cast<DTYPE *>(pImage)[offset] < value)
     415               0 :                static_cast<DTYPE *>(pImage)[offset] = value;

     416                 :          }
     417          112133 :          else if (EQUAL(Aggregation, "Min"))

     418                 :          {
     419               0 :             DTYPE value = GetChannelElement<DTYPE>(*channel, i);

     420               0 :             if (static_cast<DTYPE *>(pImage)[offset] == static_cast<DTYPE>(nodatavalue) ||

     421                 :                static_cast<DTYPE *>(pImage)[offset] > value)
     422               0 :                static_cast<DTYPE *>(pImage)[offset] = value;

     423                 :          }
     424          112133 :          else if (EQUAL(Aggregation, "Mean"))

     425                 :          {
     426          112133 :             DTYPE value = GetChannelElement<DTYPE>(*channel, i);

     427          112133 :             Accumulator[offset].count++;

     428          112133 :             Accumulator[offset].value += value;

     429          112133 :             static_cast<DTYPE*>(pImage)[offset] = static_cast<DTYPE>(Accumulator[offset].value / Accumulator[offset].count);

     430                 :          }
     431                 :       }
     432                 :    }
     433                 :    
     434               2 :    delete[] Accumulator;

     435               2 :    return CE_None;

     436                 : }
     437                 : 
     438               2 : double MG4LidarRasterBand::getMaxValue()

     439                 : {
     440                 :    double retval;
     441               2 :    switch(eDataType)

     442                 :    {
     443                 :       #define DO_CASE(gdt, largestvalue)  case (gdt):\
     444                 :          retval = static_cast<double>(largestvalue); \
     445                 :          break;
     446                 :          
     447               0 :       DO_CASE (GDT_Float64, DBL_MAX);

     448               2 :       DO_CASE (GDT_Float32, FLT_MAX);

     449               0 :       DO_CASE (GDT_Int32, INT_MAX);

     450               0 :       DO_CASE (GDT_UInt32, UINT_MAX);

     451               0 :       DO_CASE (GDT_Int16, SHRT_MAX);

     452               0 :       DO_CASE (GDT_UInt16, USHRT_MAX);

     453               0 :       DO_CASE (GDT_Byte, UCHAR_MAX);

     454                 :       #undef DO_CASE 
     455                 :        default:
     456               0 :            retval = 0;

     457                 :            break;
     458                 :    }
     459               2 :    return retval;

     460                 : }
     461                 : /************************************************************************/
     462                 : /*                             IReadBlock()                             */
     463                 : /************************************************************************/
     464                 : 
     465                 : CPLErr MG4LidarRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     466               2 :                                       void * pImage )

     467                 : {
     468                 :    CPLErr eErr;
     469               2 :    switch(eDataType)

     470                 :    {
     471                 : #define DO_CASE(gdt, nativedt)  case (gdt):\
     472                 :    eErr = doReadBlock<nativedt>(nBlockXOff, nBlockYOff, pImage); \
     473                 :    break;
     474                 : 
     475               0 :       DO_CASE (GDT_Float64, double);

     476               2 :       DO_CASE (GDT_Float32, float);

     477               0 :       DO_CASE (GDT_Int32, long);

     478               0 :       DO_CASE (GDT_UInt32, unsigned long);

     479               0 :       DO_CASE (GDT_Int16, short);

     480               0 :       DO_CASE (GDT_UInt16, unsigned short);

     481               0 :       DO_CASE (GDT_Byte, char);

     482                 : #undef DO_CASE 
     483                 :       default:
     484               0 :            return CE_Failure;

     485                 :            break;
     486                 : 
     487                 :    }
     488               2 :    return CE_None;

     489                 : }
     490                 : 
     491                 : /************************************************************************/
     492                 : /*                           GetStatistics()                            */
     493                 : /************************************************************************/
     494                 : 
     495                 : CPLErr MG4LidarRasterBand::GetStatistics( int bApproxOK, int bForce,
     496                 :                                          double *pdfMin, double *pdfMax, 
     497               0 :                                          double *pdfMean, double *pdfStdDev )

     498                 : 
     499                 : {
     500               0 :    bApproxOK = TRUE; 

     501               0 :    bForce = TRUE;

     502                 : 
     503                 :    return GDALPamRasterBand::GetStatistics( bApproxOK, bForce, 
     504                 :       pdfMin, pdfMax, 
     505               0 :       pdfMean, pdfStdDev );   

     506                 : 
     507                 : }
     508                 : /************************************************************************/
     509                 : /*                           GetNoDataValue()                           */
     510                 : /************************************************************************/
     511                 : 
     512               0 : double MG4LidarRasterBand::GetNoDataValue( int *pbSuccess )

     513                 : {
     514               0 :    if (pbSuccess)

     515               0 :        *pbSuccess = TRUE;

     516               0 :    return nodatavalue;

     517                 : }
     518                 : 
     519                 : 
     520                 : /************************************************************************/
     521                 : /*                            MG4LidarDataset()                             */
     522                 : /************************************************************************/
     523               2 : MG4LidarDataset::MG4LidarDataset()

     524                 : {
     525               2 :    reader = NULL;

     526                 : 
     527               2 :    poXMLPCView = NULL;

     528               2 :    nOverviewCount = 0;

     529               2 :    papoOverviewDS = NULL;

     530                 : 
     531               2 : }

     532                 : /************************************************************************/
     533                 : /*                            ~MG4LidarDataset()                             */
     534                 : /************************************************************************/
     535                 : 
     536               2 : MG4LidarDataset::~MG4LidarDataset()

     537                 : 
     538                 : {
     539               2 :    FlushCache();

     540               2 :    if ( papoOverviewDS )

     541                 :    {
     542               2 :       for( int i = 0; i < nOverviewCount; i++ )

     543               1 :          delete papoOverviewDS[i];

     544               1 :       CPLFree( papoOverviewDS );

     545                 :    }
     546                 :    else
     547                 :    {
     548               1 :       CPLDestroyXMLNode(poXMLPCView);

     549               1 :       RELEASE(reader);

     550                 :    }
     551               2 : }

     552                 : 
     553                 : /************************************************************************/
     554                 : /*                          GetGeoTransform()                           */
     555                 : /************************************************************************/
     556                 : 
     557               3 : CPLErr MG4LidarDataset::GetGeoTransform( double * padfTransform )

     558                 : 
     559                 : {
     560               3 :    padfTransform[0] = reader->getBounds().x.min ;// Upper left X, Y

     561               3 :    padfTransform[3] = reader->getBounds().y.max; // 

     562               3 :    padfTransform[1] = reader->getBounds().x.length()/GetRasterXSize(); //xRes

     563               3 :    padfTransform[2] = 0.0;

     564                 : 
     565               3 :    padfTransform[4] = 0.0;

     566               3 :    padfTransform[5] = -1 * reader->getBounds().y.length()/GetRasterYSize(); //yRes

     567                 : 
     568               3 :    return CE_None;

     569                 : }
     570                 : 
     571                 : /************************************************************************/
     572                 : /*                          GetProjectionRef()                          */
     573                 : /************************************************************************/
     574                 : 
     575               1 : const char *MG4LidarDataset::GetProjectionRef()

     576                 : 
     577                 : {
     578               1 :    const char * wkt = CPLGetXMLValue(poXMLPCView, "GeoReference", NULL);

     579               1 :    if (wkt == NULL)

     580               1 :       wkt = reader->getWKT(); 

     581               1 :    return(wkt);

     582                 : }
     583                 : 
     584                 : /************************************************************************/
     585                 : /*                             OpenZoomLevel()                          */
     586                 : /************************************************************************/
     587                 : 
     588               2 : CPLErr MG4LidarDataset::OpenZoomLevel( int iZoom )

     589                 : {
     590                 :    /* -------------------------------------------------------------------- */
     591                 :    /*      Get image geometry.                                            */
     592                 :    /* -------------------------------------------------------------------- */
     593               2 :    iLevel = iZoom;

     594                 : 
     595                 :    // geo dimensions
     596               2 :    const double gWidth = reader->getBounds().x.length() ;

     597               2 :    const double gHeight = reader->getBounds().y.length() ;

     598                 : 
     599                 :    // geo res
     600               2 :    double xRes = pow(RESOLUTION_RATIO, iZoom) * gWidth / MaxRasterSize ;

     601               2 :    double yRes = pow(RESOLUTION_RATIO, iZoom) * gHeight / MaxRasterSize ;

     602               2 :    xRes = yRes = MAX(xRes, yRes);

     603                 : 
     604                 :    // pixel dimensions
     605               2 :    nRasterXSize  = static_cast<int>(gWidth / xRes  + 0.5);

     606               2 :    nRasterYSize  = static_cast<int>(gHeight / yRes + 0.5);

     607                 : 
     608               2 :    nBlockXSize = static_cast<int>(MIN(MaxBlockSideSize , GetRasterXSize()));

     609               2 :    nBlockYSize = static_cast<int>(MIN(MaxBlockSideSize , GetRasterYSize())); 

     610                 : 
     611                 :    CPLDebug( "MG4Lidar", "Opened zoom level %d with size %dx%d.\n",
     612               2 :       iZoom, nRasterXSize, nRasterYSize );

     613                 : 
     614                 : 
     615                 : 
     616                 :    /* -------------------------------------------------------------------- */
     617                 :    /*  Handle sample type and color space.                                 */
     618                 :    /* -------------------------------------------------------------------- */
     619                 :    //eColorSpace = poImageReader->getColorSpace();
     620                 :    /* -------------------------------------------------------------------- */
     621                 :    /*      Create band information objects.                                */
     622                 :    /* -------------------------------------------------------------------- */
     623               2 :    size_t BandCount = 0;

     624               2 :    CPLXMLNode* xmlBand = poXMLPCView;

     625               2 :    bool bClass = false;

     626               2 :    bool bNumRets = false;

     627               2 :    bool bRetNum = false;

     628               6 :    while ((xmlBand = CPLSearchXMLNode(xmlBand, "Band")) != NULL)

     629                 :    {
     630               2 :       CPLXMLNode * xmlChannel = CPLSearchXMLNode(xmlBand, "Channel");

     631               2 :       const char * name = "Z";

     632               2 :       if (xmlChannel && xmlChannel->psChild && xmlChannel->psChild->pszValue)

     633               2 :          name = xmlChannel->psChild->pszValue;

     634                 :       
     635               2 :       BandCount++;

     636               2 :       MG4LidarRasterBand *band = new MG4LidarRasterBand(this, BandCount, xmlBand, name);

     637               2 :       SetBand(BandCount, band);

     638               4 :       if (band->papszFilterClassCodes) bClass = true;

     639               2 :       if (band->papszFilterReturnNums) bNumRets = true;

     640               2 :       if (bNumRets && CSLFindString(band->papszFilterReturnNums, "Last")) bRetNum = true;

     641               2 :       xmlBand = xmlBand->psNext;

     642                 :    }
     643               2 :    nBands = BandCount;

     644               2 :    int nSDKChannels = BandCount + (bClass ? 1 : 0) + (bNumRets ? 1 : 0) + (bRetNum ? 1 : 0);

     645               2 :    if (BandCount == 0)  // default if no bands specified.

     646                 :    {
     647               0 :       MG4LidarRasterBand *band = new MG4LidarRasterBand(this, 1, NULL, CHANNEL_NAME_Z);

     648               0 :       SetBand(1, band);

     649               0 :       nBands = 1;

     650               0 :       nSDKChannels = 1;

     651                 :    }
     652               2 :    requiredChannels.init(nSDKChannels);

     653               2 :    const ChannelInfo *ci = NULL;

     654               4 :    for (int i=0; i<nBands; i++)

     655                 :    {
     656               2 :       ci = reader->getChannel(dynamic_cast<MG4LidarRasterBand*>(papoBands[i])->ChannelName);

     657               2 :       requiredChannels.getChannel(i).init(*ci);

     658                 :    }
     659               2 :    int iSDKChannels = nBands;

     660               2 :    if (bClass)

     661                 :    {
     662               2 :       ci = reader->getChannel(CHANNEL_NAME_ClassId);

     663               2 :       requiredChannels.getChannel(iSDKChannels++).init(*ci);

     664                 :    }
     665               2 :    if (bRetNum)

     666                 :    {
     667               0 :       ci = reader->getChannel(CHANNEL_NAME_ReturnNum);

     668               0 :       requiredChannels.getChannel(iSDKChannels++).init(*ci);

     669                 :    }
     670               2 :    if (bNumRets)

     671                 :    {
     672               0 :       ci = reader->getChannel(CHANNEL_NAME_NumReturns);

     673               0 :       requiredChannels.getChannel(iSDKChannels++).init(*ci);

     674                 :    }
     675                 : 
     676               2 :    return CE_None;

     677                 : }
     678                 : 
     679                 : /************************************************************************/
     680                 : /*                                Open()                                */
     681                 : /************************************************************************/
     682                 : 
     683           10192 : GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo )

     684                 : 
     685                 : {
     686                 : #ifdef notdef
     687                 :    CPLPushErrorHandler( CPLLoggingErrorHandler );
     688                 :    CPLSetConfigOption( "CPL_DEBUG", "ON" );
     689                 :    CPLSetConfigOption( "CPL_LOG", "C:\\ArcGIS_GDAL\\jdem\\cpl.log" );
     690                 : #endif
     691           10192 :    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 50 )

     692            9579 :       return NULL;

     693             613 :    if( strstr((const char *) poOpenInfo->pabyHeader, "<PointCloudView" ) == NULL )

     694             612 :       return NULL;

     695                 : 
     696                 :    CPLXMLNode *pxmlPCView, *psInputFile;
     697               1 :    pxmlPCView = CPLParseXMLFile( poOpenInfo->pszFilename );

     698               1 :    if (pxmlPCView == NULL)

     699               0 :        return NULL;

     700                 : 
     701               1 :    psInputFile = CPLGetXMLNode( pxmlPCView, "InputFile" );

     702               1 :    if( psInputFile == NULL )

     703                 :    {
     704                 :       CPLError( CE_Failure, CPLE_OpenFailed, 
     705               0 :          "Failed to find <InputFile> in document." );

     706               0 :       CPLDestroyXMLNode(pxmlPCView);

     707               0 :       return NULL;

     708                 :    }
     709               1 :    CPLString sidInputName(psInputFile->psChild->pszValue);

     710               1 :    if (CPLIsFilenameRelative(sidInputName))

     711                 :    {
     712               1 :       CPLString dirname(CPLGetDirname(poOpenInfo->pszFilename));

     713               1 :       sidInputName = CPLString(CPLFormFilename(dirname, sidInputName, NULL));

     714                 :    }
     715               1 :    GDALOpenInfo openinfo(sidInputName, GA_ReadOnly);

     716                 : 
     717                 :    /* -------------------------------------------------------------------- */
     718                 :    /*      Check that particular fields in the header are valid looking    */
     719                 :    /*      dates.                                                          */
     720                 :    /* -------------------------------------------------------------------- */
     721               1 :    if( openinfo.fp == NULL || openinfo.nHeaderBytes < 50 )

     722                 :    {
     723               0 :       CPLDestroyXMLNode(pxmlPCView);

     724               1 :       return NULL;

     725                 :    }
     726                 : 
     727                 :    /* check magic */
     728                 :    // to do:  SDK should provide an API for this.
     729               1 :    if(  !EQUALN((const char *) openinfo.pabyHeader, "msid", 4)

     730                 :       || (*(openinfo.pabyHeader+4) != 0x4 )) // Generation 4.  ... is there more we can check?
     731                 :    {
     732               0 :       CPLDestroyXMLNode(pxmlPCView);

     733               0 :       return NULL;

     734                 :    }
     735                 : 
     736                 :    /* -------------------------------------------------------------------- */
     737                 :    /*      Create a corresponding GDALDataset.                             */
     738                 :    /* -------------------------------------------------------------------- */
     739                 :    MG4LidarDataset  *poDS;
     740                 : 
     741               1 :    poDS = new MG4LidarDataset();

     742               1 :    poDS->poXMLPCView = pxmlPCView;

     743               2 :    poDS->reader = CropableMG4PointReader::create();

     744               1 :    const char * pszClipExtent = CPLGetXMLValue(pxmlPCView, "ClipBox", NULL);

     745               1 :    MG4PointReader *r = MG4PointReader::create();

     746               1 :    r->init(openinfo.pszFilename);

     747               1 :    Bounds bounds = r->getBounds();

     748               1 :    if (pszClipExtent)

     749                 :    {
     750               0 :       char ** papszClipExtent = CSLTokenizeString(pszClipExtent);

     751               0 :       int cslcount = CSLCount(papszClipExtent);

     752               0 :       if (cslcount != 4 && cslcount != 6)

     753                 :       {
     754                 :          CPLError( CE_Failure, CPLE_OpenFailed, 
     755               0 :             "Invalid ClipBox.  Must contain 4 or 6 floats." );

     756               0 :          CSLDestroy(papszClipExtent);

     757               0 :          delete poDS;

     758               0 :          RELEASE(r);

     759               0 :          return NULL;

     760                 :       }
     761               0 :       if (!EQUAL(papszClipExtent[0], "NOFILTER"))

     762               0 :          bounds.x.min = atof(papszClipExtent[0]);

     763               0 :       if (!EQUAL(papszClipExtent[1], "NOFILTER"))

     764               0 :          bounds.x.max = atof(papszClipExtent[1]);

     765               0 :       if (!EQUAL(papszClipExtent[2], "NOFILTER"))

     766               0 :          bounds.y.min = atof(papszClipExtent[2]);

     767               0 :       if (!EQUAL(papszClipExtent[3], "NOFILTER"))

     768               0 :          bounds.y.max = atof(papszClipExtent[3]);

     769               0 :       if (cslcount == 6)

     770                 :       {
     771               0 :          if (!EQUAL(papszClipExtent[4], "NOFILTER"))

     772               0 :             bounds.z.min = atof(papszClipExtent[4]);

     773               0 :          if (!EQUAL(papszClipExtent[5], "NOFILTER"))

     774               0 :             bounds.z.max = atof(papszClipExtent[5]);

     775                 :       }
     776               0 :       CSLDestroy(papszClipExtent);

     777                 :    }
     778                 : 
     779               1 :    dynamic_cast<CropableMG4PointReader *>(poDS->reader)->init(openinfo.pszFilename, &bounds);

     780               1 :    poDS->SetDescription(poOpenInfo->pszFilename);

     781               1 :    poDS->TryLoadXML(); 

     782                 : 
     783               1 :    double pts_per_area = ((double)r->getNumPoints())/(r->getBounds().x.length()*r->getBounds().y.length());

     784               1 :    double average_pt_spacing = sqrt(1.0 / pts_per_area) ;

     785               1 :    double cell_side = average_pt_spacing;

     786               1 :    const char * pszCellSize = CPLGetXMLValue(pxmlPCView, "CellSize", NULL);

     787               1 :    if (pszCellSize)

     788               0 :       cell_side = atof(pszCellSize);

     789               1 :    MaxRasterSize = MAX(poDS->reader->getBounds().x.length()/cell_side, poDS->reader->getBounds().y.length()/cell_side);

     790                 : 
     791               1 :    RELEASE(r);

     792                 : 
     793                 :    // Calculate the number of levels to expose.  The highest level correpsonds to a
     794                 :    // raster size of 256 on the longest side.
     795               1 :    double blocksizefactor = MaxRasterSize/256.0;

     796               1 :    poDS->nOverviewCount = (int)(log(blocksizefactor)/log(RESOLUTION_RATIO) + 0.5);

     797               1 :    if ( poDS->nOverviewCount > 0 )

     798                 :    {
     799                 :       int i;
     800                 : 
     801                 :       poDS->papoOverviewDS = (MG4LidarDataset **)
     802               1 :          CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) );

     803                 : 
     804               2 :       for ( i = 0; i < poDS->nOverviewCount; i++ )

     805                 :       {
     806               1 :          poDS->papoOverviewDS[i] = new MG4LidarDataset ();

     807               1 :          poDS->papoOverviewDS[i]->reader = poDS->reader;

     808               2 :          poDS->papoOverviewDS[i]->SetMetadata(poDS->GetMetadata("MG4Lidar"), "MG4Lidar");

     809               1 :          poDS->papoOverviewDS[i]->poXMLPCView = pxmlPCView;

     810               1 :          poDS->papoOverviewDS[i]->OpenZoomLevel( i+1 );

     811                 :       }       
     812                 :    }
     813                 : 
     814                 :    /* -------------------------------------------------------------------- */
     815                 :    /*      Create object for the whole image.                              */
     816                 :    /* -------------------------------------------------------------------- */
     817               1 :    poDS->OpenZoomLevel( 0 );

     818                 : 
     819                 :    CPLDebug( "MG4Lidar",
     820                 :       "Opened image: width %d, height %d, bands %d",
     821               1 :       poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands );

     822                 : 
     823               1 :    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))

     824                 :    {
     825               0 :        delete poDS;

     826               0 :        return NULL;

     827                 :    }
     828                 : 
     829               1 :    if (! ((poDS->nBands == 1) || (poDS->nBands == 3)))

     830                 :    {
     831                 :       CPLDebug( "MG4Lidar",
     832               0 :          "Inappropriate number of bands (%d)", poDS->nBands );

     833               0 :       delete poDS;

     834               0 :       return(NULL);

     835                 :    }
     836                 : 
     837               1 :    return( poDS );

     838                 : }
     839                 : 
     840                 : /************************************************************************/
     841                 : /*                          GDALRegister_MG4Lidar()                        */
     842                 : /************************************************************************/
     843                 : 
     844             409 : void GDALRegister_MG4Lidar()

     845                 : 
     846                 : {
     847                 :    GDALDriver *poDriver;
     848                 : 
     849             409 :     if (! GDAL_CHECK_VERSION("MG4Lidar driver"))

     850               0 :         return;

     851                 : 
     852             409 :    if( GDALGetDriverByName( "MG4Lidar" ) == NULL )

     853                 :    {
     854             392 :       poDriver = new GDALDriver();

     855                 : 
     856             392 :       poDriver->SetDescription( "MG4Lidar" );

     857                 :       poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     858             392 :          "MrSID Generation 4 / Lidar (.sid)" );

     859                 :       // To do:  update this help file in gdal.org
     860                 :       poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     861             392 :          "frmt_mrsid_lidar.html" );

     862                 : 
     863             392 :       poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "view" );

     864                 :       poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
     865             392 :          "Float64" );

     866                 : 
     867             392 :       poDriver->pfnOpen = MG4LidarDataset::Open;

     868                 : 
     869             392 :       GetGDALDriverManager()->RegisterDriver( poDriver );

     870                 :    }
     871                 : }

Generated by: LTP GCOV extension version 1.5