LCOV - code coverage report
Current view: directory - frmts/mrsid_lidar - gdal_MG4Lidar.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 403 275 68.2 %
Date: 2011-12-18 Functions: 44 20 45.5 %

       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 "lidar/Version.h"
      40                 : #include <float.h>
      41                 : LT_USE_LIDAR_NAMESPACE
      42                 : 
      43                 : #include "gdal_pam.h"
      44                 : // #include "gdal_alg.h" // 1.6 and later have gridding algorithms
      45                 : 
      46                 : CPL_C_START
      47                 : //void __declspec(dllexport) GDALRegister_MG4Lidar(void);
      48                 : void CPL_DLL GDALRegister_MG4Lidar(void);
      49                 : CPL_C_END
      50                 : 
      51                 : /************************************************************************/
      52                 : /* ==================================================================== */
      53                 : /*        MG4LidarDataset       */
      54                 : /* ==================================================================== */
      55                 : /************************************************************************/
      56                 : 
      57                 : // Resolution Ratio between adjacent levels.
      58                 : #define RESOLUTION_RATIO 2.0
      59                 : 
      60                 : class MG4LidarRasterBand;
      61                 : class CropableMG4PointReader : public MG4PointReader
      62                 : {
      63                 :    CONCRETE_OBJECT(CropableMG4PointReader);
      64               1 :    void init (const char *path, Bounds *bounds)
      65                 :    {
      66               1 :       MG4PointReader::init(path);
      67               1 :       if (bounds != NULL)
      68               1 :          setBounds(*bounds);
      69               1 :    }
      70                 : };
      71               1 : CropableMG4PointReader::CropableMG4PointReader() : MG4PointReader() {};   
      72               1 : CropableMG4PointReader::~CropableMG4PointReader() {};   
      73                 : 
      74               1 : IMPLEMENT_OBJECT_CREATE(CropableMG4PointReader);
      75                 : 
      76                 : static double MaxRasterSize = 2048.0;
      77                 : static double MaxBlockSideSize = 1024.0;
      78                 : class MG4LidarDataset : public GDALPamDataset
      79                 : {
      80                 : friend class MG4LidarRasterBand;
      81                 : public:
      82                 :    MG4LidarDataset();
      83                 :    ~MG4LidarDataset();
      84                 :    static GDALDataset *Open( GDALOpenInfo * );
      85                 :    CPLErr   GetGeoTransform( double * padfTransform );
      86                 :    const char *GetProjectionRef();
      87                 : protected:
      88                 :    MG4PointReader *reader;
      89                 :    CPLErr OpenZoomLevel( int Zoom );
      90                 :    PointInfo requiredChannels;
      91                 :    int nOverviewCount;
      92                 :    MG4LidarDataset **papoOverviewDS;
      93                 :    CPLXMLNode *poXMLPCView;
      94                 :    bool ownsXML;
      95                 :    int nBlockXSize, nBlockYSize;
      96                 :    int iLevel;
      97                 : };
      98                 : 
      99                 : /* ========================================  */
     100                 : /*                            MG4LidarRasterBand                                          */
     101                 : /* ========================================  */
     102                 : 
     103                 : class MG4LidarRasterBand : public GDALPamRasterBand
     104                 : {
     105                 :    friend class MG4LidarDataset;
     106                 : 
     107                 : public:
     108                 : 
     109                 :    MG4LidarRasterBand( MG4LidarDataset *, int, CPLXMLNode *, const char * );
     110                 :    ~MG4LidarRasterBand();
     111                 : 
     112                 :    virtual CPLErr GetStatistics( int bApproxOK, int bForce, double *pdfMin, double *pdfMax, double *pdfMean, double *padfStdDev );
     113                 :    virtual int GetOverviewCount();
     114                 :    virtual GDALRasterBand * GetOverview( int i );
     115                 :    virtual CPLErr IReadBlock( int, int, void * );
     116                 :    virtual double GetNoDataValue( int *pbSuccess = NULL );
     117                 : 
     118                 :    protected:
     119                 :    double getMaxValue();
     120                 :    double nodatavalue;
     121                 :    virtual const bool ElementPassesFilter(const PointData &, size_t);
     122                 :    template<typename DTYPE>
     123                 :    CPLErr   doReadBlock(int, int, void *);
     124                 :    CPLXMLNode *poxmlBand;
     125                 :    char **papszFilterClassCodes;
     126                 :    char **papszFilterReturnNums;
     127                 :    const char * Aggregation;
     128                 :    CPLString ChannelName;
     129                 : };
     130                 : 
     131                 : 
     132                 : /************************************************************************/
     133                 : /*                           MG4LidarRasterBand()                            */
     134                 : /************************************************************************/
     135                 : 
     136               2 : MG4LidarRasterBand::MG4LidarRasterBand( MG4LidarDataset *pods, int nband, CPLXMLNode *xmlBand, const char * name )
     137                 : {
     138               2 :    this->poDS = pods;
     139               2 :    this->nBand = nband;
     140               2 :    this->poxmlBand = xmlBand;
     141               2 :    this->ChannelName = name;
     142               2 :    this->Aggregation = NULL;
     143               2 :    nBlockXSize = pods->nBlockXSize;
     144               2 :    nBlockYSize = pods->nBlockYSize;
     145                 : 
     146               2 :    switch(pods->reader->getChannel(name)->getDataType())
     147                 :    {
     148                 : #define DO_CASE(ltdt, gdt) case (ltdt): eDataType = gdt; break;
     149               2 :       DO_CASE(DATATYPE_FLOAT64, GDT_Float64);
     150               0 :       DO_CASE(DATATYPE_FLOAT32, GDT_Float32);
     151               0 :       DO_CASE(DATATYPE_SINT32, GDT_Int32);
     152               0 :       DO_CASE(DATATYPE_UINT32, GDT_UInt32);
     153               0 :       DO_CASE(DATATYPE_SINT16, GDT_Int16);
     154               0 :       DO_CASE(DATATYPE_UINT16, GDT_UInt16);
     155               0 :       DO_CASE(DATATYPE_SINT8, GDT_Byte);
     156               0 :       DO_CASE(DATATYPE_UINT8, GDT_Byte);
     157                 : default:
     158                 :    CPLError(CE_Failure, CPLE_AssertionFailed,
     159               0 :       "Invalid datatype in MG4 file");
     160                 :    break;
     161                 : #undef DO_CASE      
     162                 :    }
     163                 :    // Coerce datatypes as required.
     164               2 :    const char * ForceDataType =  CPLGetXMLValue(pods->poXMLPCView, "Datatype", NULL);
     165                 : 
     166               2 :    if (ForceDataType != NULL)
     167                 :    {
     168               2 :       GDALDataType dt = GDALGetDataTypeByName(ForceDataType);
     169               2 :       if (dt != GDT_Unknown)
     170               2 :          eDataType = dt;
     171                 :    }
     172                 : 
     173               2 :    CPLXMLNode *poxmlFilter = CPLGetXMLNode(poxmlBand, "ClassificationFilter");
     174               2 :    if( poxmlFilter == NULL )
     175               0 :       poxmlFilter = CPLGetXMLNode(pods->poXMLPCView, "ClassificationFilter");
     176               2 :    if (poxmlFilter == NULL || poxmlFilter->psChild == NULL ||
     177                 :        poxmlFilter->psChild->pszValue == NULL)
     178               0 :       papszFilterClassCodes = NULL;
     179                 :    else
     180               2 :       papszFilterClassCodes = CSLTokenizeString(poxmlFilter->psChild->pszValue);
     181                 : 
     182               2 :    poxmlFilter = CPLGetXMLNode(poxmlBand, "ReturnNumberFilter");
     183               2 :    if( poxmlFilter == NULL )
     184               2 :       poxmlFilter = CPLGetXMLNode(pods->poXMLPCView, "ReturnNumberFilter");
     185               4 :    if (poxmlFilter == NULL || poxmlFilter->psChild == NULL ||
     186                 :        poxmlFilter->psChild->pszValue == NULL)
     187               2 :       papszFilterReturnNums = NULL;
     188                 :    else
     189               0 :       papszFilterReturnNums = CSLTokenizeString(poxmlFilter->psChild->pszValue);
     190                 : 
     191                 :    
     192               2 :    CPLXMLNode * poxmlAggregation = CPLGetXMLNode(poxmlBand, "AggregationMethod");
     193               2 :    if( poxmlAggregation == NULL )
     194               2 :       poxmlAggregation = CPLGetXMLNode(pods->poXMLPCView, "AggregationMethod");
     195               4 :    if (poxmlAggregation == NULL || poxmlAggregation->psChild == NULL ||
     196                 :        poxmlAggregation->psChild->pszValue == NULL)
     197               2 :       Aggregation = "Mean";
     198                 :    else
     199               0 :       Aggregation = poxmlAggregation->psChild->pszValue;
     200                 : 
     201               2 :    nodatavalue = getMaxValue();
     202                 : 
     203               2 :    CPLXMLNode * poxmlIntepolation = CPLGetXMLNode(poxmlBand, "InterpolationMethod");
     204               2 :    if( poxmlIntepolation == NULL )
     205               2 :       poxmlIntepolation = CPLGetXMLNode(pods->poXMLPCView, "InterpolationMethod");
     206               2 :    if (poxmlIntepolation != NULL )
     207                 :    {
     208               0 :       CPLXMLNode * poxmlMethod= NULL;
     209               0 :       char ** papszParams = NULL;
     210               0 :       if (((poxmlMethod = CPLSearchXMLNode(poxmlIntepolation, "None")) != NULL) &&
     211                 :           poxmlMethod->psChild != NULL && poxmlMethod->psChild->pszValue != NULL)
     212                 :       {
     213               0 :          papszParams = CSLTokenizeString(poxmlMethod->psChild->pszValue);
     214               0 :          if (!EQUAL(papszParams[0], "MAX"))
     215               0 :             nodatavalue = atof(papszParams[0]);
     216                 :       }
     217                 :       // else if .... Add support for other interpolation methods here.
     218               0 :       CSLDestroy(papszParams);
     219                 :    }
     220               2 :    const char * filter = NULL;
     221               2 :    if (papszFilterClassCodes != NULL && papszFilterReturnNums != NULL)
     222               0 :       filter ="Classification and Return";
     223               2 :    if (papszFilterClassCodes != NULL)
     224               2 :       filter = "Classification";
     225               0 :    else if (papszFilterReturnNums != NULL)
     226               0 :       filter = "Return";
     227               2 :    CPLString osDesc;
     228               2 :    if (filter)
     229               2 :       osDesc.Printf("%s of %s (filtered by %s)", Aggregation, ChannelName.c_str(), filter);
     230                 :    else
     231               0 :       osDesc.Printf("%s of %s", Aggregation, ChannelName.c_str());
     232               2 :    SetDescription(osDesc);
     233               2 : }
     234                 : 
     235                 : /************************************************************************/
     236                 : /*                          ~MG4LidarRasterBand()                            */
     237                 : /************************************************************************/
     238               2 : MG4LidarRasterBand::~MG4LidarRasterBand()
     239                 : {
     240               2 :    CSLDestroy(papszFilterClassCodes);
     241               2 :    CSLDestroy(papszFilterReturnNums);
     242               2 : }
     243                 : 
     244                 : /************************************************************************/
     245                 : /*                          GetOverviewCount()                          */
     246                 : /************************************************************************/
     247                 : 
     248               0 : int MG4LidarRasterBand::GetOverviewCount()
     249                 : {
     250               0 :    MG4LidarDataset *poGDS = (MG4LidarDataset *) poDS;
     251               0 :    return poGDS->nOverviewCount;
     252                 : }
     253                 : 
     254                 : /************************************************************************/
     255                 : /*                            GetOverview()                             */
     256                 : /************************************************************************/
     257               1 : GDALRasterBand *MG4LidarRasterBand::GetOverview( int i )
     258                 : {
     259               1 :    MG4LidarDataset *poGDS = (MG4LidarDataset *) poDS;
     260                 : 
     261               1 :    if( i < 0 || i >= poGDS->nOverviewCount )
     262               0 :       return NULL;
     263                 :    else
     264               1 :       return poGDS->papoOverviewDS[i]->GetRasterBand( nBand );
     265                 : }
     266                 : template<typename DTYPE>
     267          407623 : const DTYPE GetChannelElement(const ChannelData &channel, size_t idx)
     268                 : {
     269          407623 :    DTYPE retval = static_cast<DTYPE>(0);
     270          407623 :    switch (channel.getDataType())
     271                 :    {
     272                 :    case (DATATYPE_FLOAT64):
     273          112133 :       retval = static_cast<DTYPE>(static_cast<const double*>(channel.getData())[idx]);
     274          112133 :       break;
     275                 :    case (DATATYPE_FLOAT32):
     276               0 :       retval = static_cast<DTYPE>(static_cast<const float *>(channel.getData())[idx]);
     277               0 :       break;
     278                 :    case (DATATYPE_SINT32):
     279               0 :       retval = static_cast<DTYPE>(static_cast<const long *>(channel.getData())[idx]);
     280               0 :       break;
     281                 :    case (DATATYPE_UINT32):
     282               0 :       retval = static_cast<DTYPE>(static_cast<const unsigned long *>(channel.getData())[idx]);
     283               0 :       break;
     284                 :    case (DATATYPE_SINT16):
     285               0 :       retval = static_cast<DTYPE>(static_cast<const short *>(channel.getData())[idx]);
     286               0 :       break;
     287                 :    case (DATATYPE_UINT16):
     288               0 :       retval = static_cast<DTYPE>(static_cast<const unsigned short *>(channel.getData())[idx]);
     289               0 :       break;
     290                 :    case (DATATYPE_SINT8):
     291               0 :       retval = static_cast<DTYPE>(static_cast<const char *>(channel.getData())[idx]);
     292               0 :       break;
     293                 :    case (DATATYPE_UINT8):
     294          295490 :       retval = static_cast<DTYPE>(static_cast<const unsigned char *>(channel.getData())[idx]);
     295          295490 :       break;
     296                 :    case (DATATYPE_SINT64):
     297               0 :       retval = static_cast<DTYPE>(static_cast<const GIntBig *>(channel.getData())[idx]);
     298               0 :       break;
     299                 :    case (DATATYPE_UINT64):
     300               0 :       retval = static_cast<DTYPE>(static_cast<const GUIntBig *>(channel.getData())[idx]);
     301                 :       break;
     302                 :    default:
     303                 :       break;
     304                 :    }
     305          407623 :    return retval;
     306                 : }
     307                 : 
     308                 : 
     309          295490 : const bool MG4LidarRasterBand::ElementPassesFilter(const PointData &pointdata, size_t i)
     310                 : {
     311          295490 :    bool bClassificationOK = true;
     312          295490 :    bool bReturnNumOK = true;
     313                 : 
     314                 :    // Check if classification code is ok:  it was requested and it does match one of the requested codes
     315          295490 :    const int classcode = GetChannelElement<int>(*pointdata.getChannel(CHANNEL_NAME_ClassId), i);
     316                 :    char bufCode[16];
     317          295490 :    sprintf(bufCode, "%d", classcode);
     318                 :    bClassificationOK = (papszFilterClassCodes == NULL ? true :
     319          295490 :       (CSLFindString(papszFilterClassCodes,bufCode)!=-1));
     320                 : 
     321          295490 :    if (bClassificationOK)
     322                 :    {
     323                 :       // Check if return num is ok:  it was requested and it does match one of the requested return numbers
     324          112133 :       const long returnnum= static_cast<const unsigned char *>(pointdata.getChannel(CHANNEL_NAME_ReturnNum)->getData())[i];
     325          112133 :       sprintf(bufCode, "%d", (int)returnnum);
     326                 :       bReturnNumOK = (papszFilterReturnNums == NULL ? true :
     327          112133 :          (CSLFindString(papszFilterReturnNums, bufCode)!=-1));
     328          112133 :       if (!bReturnNumOK && CSLFindString(papszFilterReturnNums, "Last")!=-1)
     329                 :       {  // Didn't find an explicit match (e.g. return number "1") so we handle a request for "Last" returns
     330               0 :          const long numreturns= GetChannelElement<long>(*pointdata.getChannel(CHANNEL_NAME_NumReturns), i);
     331               0 :          bReturnNumOK = (returnnum == numreturns);
     332                 :       }
     333                 :    }
     334                 : 
     335          295490 :    return bReturnNumOK && bClassificationOK;
     336                 : 
     337                 : }
     338                 : 
     339                 : 
     340                 : template<typename DTYPE>
     341               2 : CPLErr   MG4LidarRasterBand::doReadBlock(int nBlockXOff, int nBlockYOff, void * pImage)
     342                 : {
     343               2 :    MG4LidarDataset * poGDS = (MG4LidarDataset *)poDS;
     344               2 :    MG4PointReader *reader =poGDS->reader;
     345                 : 
     346                 :    struct Accumulator_t
     347                 :    {
     348                 :       DTYPE value;
     349                 :       int count;
     350                 :    } ;
     351               2 :    Accumulator_t * Accumulator = NULL;
     352               2 :    if (EQUAL(Aggregation, "Mean"))
     353                 :    {
     354               2 :       Accumulator = new Accumulator_t[nBlockXSize*nBlockYSize];
     355               2 :       memset (Accumulator, 0, sizeof(Accumulator_t)*nBlockXSize*nBlockYSize);
     356                 :    }
     357             688 :    for (int i = 0; i < nBlockXSize; i++)
     358                 :    {
     359          247117 :       for (int j = 0; j < nBlockYSize; j++)
     360                 :       {
     361          246431 :          static_cast<DTYPE*>(pImage)[i*nBlockYSize+j] = static_cast<DTYPE>(nodatavalue);
     362                 :       }
     363                 :    }
     364                 : 
     365                 :    double geoTrans[6];
     366               2 :    poGDS->GetGeoTransform(geoTrans);   
     367               2 :    double xres = geoTrans[1];
     368               2 :    double yres = geoTrans[5];
     369                 : 
     370                 :    // Get the extent of the requested block.
     371               2 :    double xmin = geoTrans[0] + (nBlockXOff *nBlockXSize* xres);
     372               2 :    double xmax = xmin + nBlockXSize* xres;
     373               2 :    double ymax = reader->getBounds().y.max - (nBlockYOff * nBlockYSize* -yres);
     374               2 :    double ymin = ymax - nBlockYSize* -yres;
     375               2 :    Bounds bounds(xmin, xmax,  ymin, ymax, -HUGE_VAL, +HUGE_VAL); 
     376               2 :    PointData pointdata;
     377               2 :    pointdata.init(reader->getPointInfo(), 4096);
     378               2 :    double fraction = 1.0/pow(RESOLUTION_RATIO, poGDS->iLevel);
     379               2 :    CPLDebug( "MG4Lidar", "IReadBlock(x=%d y=%d, level=%d, fraction=%f)", nBlockXOff, nBlockYOff, poGDS->iLevel, fraction);
     380               2 :    Scoped<PointIterator> iter(reader->createIterator(bounds, fraction, reader->getPointInfo(), NULL));
     381                 : 
     382               2 :    const double * x = pointdata.getX();
     383               2 :    const double * y = pointdata.getY();
     384                 :    size_t nPoints;
     385              78 :    while ( (nPoints = iter->getNextPoints(pointdata)) != 0)
     386                 :    {
     387          295564 :       for( size_t i = 0; i < nPoints; i++ )
     388                 :       {
     389          295490 :          const ChannelData * channel = pointdata.getChannel(ChannelName);
     390          295490 :          if (papszFilterClassCodes || papszFilterReturnNums)
     391                 :          {
     392          295490 :             if (!ElementPassesFilter(pointdata, i))
     393          183357 :                continue;
     394                 :          }
     395          112133 :          double col = (x[i] - xmin) / xres;
     396          112133 :          double row = (ymax - y[i]) / -yres;
     397          112133 :          col = floor (col);
     398          112133 :          row = floor (row);
     399                 : 
     400          112133 :          if (row < 0) 
     401               0 :             row = 0;
     402          112133 :          else if (row >= nBlockYSize) 
     403               0 :             row = nBlockYSize - 1;
     404          112133 :          if (col < 0) 
     405               0 :             col = 0;
     406          112133 :          else if (col >= nBlockXSize ) 
     407               1 :             col = nBlockXSize - 1;
     408                 : 
     409          112133 :          int iCol = (int) (col);
     410          112133 :          int iRow = (int) (row);
     411          112133 :          const int offset =iRow* nBlockXSize + iCol;
     412          112133 :          if (EQUAL(Aggregation, "Max"))
     413                 :          {
     414               0 :             DTYPE value = GetChannelElement<DTYPE>(*channel, i);
     415               0 :             if (static_cast<DTYPE *>(pImage)[offset] == static_cast<DTYPE>(nodatavalue) ||
     416                 :                static_cast<DTYPE *>(pImage)[offset] < value)
     417               0 :                static_cast<DTYPE *>(pImage)[offset] = value;
     418                 :          }
     419          112133 :          else if (EQUAL(Aggregation, "Min"))
     420                 :          {
     421               0 :             DTYPE value = GetChannelElement<DTYPE>(*channel, i);
     422               0 :             if (static_cast<DTYPE *>(pImage)[offset] == static_cast<DTYPE>(nodatavalue) ||
     423                 :                static_cast<DTYPE *>(pImage)[offset] > value)
     424               0 :                static_cast<DTYPE *>(pImage)[offset] = value;
     425                 :          }
     426          112133 :          else if (EQUAL(Aggregation, "Mean"))
     427                 :          {
     428          112133 :             DTYPE value = GetChannelElement<DTYPE>(*channel, i);
     429          112133 :             Accumulator[offset].count++;
     430          112133 :             Accumulator[offset].value += value;
     431          112133 :             static_cast<DTYPE*>(pImage)[offset] = static_cast<DTYPE>(Accumulator[offset].value / Accumulator[offset].count);
     432                 :          }
     433                 :       }
     434                 :    }
     435                 :    
     436               2 :    delete[] Accumulator;
     437               2 :    return CE_None;
     438                 : }
     439                 : 
     440               2 : double MG4LidarRasterBand::getMaxValue()
     441                 : {
     442                 :    double retval;
     443               2 :    switch(eDataType)
     444                 :    {
     445                 :       #define DO_CASE(gdt, largestvalue)  case (gdt):\
     446                 :          retval = static_cast<double>(largestvalue); \
     447                 :          break;
     448                 :          
     449               0 :       DO_CASE (GDT_Float64, DBL_MAX);
     450               2 :       DO_CASE (GDT_Float32, FLT_MAX);
     451               0 :       DO_CASE (GDT_Int32, INT_MAX);
     452               0 :       DO_CASE (GDT_UInt32, UINT_MAX);
     453               0 :       DO_CASE (GDT_Int16, SHRT_MAX);
     454               0 :       DO_CASE (GDT_UInt16, USHRT_MAX);
     455               0 :       DO_CASE (GDT_Byte, UCHAR_MAX);
     456                 :       #undef DO_CASE 
     457                 :        default:
     458               0 :            retval = 0;
     459                 :            break;
     460                 :    }
     461               2 :    return retval;
     462                 : }
     463                 : /************************************************************************/
     464                 : /*                             IReadBlock()                             */
     465                 : /************************************************************************/
     466                 : 
     467               2 : CPLErr MG4LidarRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     468                 :                                       void * pImage )
     469                 : {
     470                 :    CPLErr eErr;
     471               2 :    switch(eDataType)
     472                 :    {
     473                 : #define DO_CASE(gdt, nativedt)  case (gdt):\
     474                 :    eErr = doReadBlock<nativedt>(nBlockXOff, nBlockYOff, pImage); \
     475                 :    break;
     476                 : 
     477               0 :       DO_CASE (GDT_Float64, double);
     478               2 :       DO_CASE (GDT_Float32, float);
     479               0 :       DO_CASE (GDT_Int32, long);
     480               0 :       DO_CASE (GDT_UInt32, unsigned long);
     481               0 :       DO_CASE (GDT_Int16, short);
     482               0 :       DO_CASE (GDT_UInt16, unsigned short);
     483               0 :       DO_CASE (GDT_Byte, char);
     484                 : #undef DO_CASE 
     485                 :       default:
     486               0 :            return CE_Failure;
     487                 :            break;
     488                 : 
     489                 :    }
     490               2 :    return CE_None;
     491                 : }
     492                 : 
     493                 : /************************************************************************/
     494                 : /*                           GetStatistics()                            */
     495                 : /************************************************************************/
     496                 : 
     497               0 : CPLErr MG4LidarRasterBand::GetStatistics( int bApproxOK, int bForce,
     498                 :                                          double *pdfMin, double *pdfMax, 
     499                 :                                          double *pdfMean, double *pdfStdDev )
     500                 : 
     501                 : {
     502               0 :    bApproxOK = TRUE; 
     503               0 :    bForce = TRUE;
     504                 : 
     505                 :    return GDALPamRasterBand::GetStatistics( bApproxOK, bForce, 
     506                 :       pdfMin, pdfMax, 
     507               0 :       pdfMean, pdfStdDev );   
     508                 : 
     509                 : }
     510                 : /************************************************************************/
     511                 : /*                           GetNoDataValue()                           */
     512                 : /************************************************************************/
     513                 : 
     514               0 : double MG4LidarRasterBand::GetNoDataValue( int *pbSuccess )
     515                 : {
     516               0 :    if (pbSuccess)
     517               0 :        *pbSuccess = TRUE;
     518               0 :    return nodatavalue;
     519                 : }
     520                 : 
     521                 : 
     522                 : /************************************************************************/
     523                 : /*                            MG4LidarDataset()                             */
     524                 : /************************************************************************/
     525               2 : MG4LidarDataset::MG4LidarDataset()
     526                 : {
     527               2 :    reader = NULL;
     528                 : 
     529               2 :    poXMLPCView = NULL;
     530               2 :    ownsXML = false;
     531               2 :    nOverviewCount = 0;
     532               2 :    papoOverviewDS = NULL;
     533                 : 
     534               2 : }
     535                 : /************************************************************************/
     536                 : /*                            ~MG4LidarDataset()                             */
     537                 : /************************************************************************/
     538                 : 
     539               2 : MG4LidarDataset::~MG4LidarDataset()
     540                 : 
     541                 : {
     542               2 :    FlushCache();
     543               2 :    if ( papoOverviewDS )
     544                 :    {
     545               2 :       for( int i = 0; i < nOverviewCount; i++ )
     546               1 :          delete papoOverviewDS[i];
     547               1 :       CPLFree( papoOverviewDS );
     548                 :    }
     549               2 :    if (ownsXML)
     550               1 :       CPLDestroyXMLNode(poXMLPCView);
     551                 : 
     552               2 :    RELEASE(reader);
     553               2 : }
     554                 : 
     555                 : /************************************************************************/
     556                 : /*                          GetGeoTransform()                           */
     557                 : /************************************************************************/
     558                 : 
     559               3 : CPLErr MG4LidarDataset::GetGeoTransform( double * padfTransform )
     560                 : 
     561                 : {
     562               3 :    padfTransform[0] = reader->getBounds().x.min ;// Upper left X, Y
     563               3 :    padfTransform[3] = reader->getBounds().y.max; // 
     564               3 :    padfTransform[1] = reader->getBounds().x.length()/GetRasterXSize(); //xRes
     565               3 :    padfTransform[2] = 0.0;
     566                 : 
     567               3 :    padfTransform[4] = 0.0;
     568               3 :    padfTransform[5] = -1 * reader->getBounds().y.length()/GetRasterYSize(); //yRes
     569                 : 
     570               3 :    return CE_None;
     571                 : }
     572                 : 
     573                 : /************************************************************************/
     574                 : /*                          GetProjectionRef()                          */
     575                 : /************************************************************************/
     576                 : 
     577               1 : const char *MG4LidarDataset::GetProjectionRef()
     578                 : 
     579                 : {
     580               1 :    const char * wkt = CPLGetXMLValue(poXMLPCView, "GeoReference", NULL);
     581               1 :    if (wkt == NULL)
     582               1 :       wkt = reader->getWKT(); 
     583               1 :    return(wkt);
     584                 : }
     585                 : 
     586                 : /************************************************************************/
     587                 : /*                             OpenZoomLevel()                          */
     588                 : /************************************************************************/
     589                 : 
     590               2 : CPLErr MG4LidarDataset::OpenZoomLevel( int iZoom )
     591                 : {
     592                 :    /* -------------------------------------------------------------------- */
     593                 :    /*      Get image geometry.                                            */
     594                 :    /* -------------------------------------------------------------------- */
     595               2 :    iLevel = iZoom;
     596                 : 
     597                 :    // geo dimensions
     598               2 :    const double gWidth = reader->getBounds().x.length() ;
     599               2 :    const double gHeight = reader->getBounds().y.length() ;
     600                 : 
     601                 :    // geo res
     602               2 :    double xRes = pow(RESOLUTION_RATIO, iZoom) * gWidth / MaxRasterSize ;
     603               2 :    double yRes = pow(RESOLUTION_RATIO, iZoom) * gHeight / MaxRasterSize ;
     604               2 :    xRes = yRes = MAX(xRes, yRes);
     605                 : 
     606                 :    // pixel dimensions
     607               2 :    nRasterXSize  = static_cast<int>(gWidth / xRes  + 0.5);
     608               2 :    nRasterYSize  = static_cast<int>(gHeight / yRes + 0.5);
     609                 : 
     610               2 :    nBlockXSize = static_cast<int>(MIN(MaxBlockSideSize , GetRasterXSize()));
     611               2 :    nBlockYSize = static_cast<int>(MIN(MaxBlockSideSize , GetRasterYSize())); 
     612                 : 
     613                 :    CPLDebug( "MG4Lidar", "Opened zoom level %d with size %dx%d.\n",
     614               2 :       iZoom, nRasterXSize, nRasterYSize );
     615                 : 
     616                 : 
     617                 : 
     618                 :    /* -------------------------------------------------------------------- */
     619                 :    /*  Handle sample type and color space.                                 */
     620                 :    /* -------------------------------------------------------------------- */
     621                 :    //eColorSpace = poImageReader->getColorSpace();
     622                 :    /* -------------------------------------------------------------------- */
     623                 :    /*      Create band information objects.                                */
     624                 :    /* -------------------------------------------------------------------- */
     625               2 :    size_t BandCount = 0;
     626               2 :    CPLXMLNode* xmlBand = poXMLPCView;
     627               2 :    bool bClass = false;
     628               2 :    bool bNumRets = false;
     629               2 :    bool bRetNum = false;
     630               6 :    while ((xmlBand = CPLSearchXMLNode(xmlBand, "Band")) != NULL)
     631                 :    {
     632               2 :       CPLXMLNode * xmlChannel = CPLSearchXMLNode(xmlBand, "Channel");
     633               2 :       const char * name = "Z";
     634               2 :       if (xmlChannel && xmlChannel->psChild && xmlChannel->psChild->pszValue)
     635               2 :          name = xmlChannel->psChild->pszValue;
     636                 :       
     637               2 :       BandCount++;
     638               2 :       MG4LidarRasterBand *band = new MG4LidarRasterBand(this, BandCount, xmlBand, name);
     639               2 :       SetBand(BandCount, band);
     640               4 :       if (band->papszFilterClassCodes) bClass = true;
     641               2 :       if (band->papszFilterReturnNums) bNumRets = true;
     642               2 :       if (bNumRets && CSLFindString(band->papszFilterReturnNums, "Last")) bRetNum = true;
     643               2 :       xmlBand = xmlBand->psNext;
     644                 :    }
     645               2 :    nBands = BandCount;
     646               2 :    int nSDKChannels = BandCount + (bClass ? 1 : 0) + (bNumRets ? 1 : 0) + (bRetNum ? 1 : 0);
     647               2 :    if (BandCount == 0)  // default if no bands specified.
     648                 :    {
     649               0 :       MG4LidarRasterBand *band = new MG4LidarRasterBand(this, 1, NULL, CHANNEL_NAME_Z);
     650               0 :       SetBand(1, band);
     651               0 :       nBands = 1;
     652               0 :       nSDKChannels = 1;
     653                 :    }
     654               2 :    requiredChannels.init(nSDKChannels);
     655               2 :    const ChannelInfo *ci = NULL;
     656               4 :    for (int i=0; i<nBands; i++)
     657                 :    {
     658               2 :       ci = reader->getChannel(dynamic_cast<MG4LidarRasterBand*>(papoBands[i])->ChannelName);
     659               2 :       requiredChannels.getChannel(i).init(*ci);
     660                 :    }
     661               2 :    int iSDKChannels = nBands;
     662               2 :    if (bClass)
     663                 :    {
     664               2 :       ci = reader->getChannel(CHANNEL_NAME_ClassId);
     665               2 :       requiredChannels.getChannel(iSDKChannels++).init(*ci);
     666                 :    }
     667               2 :    if (bRetNum)
     668                 :    {
     669               0 :       ci = reader->getChannel(CHANNEL_NAME_ReturnNum);
     670               0 :       requiredChannels.getChannel(iSDKChannels++).init(*ci);
     671                 :    }
     672               2 :    if (bNumRets)
     673                 :    {
     674               0 :       ci = reader->getChannel(CHANNEL_NAME_NumReturns);
     675               0 :       requiredChannels.getChannel(iSDKChannels++).init(*ci);
     676                 :    }
     677                 : 
     678               2 :    return CE_None;
     679                 : }
     680                 : 
     681                 : /************************************************************************/
     682                 : /*                                Open()                                */
     683                 : /************************************************************************/
     684                 : 
     685           11392 : GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo )
     686                 : 
     687                 : {
     688                 : #ifdef notdef
     689                 :    CPLPushErrorHandler( CPLLoggingErrorHandler );
     690                 :    CPLSetConfigOption( "CPL_DEBUG", "ON" );
     691                 :    CPLSetConfigOption( "CPL_LOG", "C:\\ArcGIS_GDAL\\jdem\\cpl.log" );
     692                 : #endif
     693                 : 
     694           11392 :    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 32 )
     695           10703 :       return NULL;
     696                 : 
     697                 :    CPLXMLNode *pxmlPCView;
     698                 : 
     699                 :    // do something sensible for .sid files without a .view
     700             689 :    if( EQUALN((const char *) poOpenInfo->pabyHeader, "msid", 4) )
     701                 :    {
     702                 :       int gen;
     703                 :       bool raster;
     704               0 :       if( !Version::getMrSIDFileVersion(poOpenInfo->pabyHeader, gen, raster)
     705                 :           || raster )
     706               0 :          return NULL;
     707                 : 
     708               0 :       CPLString xmltmp( "<PointCloudView><InputFile>" );
     709               0 :       xmltmp.append( poOpenInfo->pszFilename );
     710               0 :       xmltmp.append( "</InputFile></PointCloudView>" );
     711               0 :       pxmlPCView = CPLParseXMLString( xmltmp );
     712               0 :       if (pxmlPCView == NULL)
     713               0 :          return NULL;
     714                 :    }
     715                 :    else
     716                 :    {
     717                 :       // support .view xml
     718             689 :       if( !EQUALN((const char *) poOpenInfo->pabyHeader, "<PointCloudView", 15 ) )
     719             688 :          return NULL;
     720                 : 
     721               1 :       pxmlPCView = CPLParseXMLFile( poOpenInfo->pszFilename );
     722               1 :       if (pxmlPCView == NULL)
     723               0 :           return NULL;
     724                 :    }
     725                 : 
     726               1 :    CPLXMLNode *psInputFile = CPLGetXMLNode( pxmlPCView, "InputFile" );
     727               1 :    if( psInputFile == NULL )
     728                 :    {
     729                 :       CPLError( CE_Failure, CPLE_OpenFailed, 
     730               0 :          "Failed to find <InputFile> in document." );
     731               0 :       CPLDestroyXMLNode(pxmlPCView);
     732               0 :       return NULL;
     733                 :    }
     734               1 :    CPLString sidInputName(psInputFile->psChild->pszValue);
     735               1 :    if (CPLIsFilenameRelative(sidInputName))
     736                 :    {
     737               1 :       CPLString dirname(CPLGetDirname(poOpenInfo->pszFilename));
     738               1 :       sidInputName = CPLString(CPLFormFilename(dirname, sidInputName, NULL));
     739                 :    }
     740               1 :    GDALOpenInfo openinfo(sidInputName, GA_ReadOnly);
     741                 : 
     742                 :    /* -------------------------------------------------------------------- */
     743                 :    /*      Check that particular fields in the header are valid looking    */
     744                 :    /*      dates.                                                          */
     745                 :    /* -------------------------------------------------------------------- */
     746               1 :    if( openinfo.fp == NULL || openinfo.nHeaderBytes < 50 )
     747                 :    {
     748               0 :       CPLDestroyXMLNode(pxmlPCView);
     749               0 :       return NULL;
     750                 :    }
     751                 : 
     752                 :    /* check magic */
     753                 :    // to do:  SDK should provide an API for this.
     754               1 :    if(  !EQUALN((const char *) openinfo.pabyHeader, "msid", 4)
     755                 :       || (*(openinfo.pabyHeader+4) != 0x4 )) // Generation 4.  ... is there more we can check?
     756                 :    {
     757               0 :       CPLDestroyXMLNode(pxmlPCView);
     758               0 :       return NULL;
     759                 :    }
     760                 : 
     761                 :    /* -------------------------------------------------------------------- */
     762                 :    /*      Create a corresponding GDALDataset.                             */
     763                 :    /* -------------------------------------------------------------------- */
     764                 :    MG4LidarDataset  *poDS;
     765                 : 
     766               1 :    poDS = new MG4LidarDataset();
     767               1 :    poDS->poXMLPCView = pxmlPCView;
     768               1 :    poDS->ownsXML = true;
     769               2 :    poDS->reader = CropableMG4PointReader::create();
     770               1 :    const char * pszClipExtent = CPLGetXMLValue(pxmlPCView, "ClipBox", NULL);
     771               1 :    MG4PointReader *r = MG4PointReader::create();
     772               1 :    r->init(openinfo.pszFilename);
     773               1 :    Bounds bounds = r->getBounds();
     774               1 :    if (pszClipExtent)
     775                 :    {
     776               0 :       char ** papszClipExtent = CSLTokenizeString(pszClipExtent);
     777               0 :       int cslcount = CSLCount(papszClipExtent);
     778               0 :       if (cslcount != 4 && cslcount != 6)
     779                 :       {
     780                 :          CPLError( CE_Failure, CPLE_OpenFailed, 
     781               0 :             "Invalid ClipBox.  Must contain 4 or 6 floats." );
     782               0 :          CSLDestroy(papszClipExtent);
     783               0 :          delete poDS;
     784               0 :          RELEASE(r);
     785               0 :          return NULL;
     786                 :       }
     787               0 :       if (!EQUAL(papszClipExtent[0], "NOFILTER"))
     788               0 :          bounds.x.min = atof(papszClipExtent[0]);
     789               0 :       if (!EQUAL(papszClipExtent[1], "NOFILTER"))
     790               0 :          bounds.x.max = atof(papszClipExtent[1]);
     791               0 :       if (!EQUAL(papszClipExtent[2], "NOFILTER"))
     792               0 :          bounds.y.min = atof(papszClipExtent[2]);
     793               0 :       if (!EQUAL(papszClipExtent[3], "NOFILTER"))
     794               0 :          bounds.y.max = atof(papszClipExtent[3]);
     795               0 :       if (cslcount == 6)
     796                 :       {
     797               0 :          if (!EQUAL(papszClipExtent[4], "NOFILTER"))
     798               0 :             bounds.z.min = atof(papszClipExtent[4]);
     799               0 :          if (!EQUAL(papszClipExtent[5], "NOFILTER"))
     800               0 :             bounds.z.max = atof(papszClipExtent[5]);
     801                 :       }
     802               0 :       CSLDestroy(papszClipExtent);
     803                 :    }
     804                 : 
     805               1 :    dynamic_cast<CropableMG4PointReader *>(poDS->reader)->init(openinfo.pszFilename, &bounds);
     806               1 :    poDS->SetDescription(poOpenInfo->pszFilename);
     807               1 :    poDS->TryLoadXML(); 
     808                 : 
     809               1 :    double pts_per_area = ((double)r->getNumPoints())/(r->getBounds().x.length()*r->getBounds().y.length());
     810               1 :    double average_pt_spacing = sqrt(1.0 / pts_per_area) ;
     811               1 :    double cell_side = average_pt_spacing;
     812               1 :    const char * pszCellSize = CPLGetXMLValue(pxmlPCView, "CellSize", NULL);
     813               1 :    if (pszCellSize)
     814               0 :       cell_side = atof(pszCellSize);
     815               1 :    MaxRasterSize = MAX(poDS->reader->getBounds().x.length()/cell_side, poDS->reader->getBounds().y.length()/cell_side);
     816                 : 
     817               1 :    RELEASE(r);
     818                 : 
     819                 :    // Calculate the number of levels to expose.  The highest level correpsonds to a
     820                 :    // raster size of 256 on the longest side.
     821               1 :    double blocksizefactor = MaxRasterSize/256.0;
     822               1 :    poDS->nOverviewCount = MAX(0, (int)(log(blocksizefactor)/log(RESOLUTION_RATIO) + 0.5));
     823               1 :    if ( poDS->nOverviewCount > 0 )
     824                 :    {
     825                 :       int i;
     826                 : 
     827                 :       poDS->papoOverviewDS = (MG4LidarDataset **)
     828               1 :          CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) );
     829                 : 
     830               2 :       for ( i = 0; i < poDS->nOverviewCount; i++ )
     831                 :       {
     832               1 :          poDS->papoOverviewDS[i] = new MG4LidarDataset ();
     833               2 :          poDS->papoOverviewDS[i]->reader = RETAIN(poDS->reader);
     834               1 :          poDS->papoOverviewDS[i]->SetMetadata(poDS->GetMetadata("MG4Lidar"), "MG4Lidar");
     835               1 :          poDS->papoOverviewDS[i]->poXMLPCView = pxmlPCView;
     836               1 :          poDS->papoOverviewDS[i]->OpenZoomLevel( i+1 );
     837                 :       }       
     838                 :    }
     839                 : 
     840                 :    /* -------------------------------------------------------------------- */
     841                 :    /*      Create object for the whole image.                              */
     842                 :    /* -------------------------------------------------------------------- */
     843               1 :    poDS->OpenZoomLevel( 0 );
     844                 : 
     845                 :    CPLDebug( "MG4Lidar",
     846                 :       "Opened image: width %d, height %d, bands %d",
     847               1 :       poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands );
     848                 : 
     849               1 :    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     850                 :    {
     851               0 :        delete poDS;
     852               0 :        return NULL;
     853                 :    }
     854                 : 
     855               1 :    if (! ((poDS->nBands == 1) || (poDS->nBands == 3)))
     856                 :    {
     857                 :       CPLDebug( "MG4Lidar",
     858               0 :          "Inappropriate number of bands (%d)", poDS->nBands );
     859               0 :       delete poDS;
     860               0 :       return(NULL);
     861                 :    }
     862                 : 
     863               1 :    return( poDS );
     864                 : }
     865                 : 
     866                 : /************************************************************************/
     867                 : /*                          GDALRegister_MG4Lidar()                        */
     868                 : /************************************************************************/
     869                 : 
     870             558 : void GDALRegister_MG4Lidar()
     871                 : 
     872                 : {
     873                 :    GDALDriver *poDriver;
     874                 : 
     875             558 :     if (! GDAL_CHECK_VERSION("MG4Lidar driver"))
     876               0 :         return;
     877                 : 
     878             558 :    if( GDALGetDriverByName( "MG4Lidar" ) == NULL )
     879                 :    {
     880             537 :       poDriver = new GDALDriver();
     881                 : 
     882             537 :       poDriver->SetDescription( "MG4Lidar" );
     883                 :       poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     884             537 :          "MrSID Generation 4 / Lidar (.sid)" );
     885                 :       // To do:  update this help file in gdal.org
     886                 :       poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     887             537 :          "frmt_mrsid_lidar.html" );
     888                 : 
     889             537 :       poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "view" );
     890                 :       poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
     891             537 :          "Float64" );
     892                 : 
     893             537 :       poDriver->pfnOpen = MG4LidarDataset::Open;
     894                 : 
     895             537 :       GetGDALDriverManager()->RegisterDriver( poDriver );
     896                 :    }
     897                 : }

Generated by: LCOV version 1.7