ultimatepp/bazaar/plugin/gdal/frmts/map/mapdataset.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

511 lines
18 KiB
C++

/******************************************************************************
*
* Project: OziExplorer .MAP Driver
* Purpose: GDALDataset driver for OziExplorer .MAP files
* Author: Jean-Claude Repetto, <jrepetto at @free dot fr>
*
******************************************************************************
* Copyright (c) 2012, Jean-Claude Repetto
* Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdal_pam.h"
#include "gdal_proxy.h"
#include "ogr_spatialref.h"
#include "ogr_geometry.h"
CPL_CVSID("$Id: mapdataset.cpp 27559 2014-08-04 17:52:19Z rouault $");
/************************************************************************/
/* ==================================================================== */
/* MAPDataset */
/* ==================================================================== */
/************************************************************************/
class CPL_DLL MAPDataset : public GDALDataset
{
GDALDataset *poImageDS;
char *pszWKT;
int bGeoTransformValid;
double adfGeoTransform[6];
int nGCPCount;
GDAL_GCP *pasGCPList;
OGRPolygon *poNeatLine;
CPLString osImgFilename;
public:
MAPDataset();
virtual ~MAPDataset();
virtual const char* GetProjectionRef();
virtual CPLErr GetGeoTransform( double * );
virtual int GetGCPCount();
virtual const char *GetGCPProjection();
virtual const GDAL_GCP *GetGCPs();
virtual char **GetFileList();
virtual int CloseDependentDatasets();
static GDALDataset *Open( GDALOpenInfo * );
static int Identify( GDALOpenInfo *poOpenInfo );
};
/************************************************************************/
/* ==================================================================== */
/* MAPWrapperRasterBand */
/* ==================================================================== */
/************************************************************************/
class MAPWrapperRasterBand : public GDALProxyRasterBand
{
GDALRasterBand* poBaseBand;
protected:
virtual GDALRasterBand* RefUnderlyingRasterBand() { return poBaseBand; }
public:
MAPWrapperRasterBand( GDALRasterBand* poBaseBand )
{
this->poBaseBand = poBaseBand;
eDataType = poBaseBand->GetRasterDataType();
poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
}
~MAPWrapperRasterBand() {}
};
/************************************************************************/
/* ==================================================================== */
/* MAPDataset */
/* ==================================================================== */
/************************************************************************/
MAPDataset::MAPDataset()
{
poImageDS = NULL;
pszWKT = NULL;
adfGeoTransform[0] = 0.0;
adfGeoTransform[1] = 1.0;
adfGeoTransform[2] = 0.0;
adfGeoTransform[3] = 0.0;
adfGeoTransform[4] = 0.0;
adfGeoTransform[5] = 1.0;
nGCPCount = 0;
pasGCPList = NULL;
poNeatLine = NULL;
bGeoTransformValid = false;
}
/************************************************************************/
/* ~MAPDataset() */
/************************************************************************/
MAPDataset::~MAPDataset()
{
if (poImageDS != NULL)
{
GDALClose( poImageDS );
poImageDS = NULL;
}
if (pszWKT != NULL)
{
CPLFree(pszWKT);
pszWKT = NULL;
}
if (nGCPCount)
{
GDALDeinitGCPs( nGCPCount, pasGCPList );
CPLFree(pasGCPList);
}
if ( poNeatLine != NULL )
{
delete poNeatLine;
poNeatLine = NULL;
}
}
/************************************************************************/
/* CloseDependentDatasets() */
/************************************************************************/
int MAPDataset::CloseDependentDatasets()
{
int bRet = GDALDataset::CloseDependentDatasets();
if (poImageDS != NULL)
{
GDALClose( poImageDS );
poImageDS = NULL;
bRet = TRUE;
}
return bRet;
}
/************************************************************************/
/* Identify() */
/************************************************************************/
int MAPDataset::Identify( GDALOpenInfo *poOpenInfo )
{
if( poOpenInfo->nHeaderBytes < 200
|| !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"MAP") )
return FALSE;
if( strstr((const char *) poOpenInfo->pabyHeader,"OziExplorer Map Data File") == NULL )
return FALSE;
else
return TRUE;
}
/************************************************************************/
/* Open() */
/************************************************************************/
#define MAX_GCP 30
GDALDataset *MAPDataset::Open( GDALOpenInfo * poOpenInfo )
{
if( !Identify( poOpenInfo ) )
return NULL;
/* -------------------------------------------------------------------- */
/* Confirm the requested access is supported. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->eAccess == GA_Update )
{
CPLError( CE_Failure, CPLE_NotSupported,
"The MAP driver does not support update access to existing"
" datasets.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
MAPDataset *poDS = new MAPDataset();
/* -------------------------------------------------------------------- */
/* Try to load and parse the .MAP file. */
/* -------------------------------------------------------------------- */
int bOziFileOK =
GDALLoadOziMapFile( poOpenInfo->pszFilename,
poDS->adfGeoTransform,
&poDS->pszWKT,
&poDS->nGCPCount, &poDS->pasGCPList );
if ( bOziFileOK && poDS->nGCPCount == 0 )
poDS->bGeoTransformValid = TRUE;
/* We need to read again the .map file because the GDALLoadOziMapFile function
does not returns all required data . An API change is necessary : maybe in GDAL 2.0 ? */
char **papszLines;
int iLine, nLines=0;
papszLines = CSLLoad2( poOpenInfo->pszFilename, 200, 200, NULL );
if ( !papszLines )
return NULL;
nLines = CSLCount( papszLines );
if( nLines < 2 )
{
CSLDestroy(papszLines);
return NULL;
}
/* -------------------------------------------------------------------- */
/* We need to open the image in order to establish */
/* details like the band count and types. */
/* -------------------------------------------------------------------- */
poDS->osImgFilename = papszLines[2];
VSIStatBufL sStat;
if (VSIStatL(poDS->osImgFilename, &sStat) != 0)
{
CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
if (CPLIsFilenameRelative(poDS->osImgFilename))
{
poDS->osImgFilename = CPLFormCIFilename(osPath, poDS->osImgFilename, NULL);
}
else
{
poDS->osImgFilename = CPLGetFilename(poDS->osImgFilename);
poDS->osImgFilename = CPLFormCIFilename(osPath, poDS->osImgFilename, NULL);
}
}
/* -------------------------------------------------------------------- */
/* Try and open the file. */
/* -------------------------------------------------------------------- */
poDS->poImageDS = (GDALDataset *) GDALOpen(poDS->osImgFilename, GA_ReadOnly );
if( poDS->poImageDS == NULL || poDS->poImageDS->GetRasterCount() == 0)
{
CSLDestroy(papszLines);
delete poDS;
return NULL;
}
/* -------------------------------------------------------------------- */
/* Attach the bands. */
/* -------------------------------------------------------------------- */
int iBand;
poDS->nRasterXSize = poDS->poImageDS->GetRasterXSize();
poDS->nRasterYSize = poDS->poImageDS->GetRasterYSize();
if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
{
delete poDS;
GDALClose( poDS->poImageDS );
return NULL;
}
for( iBand = 1; iBand <= poDS->poImageDS->GetRasterCount(); iBand++ )
poDS->SetBand( iBand,
new MAPWrapperRasterBand( poDS->poImageDS->GetRasterBand( iBand )) );
/* -------------------------------------------------------------------- */
/* Add the neatline/cutline, if required */
/* -------------------------------------------------------------------- */
/* First, we need to check if it is necessary to define a neatline */
bool bNeatLine = false;
char **papszTok;
for ( iLine = 10; iLine < nLines; iLine++ )
{
if ( EQUALN(papszLines[iLine], "MMPXY,", 6) )
{
papszTok = CSLTokenizeString2( papszLines[iLine], ",",
CSLT_STRIPLEADSPACES
| CSLT_STRIPENDSPACES );
if ( CSLCount(papszTok) != 4 )
{
CSLDestroy(papszTok);
continue;
}
int x = CPLAtofM(papszTok[2]);
int y = CPLAtofM(papszTok[3]);
if (( x != 0 && x != poDS->nRasterXSize) || (y != 0 && y != poDS->nRasterYSize) )
{
bNeatLine = true;
CSLDestroy(papszTok);
break;
}
CSLDestroy(papszTok);
}
}
/* Create and fill the neatline polygon */
if (bNeatLine)
{
poDS->poNeatLine = new OGRPolygon(); /* Create a polygon to store the neatline */
OGRLinearRing* poRing = new OGRLinearRing();
if ( poDS->bGeoTransformValid ) /* Compute the projected coordinates of the corners */
{
for ( iLine = 10; iLine < nLines; iLine++ )
{
if ( EQUALN(papszLines[iLine], "MMPXY,", 6) )
{
papszTok = CSLTokenizeString2( papszLines[iLine], ",",
CSLT_STRIPLEADSPACES
| CSLT_STRIPENDSPACES );
if ( CSLCount(papszTok) != 4 )
{
CSLDestroy(papszTok);
continue;
}
double x = CPLAtofM(papszTok[2]);
double y = CPLAtofM(papszTok[3]);
double X = poDS->adfGeoTransform[0] + x * poDS->adfGeoTransform[1] +
y * poDS->adfGeoTransform[2];
double Y = poDS->adfGeoTransform[3] + x * poDS->adfGeoTransform[4] +
y * poDS->adfGeoTransform[5];
poRing->addPoint(X, Y);
CPLDebug( "CORNER MMPXY", "%f, %f, %f, %f", x, y, X, Y);
CSLDestroy(papszTok);
}
}
}
else /* Convert the geographic coordinates to projected coordinates */
{
OGRSpatialReference oSRS;
OGRSpatialReference *poLatLong = NULL;
OGRCoordinateTransformation *poTransform = NULL;
OGRErr eErr;
char *pszWKT = poDS->pszWKT;
if ( &poDS->pszWKT != NULL )
{
eErr = oSRS.importFromWkt ( &pszWKT );
if ( eErr == OGRERR_NONE )
poLatLong = oSRS.CloneGeogCS();
if ( poLatLong )
poTransform = OGRCreateCoordinateTransformation( poLatLong, &oSRS );
}
for ( iLine = 10; iLine < nLines; iLine++ )
{
if ( EQUALN(papszLines[iLine], "MMPLL,", 6) )
{
CPLDebug( "MMPLL", "%s", papszLines[iLine] );
char **papszTok = NULL;
papszTok = CSLTokenizeString2( papszLines[iLine], ",",
CSLT_STRIPLEADSPACES
| CSLT_STRIPENDSPACES );
if ( CSLCount(papszTok) != 4 )
{
CSLDestroy(papszTok);
continue;
}
double dfLon = CPLAtofM(papszTok[2]);
double dfLat = CPLAtofM(papszTok[3]);
if ( poTransform )
poTransform->Transform( 1, &dfLon, &dfLat );
poRing->addPoint(dfLon, dfLat);
CPLDebug( "CORNER MMPLL", "%f, %f", dfLon, dfLat);
CSLDestroy(papszTok);
}
}
if (poTransform)
delete poTransform;
if (poLatLong)
delete poLatLong;
}
poRing->closeRings();
poDS->poNeatLine->addRingDirectly(poRing);
char* pszNeatLineWkt = NULL;
poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
CPLDebug( "NEATLINE", "%s", pszNeatLineWkt);
poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
CPLFree(pszNeatLineWkt);
}
CSLDestroy(papszLines);
return( poDS );
}
/************************************************************************/
/* GetProjectionRef() */
/************************************************************************/
const char* MAPDataset::GetProjectionRef()
{
return (pszWKT && nGCPCount == 0) ? pszWKT : "";
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr MAPDataset::GetGeoTransform( double * padfTransform )
{
memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
return( (nGCPCount == 0) ? CE_None : CE_Failure );
}
/************************************************************************/
/* GetGCPCount() */
/************************************************************************/
int MAPDataset::GetGCPCount()
{
return nGCPCount;
}
/************************************************************************/
/* GetGCPProjection() */
/************************************************************************/
const char * MAPDataset::GetGCPProjection()
{
return (pszWKT && nGCPCount != 0) ? pszWKT : "";
}
/************************************************************************/
/* GetGCPs() */
/************************************************************************/
const GDAL_GCP * MAPDataset::GetGCPs()
{
return pasGCPList;
}
/************************************************************************/
/* GetFileList() */
/************************************************************************/
char** MAPDataset::GetFileList()
{
char **papszFileList = GDALDataset::GetFileList();
papszFileList = CSLAddString( papszFileList, osImgFilename );
return papszFileList;
}
/************************************************************************/
/* GDALRegister_MAP() */
/************************************************************************/
void GDALRegister_MAP()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "MAP" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "MAP" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"OziExplorer .MAP" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_map.html" );
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->pfnOpen = MAPDataset::Open;
poDriver->pfnIdentify = MAPDataset::Identify;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}