.gdal moved to bazaar

git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2015-12-07 13:36:24 +00:00
parent 91d7449c7b
commit 23ff1e7e82
2535 changed files with 1272044 additions and 0 deletions

View file

@ -0,0 +1,51 @@
include ../GDALmake.opt
OBJ = gdalmediancut.o gdaldither.o gdal_crs.o gdaltransformer.o \
gdalsimplewarp.o gdalwarper.o gdalwarpkernel.o \
gdalwarpoperation.o gdalchecksum.o gdal_rpc.o gdal_tps.o \
thinplatespline.o llrasterize.o gdalrasterize.o gdalgeoloc.o \
gdalgrid.o gdalcutline.o gdalproximity.o rasterfill.o \
gdalrasterpolygonenumerator.o \
gdalsievefilter.o gdalwarpkernel_opencl.o polygonize.o \
gdalrasterfpolygonenumerator.o fpolygonize.o \
contour.o gdaltransformgeolocs.o \
gdal_octave.o gdal_simplesurf.o gdalmatching.o
ifeq ($(HAVE_AVX_AT_COMPILE_TIME),yes)
CPPFLAGS := -DHAVE_AVX_AT_COMPILE_TIME $(CPPFLAGS)
endif
ifeq ($(HAVE_SSE_AT_COMPILE_TIME),yes)
CPPFLAGS := -DHAVE_SSE_AT_COMPILE_TIME $(CPPFLAGS)
endif
ifeq ($(HAVE_GEOS),yes)
CPPFLAGS := -DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS)
endif
ifeq ($(HAVE_ARMADILLO),yes)
CPPFLAGS := -DHAVE_ARMADILLO $(CPPFLAGS)
endif
CPPFLAGS := $(CPPFLAGS) $(OPENCL_FLAGS)
default: $(OBJ:.o=.$(OBJ_EXT)) gdalgridavx.$(OBJ_EXT) gdalgridsse.$(OBJ_EXT)
gdalgridavx.$(OBJ_EXT): gdalgridavx.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(AVXFLAGS) $(CPPFLAGS) -c -o $@ $<
gdalgridsse.$(OBJ_EXT): gdalgridsse.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(SSEFLAGS) $(CPPFLAGS) -c -o $@ $<
clean:
$(RM) *.o $(O_OBJ)
docs:
(cd ..; $(MAKE) docs)
install:
for f in *.h ; do $(INSTALL_DATA) $$f $(DESTDIR)$(INST_INCLUDE) ; done
lib: $(OBJ:.o=.$(OBJ_EXT))
(cd .. ; $(MAKE) force-lib)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,820 @@
/******************************************************************************
* $Id: fpolygonize.cpp 22501 2011-06-04 21:28:47Z rouault $
*
* Project: GDAL
* Purpose: Version of Raster to Polygon Converter using float buffers.
* Author: Jorge Arevalo, jorge.arevalo@deimos-space.com. Most of the code
* taken from GDALPolygonize.cpp, by Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2011, Jorge Arevalo
* Copyright (c) 2008, Frank Warmerdam
*
* 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_alg_priv.h"
#include "cpl_conv.h"
#include "cpl_string.h"
#include <vector>
CPL_CVSID("$Id: fpolygonize.cpp 22501 2011-06-04 21:28:47Z rouault $");
#define GP_NODATA_MARKER -51502112
#ifdef OGR_ENABLED
/******************************************************************************/
/* GDALFloatEquals() */
/* Code from: */
/* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */
/******************************************************************************/
GBool GDALFloatEquals(float A, float B)
{
/**
* This function will allow maxUlps-1 floats between A and B.
*/
int maxUlps = MAX_ULPS;
int aInt, bInt;
/**
* Make sure maxUlps is non-negative and small enough that the default NAN
* won't compare as equal to anything.
*/
CPLAssert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
/**
* This assignation could violate strict aliasing. It causes a warning with
* gcc -O2. Use of memcpy preferred. Credits for Even Rouault. Further info
* at http://trac.osgeo.org/gdal/ticket/4005#comment:6
*/
//int aInt = *(int*)&A;
memcpy(&aInt, &A, 4);
/**
* Make aInt lexicographically ordered as a twos-complement int
*/
if (aInt < 0)
aInt = 0x80000000 - aInt;
/**
* Make bInt lexicographically ordered as a twos-complement int
*/
//int bInt = *(int*)&B;
memcpy(&bInt, &B, 4);
if (bInt < 0)
bInt = 0x80000000 - bInt;
int intDiff = abs(aInt - bInt);
if (intDiff <= maxUlps)
return true;
return false;
}
/************************************************************************/
/* ==================================================================== */
/* RPolygonF */
/* */
/* This is a helper class to hold polygons while they are being */
/* formed in memory, and to provide services to coalesce a much */
/* of edge sections into complete rings. */
/* ==================================================================== */
/************************************************************************/
class RPolygonF {
public:
RPolygonF( float fValue ) { fPolyValue = fValue; nLastLineUpdated = -1; }
float fPolyValue;
int nLastLineUpdated;
std::vector< std::vector<int> > aanXY;
void AddSegment( int x1, int y1, int x2, int y2 );
void Dump();
void Coalesce();
void Merge( int iBaseString, int iSrcString, int iDirection );
};
/************************************************************************/
/* Dump() */
/************************************************************************/
void RPolygonF::Dump()
{
size_t iString;
printf( "RPolygonF: Value=%f, LastLineUpdated=%d\n",
fPolyValue, nLastLineUpdated );
for( iString = 0; iString < aanXY.size(); iString++ )
{
std::vector<int> &anString = aanXY[iString];
size_t iVert;
printf( " String %d:\n", (int) iString );
for( iVert = 0; iVert < anString.size(); iVert += 2 )
{
printf( " (%d,%d)\n", anString[iVert], anString[iVert+1] );
}
}
}
/************************************************************************/
/* Coalesce() */
/************************************************************************/
void RPolygonF::Coalesce()
{
size_t iBaseString;
/* -------------------------------------------------------------------- */
/* Iterate over loops starting from the first, trying to merge */
/* other segments into them. */
/* -------------------------------------------------------------------- */
for( iBaseString = 0; iBaseString < aanXY.size(); iBaseString++ )
{
std::vector<int> &anBase = aanXY[iBaseString];
int bMergeHappened = TRUE;
/* -------------------------------------------------------------------- */
/* Keep trying to merge the following strings into our target */
/* "base" string till we have tried them all once without any */
/* mergers. */
/* -------------------------------------------------------------------- */
while( bMergeHappened )
{
size_t iString;
bMergeHappened = FALSE;
/* -------------------------------------------------------------------- */
/* Loop over the following strings, trying to find one we can */
/* merge onto the end of our base string. */
/* -------------------------------------------------------------------- */
for( iString = iBaseString+1;
iString < aanXY.size();
iString++ )
{
std::vector<int> &anString = aanXY[iString];
if( anBase[anBase.size()-2] == anString[0]
&& anBase[anBase.size()-1] == anString[1] )
{
Merge( iBaseString, iString, 1 );
bMergeHappened = TRUE;
}
else if( anBase[anBase.size()-2] == anString[anString.size()-2]
&& anBase[anBase.size()-1] == anString[anString.size()-1] )
{
Merge( iBaseString, iString, -1 );
bMergeHappened = TRUE;
}
}
}
/* At this point our loop *should* be closed! */
CPLAssert( anBase[0] == anBase[anBase.size()-2]
&& anBase[1] == anBase[anBase.size()-1] );
}
}
/************************************************************************/
/* Merge() */
/************************************************************************/
void RPolygonF::Merge( int iBaseString, int iSrcString, int iDirection )
{
std::vector<int> &anBase = aanXY[iBaseString];
std::vector<int> &anString = aanXY[iSrcString];
int iStart, iEnd, i;
if( iDirection == 1 )
{
iStart = 1;
iEnd = anString.size() / 2;
}
else
{
iStart = anString.size() / 2 - 2;
iEnd = -1;
}
for( i = iStart; i != iEnd; i += iDirection )
{
anBase.push_back( anString[i*2+0] );
anBase.push_back( anString[i*2+1] );
}
if( iSrcString < ((int) aanXY.size())-1 )
aanXY[iSrcString] = aanXY[aanXY.size()-1];
size_t nSize = aanXY.size();
aanXY.resize(nSize-1);
}
/************************************************************************/
/* AddSegment() */
/************************************************************************/
void RPolygonF::AddSegment( int x1, int y1, int x2, int y2 )
{
nLastLineUpdated = MAX(y1, y2);
/* -------------------------------------------------------------------- */
/* Is there an existing string ending with this? */
/* -------------------------------------------------------------------- */
size_t iString;
for( iString = 0; iString < aanXY.size(); iString++ )
{
std::vector<int> &anString = aanXY[iString];
size_t nSSize = anString.size();
if( anString[nSSize-2] == x1
&& anString[nSSize-1] == y1 )
{
int nTemp;
nTemp = x2;
x2 = x1;
x1 = nTemp;
nTemp = y2;
y2 = y1;
y1 = nTemp;
}
if( anString[nSSize-2] == x2
&& anString[nSSize-1] == y2 )
{
// We are going to add a segment, but should we just extend
// an existing segment already going in the right direction?
int nLastLen = MAX(ABS(anString[nSSize-4]-anString[nSSize-2]),
ABS(anString[nSSize-3]-anString[nSSize-1]));
if( nSSize >= 4
&& (anString[nSSize-4] - anString[nSSize-2]
== (anString[nSSize-2] - x1)*nLastLen)
&& (anString[nSSize-3] - anString[nSSize-1]
== (anString[nSSize-1] - y1)*nLastLen) )
{
anString.pop_back();
anString.pop_back();
}
anString.push_back( x1 );
anString.push_back( y1 );
return;
}
}
/* -------------------------------------------------------------------- */
/* Create a new string. */
/* -------------------------------------------------------------------- */
size_t nSize = aanXY.size();
aanXY.resize(nSize + 1);
std::vector<int> &anString = aanXY[nSize];
anString.push_back( x1 );
anString.push_back( y1 );
anString.push_back( x2 );
anString.push_back( y2 );
return;
}
/************************************************************************/
/* ==================================================================== */
/* End of RPolygonF */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* AddEdges() */
/* */
/* Examine one pixel and compare to its neighbour above */
/* (previous) and right. If they are different polygon ids */
/* then add the pixel edge to this polygon and the one on the */
/* other side of the edge. */
/************************************************************************/
static void AddEdges( GInt32 *panThisLineId, GInt32 *panLastLineId,
GInt32 *panPolyIdMap, float *pafPolyValue,
RPolygonF **papoPoly, int iX, int iY )
{
int nThisId = panThisLineId[iX];
int nRightId = panThisLineId[iX+1];
int nPreviousId = panLastLineId[iX];
int iXReal = iX - 1;
if( nThisId != -1 )
nThisId = panPolyIdMap[nThisId];
if( nRightId != -1 )
nRightId = panPolyIdMap[nRightId];
if( nPreviousId != -1 )
nPreviousId = panPolyIdMap[nPreviousId];
if( nThisId != nPreviousId )
{
if( nThisId != -1 )
{
if( papoPoly[nThisId] == NULL )
papoPoly[nThisId] = new RPolygonF( pafPolyValue[nThisId] );
papoPoly[nThisId]->AddSegment( iXReal, iY, iXReal+1, iY );
}
if( nPreviousId != -1 )
{
if( papoPoly[nPreviousId] == NULL )
papoPoly[nPreviousId] = new RPolygonF(pafPolyValue[nPreviousId]);
papoPoly[nPreviousId]->AddSegment( iXReal, iY, iXReal+1, iY );
}
}
if( nThisId != nRightId )
{
if( nThisId != -1 )
{
if( papoPoly[nThisId] == NULL )
papoPoly[nThisId] = new RPolygonF(pafPolyValue[nThisId]);
papoPoly[nThisId]->AddSegment( iXReal+1, iY, iXReal+1, iY+1 );
}
if( nRightId != -1 )
{
if( papoPoly[nRightId] == NULL )
papoPoly[nRightId] = new RPolygonF(pafPolyValue[nRightId]);
papoPoly[nRightId]->AddSegment( iXReal+1, iY, iXReal+1, iY+1 );
}
}
}
/************************************************************************/
/* EmitPolygonToLayer() */
/************************************************************************/
static CPLErr
EmitPolygonToLayer( OGRLayerH hOutLayer, int iPixValField,
RPolygonF *poRPoly, double *padfGeoTransform )
{
OGRFeatureH hFeat;
OGRGeometryH hPolygon;
/* -------------------------------------------------------------------- */
/* Turn bits of lines into coherent rings. */
/* -------------------------------------------------------------------- */
poRPoly->Coalesce();
/* -------------------------------------------------------------------- */
/* Create the polygon geometry. */
/* -------------------------------------------------------------------- */
size_t iString;
hPolygon = OGR_G_CreateGeometry( wkbPolygon );
for( iString = 0; iString < poRPoly->aanXY.size(); iString++ )
{
std::vector<int> &anString = poRPoly->aanXY[iString];
OGRGeometryH hRing = OGR_G_CreateGeometry( wkbLinearRing );
int iVert;
// we go last to first to ensure the linestring is allocated to
// the proper size on the first try.
for( iVert = anString.size()/2 - 1; iVert >= 0; iVert-- )
{
double dfX, dfY;
int nPixelX, nPixelY;
nPixelX = anString[iVert*2];
nPixelY = anString[iVert*2+1];
dfX = padfGeoTransform[0]
+ nPixelX * padfGeoTransform[1]
+ nPixelY * padfGeoTransform[2];
dfY = padfGeoTransform[3]
+ nPixelX * padfGeoTransform[4]
+ nPixelY * padfGeoTransform[5];
OGR_G_SetPoint_2D( hRing, iVert, dfX, dfY );
}
OGR_G_AddGeometryDirectly( hPolygon, hRing );
}
/* -------------------------------------------------------------------- */
/* Create the feature object. */
/* -------------------------------------------------------------------- */
hFeat = OGR_F_Create( OGR_L_GetLayerDefn( hOutLayer ) );
OGR_F_SetGeometryDirectly( hFeat, hPolygon );
if( iPixValField >= 0 )
OGR_F_SetFieldDouble( hFeat, iPixValField, (double)poRPoly->fPolyValue );
/* -------------------------------------------------------------------- */
/* Write the to the layer. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
if( OGR_L_CreateFeature( hOutLayer, hFeat ) != OGRERR_NONE )
eErr = CE_Failure;
OGR_F_Destroy( hFeat );
return eErr;
}
/************************************************************************/
/* GPMaskImageData() */
/* */
/* Mask out image pixels to a special nodata value if the mask */
/* band is zero. */
/************************************************************************/
static CPLErr
GPMaskImageData( GDALRasterBandH hMaskBand, GByte* pabyMaskLine, int iY, int nXSize,
float *pafImageLine )
{
CPLErr eErr;
eErr = GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr == CE_None )
{
int i;
for( i = 0; i < nXSize; i++ )
{
if( pabyMaskLine[i] == 0 )
pafImageLine[i] = GP_NODATA_MARKER;
}
}
return eErr;
}
#endif // OGR_ENABLED
/************************************************************************/
/* GDALFPolygonize() */
/************************************************************************/
/**
* Create polygon coverage from raster data.
*
* This function creates vector polygons for all connected regions of pixels in
* the raster sharing a common pixel value. Optionally each polygon may be
* labelled with the pixel value in an attribute. Optionally a mask band
* can be provided to determine which pixels are eligible for processing.
*
* The source pixel band values are read into a 32bit float buffer. If you want
* to use a (probably faster) version using signed 32bit integer buffer, see
* GDALPolygonize() at polygonize.cpp.
*
* Polygon features will be created on the output layer, with polygon
* geometries representing the polygons. The polygon geometries will be
* in the georeferenced coordinate system of the image (based on the
* geotransform of the source dataset). It is acceptable for the output
* layer to already have features. Note that GDALFPolygonize() does not
* set the coordinate system on the output layer. Application code should
* do this when the layer is created, presumably matching the raster
* coordinate system.
*
* The algorithm used attempts to minimize memory use so that very large
* rasters can be processed. However, if the raster has many polygons
* or very large/complex polygons, the memory use for holding polygon
* enumerations and active polygon geometries may grow to be quite large.
*
* The algorithm will generally produce very dense polygon geometries, with
* edges that follow exactly on pixel boundaries for all non-interior pixels.
* For non-thematic raster data (such as satellite images) the result will
* essentially be one small polygon per pixel, and memory and output layer
* sizes will be substantial. The algorithm is primarily intended for
* relatively simple thematic imagery, masks, and classification results.
*
* @param hSrcBand the source raster band to be processed.
* @param hMaskBand an optional mask band. All pixels in the mask band with a
* value other than zero will be considered suitable for collection as
* polygons.
* @param hOutLayer the vector feature layer to which the polygons should
* be written.
* @param iPixValField the attribute field index indicating the feature
* attribute into which the pixel value of the polygon should be written.
* @param papszOptions a name/value list of additional options
* <dl>
* <dt>"8CONNECTED":</dt> May be set to "8" to use 8 connectedness.
* Otherwise 4 connectedness will be applied to the algorithm
* </dl>
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
*
* @return CE_None on success or CE_Failure on a failure.
*
* @since GDAL 1.9.0
*/
CPLErr CPL_STDCALL
GDALFPolygonize( GDALRasterBandH hSrcBand,
GDALRasterBandH hMaskBand,
OGRLayerH hOutLayer, int iPixValField,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
#ifndef OGR_ENABLED
CPLError(CE_Failure, CPLE_NotSupported, "GDALFPolygonize() unimplemented in a non OGR build");
return CE_Failure;
#else
VALIDATE_POINTER1( hSrcBand, "GDALFPolygonize", CE_Failure );
VALIDATE_POINTER1( hOutLayer, "GDALFPolygonize", CE_Failure );
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
int nConnectedness = CSLFetchNameValue( papszOptions, "8CONNECTED" ) ? 8 : 4;
/* -------------------------------------------------------------------- */
/* Confirm our output layer will support feature creation. */
/* -------------------------------------------------------------------- */
if( !OGR_L_TestCapability( hOutLayer, OLCSequentialWrite ) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Output feature layer does not appear to support creation\n"
"of features in GDALFPolygonize()." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Allocate working buffers. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
int nXSize = GDALGetRasterBandXSize( hSrcBand );
int nYSize = GDALGetRasterBandYSize( hSrcBand );
float *pafLastLineVal = (float *) VSIMalloc2(sizeof(float),nXSize + 2);
float *pafThisLineVal = (float *) VSIMalloc2(sizeof(float),nXSize + 2);
GInt32 *panLastLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2);
GInt32 *panThisLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2);
GByte *pabyMaskLine = (hMaskBand != NULL) ? (GByte *) VSIMalloc(nXSize) : NULL;
if (pafLastLineVal == NULL || pafThisLineVal == NULL ||
panLastLineId == NULL || panThisLineId == NULL ||
(hMaskBand != NULL && pabyMaskLine == NULL))
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate enough memory for temporary buffers");
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( pafThisLineVal );
CPLFree( pafLastLineVal );
CPLFree( pabyMaskLine );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Get the geotransform, if there is one, so we can convert the */
/* vectors into georeferenced coordinates. */
/* -------------------------------------------------------------------- */
GDALDatasetH hSrcDS = GDALGetBandDataset( hSrcBand );
double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
if( hSrcDS )
GDALGetGeoTransform( hSrcDS, adfGeoTransform );
/* -------------------------------------------------------------------- */
/* The first pass over the raster is only used to build up the */
/* polygon id map so we will know in advance what polygons are */
/* what on the second pass. */
/* -------------------------------------------------------------------- */
int iY;
GDALRasterFPolygonEnumerator oFirstEnum(nConnectedness);
for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
eErr = GDALRasterIO(
hSrcBand,
GF_Read, 0, iY, nXSize, 1,
pafThisLineVal, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize,
pafThisLineVal );
if( iY == 0 )
oFirstEnum.ProcessLine(
NULL, pafThisLineVal, NULL, panThisLineId, nXSize );
else
oFirstEnum.ProcessLine(
pafLastLineVal, pafThisLineVal,
panLastLineId, panThisLineId,
nXSize );
// swap lines
float * pafTmp = pafLastLineVal;
pafLastLineVal = pafThisLineVal;
pafThisLineVal = pafTmp;
GInt32 * panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.10 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/* -------------------------------------------------------------------- */
oFirstEnum.CompleteMerges();
/* -------------------------------------------------------------------- */
/* Initialize ids to -1 to serve as a nodata value for the */
/* previous line, and past the beginning and end of the */
/* scanlines. */
/* -------------------------------------------------------------------- */
int iX;
panThisLineId[0] = -1;
panThisLineId[nXSize+1] = -1;
for( iX = 0; iX < nXSize+2; iX++ )
panLastLineId[iX] = -1;
/* -------------------------------------------------------------------- */
/* We will use a new enumerator for the second pass primariliy */
/* so we can preserve the first pass map. */
/* -------------------------------------------------------------------- */
GDALRasterFPolygonEnumerator oSecondEnum(nConnectedness);
RPolygonF **papoPoly = (RPolygonF **)
CPLCalloc(sizeof(RPolygonF*),oFirstEnum.nNextPolygonId);
/* ==================================================================== */
/* Second pass during which we will actually collect polygon */
/* edges as geometries. */
/* ==================================================================== */
for( iY = 0; eErr == CE_None && iY < nYSize+1; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read the image data. */
/* -------------------------------------------------------------------- */
if( iY < nYSize )
{
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1,
pafThisLineVal, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize,
pafThisLineVal );
}
if( eErr != CE_None )
continue;
/* -------------------------------------------------------------------- */
/* Determine what polygon the various pixels belong to (redoing */
/* the same thing done in the first pass above). */
/* -------------------------------------------------------------------- */
if( iY == nYSize )
{
for( iX = 0; iX < nXSize+2; iX++ )
panThisLineId[iX] = -1;
}
else if( iY == 0 )
oSecondEnum.ProcessLine(
NULL, pafThisLineVal, NULL, panThisLineId+1, nXSize );
else
oSecondEnum.ProcessLine(
pafLastLineVal, pafThisLineVal,
panLastLineId+1, panThisLineId+1,
nXSize );
/* -------------------------------------------------------------------- */
/* Add polygon edges to our polygon list for the pixel */
/* boundaries within and above this line. */
/* -------------------------------------------------------------------- */
for( iX = 0; iX < nXSize+1; iX++ )
{
AddEdges( panThisLineId, panLastLineId,
oFirstEnum.panPolyIdMap, oFirstEnum.pafPolyValue,
papoPoly, iX, iY );
}
/* -------------------------------------------------------------------- */
/* Periodically we scan out polygons and write out those that */
/* haven't been added to on the last line as we can be sure */
/* they are complete. */
/* -------------------------------------------------------------------- */
if( iY % 8 == 7 )
{
for( iX = 0;
eErr == CE_None && iX < oSecondEnum.nNextPolygonId;
iX++ )
{
if( papoPoly[iX] && papoPoly[iX]->nLastLineUpdated < iY-1 )
{
if( hMaskBand == NULL
|| !GDALFloatEquals(papoPoly[iX]->fPolyValue, GP_NODATA_MARKER) )
{
eErr =
EmitPolygonToLayer( hOutLayer, iPixValField,
papoPoly[iX], adfGeoTransform );
}
delete papoPoly[iX];
papoPoly[iX] = NULL;
}
}
}
/* -------------------------------------------------------------------- */
/* Swap pixel value, and polygon id lines to be ready for the */
/* next line. */
/* -------------------------------------------------------------------- */
float *pafTmp = pafLastLineVal;
pafLastLineVal = pafThisLineVal;
pafThisLineVal = pafTmp;
GInt32 *panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.10 + 0.90 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Make a cleanup pass for all unflushed polygons. */
/* -------------------------------------------------------------------- */
for( iX = 0; eErr == CE_None && iX < oSecondEnum.nNextPolygonId; iX++ )
{
if( papoPoly[iX] )
{
if( hMaskBand == NULL
|| !GDALFloatEquals(papoPoly[iX]->fPolyValue, GP_NODATA_MARKER) )
{
eErr =
EmitPolygonToLayer( hOutLayer, iPixValField,
papoPoly[iX], adfGeoTransform );
}
delete papoPoly[iX];
papoPoly[iX] = NULL;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( pafThisLineVal );
CPLFree( pafLastLineVal );
CPLFree( pabyMaskLine );
CPLFree( papoPoly );
return eErr;
#endif // OGR_ENABLED
}

View file

@ -0,0 +1,482 @@
/******************************************************************************
* $Id: gdal_alg.h 27850 2014-10-12 16:58:09Z rouault $
*
* Project: GDAL Image Processing Algorithms
* Purpose: Prototypes, and definitions for various GDAL based algorithms.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2001, Frank Warmerdam
* Copyright (c) 2008-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.
****************************************************************************/
#ifndef GDAL_ALG_H_INCLUDED
#define GDAL_ALG_H_INCLUDED
/**
* \file gdal_alg.h
*
* Public (C callable) GDAL algorithm entry points, and definitions.
*/
#ifndef DOXYGEN_SKIP
#include "gdal.h"
#include "cpl_minixml.h"
#include "ogr_api.h"
#endif
CPL_C_START
int CPL_DLL CPL_STDCALL GDALComputeMedianCutPCT( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
int (*pfnIncludePixel)(int,int,void*),
int nColors,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg );
int CPL_DLL CPL_STDCALL GDALDitherRGB2PCT( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg );
int CPL_DLL CPL_STDCALL GDALChecksumImage( GDALRasterBandH hBand,
int nXOff, int nYOff, int nXSize, int nYSize );
CPLErr CPL_DLL CPL_STDCALL
GDALComputeProximity( GDALRasterBandH hSrcBand,
GDALRasterBandH hProximityBand,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALFillNodata( GDALRasterBandH hTargetBand,
GDALRasterBandH hMaskBand,
double dfMaxSearchDist,
int bDeprecatedOption,
int nSmoothingIterations,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALPolygonize( GDALRasterBandH hSrcBand,
GDALRasterBandH hMaskBand,
OGRLayerH hOutLayer, int iPixValField,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALFPolygonize( GDALRasterBandH hSrcBand,
GDALRasterBandH hMaskBand,
OGRLayerH hOutLayer, int iPixValField,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
GDALRasterBandH hDstBand,
int nSizeThreshold, int nConnectedness,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
/*
* Warp Related.
*/
typedef int
(*GDALTransformerFunc)( void *pTransformerArg,
int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
#define GDAL_GTI2_SIGNATURE "GTI2"
typedef struct {
GByte abySignature[4];
const char *pszClassName;
GDALTransformerFunc pfnTransform;
void (*pfnCleanup)( void * pTransformerArg );
CPLXMLNode *(*pfnSerialize)( void * pTransformerArg );
void* (*pfnCreateSimilar)( void* pTransformerArg, double dfSrcRatioX, double dfSrcRatioY );
} GDALTransformerInfo;
void CPL_DLL GDALDestroyTransformer( void *pTransformerArg );
int CPL_DLL GDALUseTransformer( void *pTranformerArg,
int bDstToSrc, int nPointCount,
double *x, double *y, double *z,
int *panSuccess );
void* GDALCreateSimilarTransformer( void* psTransformerArg, double dfSrcRatioX, double dfSrcRatioY );
/* High level transformer for going from image coordinates on one file
to image coordiantes on another, potentially doing reprojection,
utilizing GCPs or using the geotransform. */
void CPL_DLL *
GDALCreateGenImgProjTransformer( GDALDatasetH hSrcDS, const char *pszSrcWKT,
GDALDatasetH hDstDS, const char *pszDstWKT,
int bGCPUseOK, double dfGCPErrorThreshold,
int nOrder );
void CPL_DLL *
GDALCreateGenImgProjTransformer2( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
char **papszOptions );
void CPL_DLL *
GDALCreateGenImgProjTransformer3( const char *pszSrcWKT,
const double *padfSrcGeoTransform,
const char *pszDstWKT,
const double *padfDstGeoTransform );
void CPL_DLL GDALSetGenImgProjTransformerDstGeoTransform( void *,
const double * );
void CPL_DLL GDALDestroyGenImgProjTransformer( void * );
int CPL_DLL GDALGenImgProjTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
void GDALSetTransformerDstGeoTransform( void *, const double * );
/* Geo to geo reprojection transformer. */
void CPL_DLL *
GDALCreateReprojectionTransformer( const char *pszSrcWKT,
const char *pszDstWKT );
void CPL_DLL GDALDestroyReprojectionTransformer( void * );
int CPL_DLL GDALReprojectionTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* GCP based transformer ... forward is to georef coordinates */
void CPL_DLL *
GDALCreateGCPTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int nReqOrder, int bReversed );
/* GCP based transformer with refinement of the GCPs ... forward is to georef coordinates */
void CPL_DLL *
GDALCreateGCPRefineTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int nReqOrder, int bReversed, double tolerance, int minimumGcps);
void CPL_DLL GDALDestroyGCPTransformer( void *pTransformArg );
int CPL_DLL GDALGCPTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* Thin Plate Spine transformer ... forward is to georef coordinates */
void CPL_DLL *
GDALCreateTPSTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed );
void CPL_DLL GDALDestroyTPSTransformer( void *pTransformArg );
int CPL_DLL GDALTPSTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
char CPL_DLL ** RPCInfoToMD( GDALRPCInfo *psRPCInfo );
/* RPC based transformer ... src is pixel/line/elev, dst is long/lat/elev */
void CPL_DLL *
GDALCreateRPCTransformer( GDALRPCInfo *psRPC, int bReversed,
double dfPixErrThreshold,
char **papszOptions );
void CPL_DLL GDALDestroyRPCTransformer( void *pTransformArg );
int CPL_DLL GDALRPCTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* Geolocation transformer */
void CPL_DLL *
GDALCreateGeoLocTransformer( GDALDatasetH hBaseDS,
char **papszGeolocationInfo,
int bReversed );
void CPL_DLL GDALDestroyGeoLocTransformer( void *pTransformArg );
int CPL_DLL GDALGeoLocTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* Approximate transformer */
void CPL_DLL *
GDALCreateApproxTransformer( GDALTransformerFunc pfnRawTransformer,
void *pRawTransformerArg, double dfMaxError );
void CPL_DLL GDALApproxTransformerOwnsSubtransformer( void *pCBData,
int bOwnFlag );
void CPL_DLL GDALDestroyApproxTransformer( void *pApproxArg );
int CPL_DLL GDALApproxTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
int CPL_DLL CPL_STDCALL
GDALSimpleImageWarp( GDALDatasetH hSrcDS,
GDALDatasetH hDstDS,
int nBandCount, int *panBandList,
GDALTransformerFunc pfnTransform,
void *pTransformArg,
GDALProgressFunc pfnProgress,
void *pProgressArg,
char **papszWarpOptions );
CPLErr CPL_DLL CPL_STDCALL
GDALSuggestedWarpOutput( GDALDatasetH hSrcDS,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfGeoTransformOut,
int *pnPixels, int *pnLines );
CPLErr CPL_DLL CPL_STDCALL
GDALSuggestedWarpOutput2( GDALDatasetH hSrcDS,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfGeoTransformOut,
int *pnPixels, int *pnLines,
double *padfExtents,
int nOptions );
CPLXMLNode CPL_DLL *
GDALSerializeTransformer( GDALTransformerFunc pfnFunc, void *pTransformArg );
CPLErr CPL_DLL GDALDeserializeTransformer( CPLXMLNode *psTree,
GDALTransformerFunc *ppfnFunc,
void **ppTransformArg );
CPLErr CPL_DLL
GDALTransformGeolocations( GDALRasterBandH hXBand,
GDALRasterBandH hYBand,
GDALRasterBandH hZBand,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
GDALProgressFunc pfnProgress,
void *pProgressArg,
char **papszOptions );
/* -------------------------------------------------------------------- */
/* Contour Line Generation */
/* -------------------------------------------------------------------- */
typedef CPLErr (*GDALContourWriter)( double dfLevel, int nPoints,
double *padfX, double *padfY, void * );
typedef void *GDALContourGeneratorH;
GDALContourGeneratorH CPL_DLL
GDAL_CG_Create( int nWidth, int nHeight,
int bNoDataSet, double dfNoDataValue,
double dfContourInterval, double dfContourBase,
GDALContourWriter pfnWriter, void *pCBData );
CPLErr CPL_DLL GDAL_CG_FeedLine( GDALContourGeneratorH hCG,
double *padfScanline );
void CPL_DLL GDAL_CG_Destroy( GDALContourGeneratorH hCG );
typedef struct
{
void *hLayer;
double adfGeoTransform[6];
int nElevField;
int nIDField;
int nNextID;
} OGRContourWriterInfo;
CPLErr CPL_DLL
OGRContourWriter( double, int, double *, double *, void *pInfo );
CPLErr CPL_DLL
GDALContourGenerate( GDALRasterBandH hBand,
double dfContourInterval, double dfContourBase,
int nFixedLevelCount, double *padfFixedLevels,
int bUseNoData, double dfNoDataValue,
void *hLayer, int iIDField, int iElevField,
GDALProgressFunc pfnProgress, void *pProgressArg );
/************************************************************************/
/* Rasterizer API - geometries burned into GDAL raster. */
/************************************************************************/
CPLErr CPL_DLL
GDALRasterizeGeometries( GDALDatasetH hDS,
int nBandCount, int *panBandList,
int nGeomCount, OGRGeometryH *pahGeometries,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfGeomBurnValue,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL
GDALRasterizeLayers( GDALDatasetH hDS,
int nBandCount, int *panBandList,
int nLayerCount, OGRLayerH *pahLayers,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfLayerBurnValues,
char **papszOptions,
GDALProgressFunc pfnProgress,
void *pProgressArg );
CPLErr CPL_DLL
GDALRasterizeLayersBuf( void *pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType, int nPixelSpace, int nLineSpace,
int nLayerCount, OGRLayerH *pahLayers,
const char *pszDstProjection,
double *padfDstGeoTransform,
GDALTransformerFunc pfnTransformer,
void *pTransformArg, double dfBurnValue,
char **papszOptions, GDALProgressFunc pfnProgress,
void *pProgressArg );
/************************************************************************/
/* Gridding interface. */
/************************************************************************/
/** Gridding Algorithms */
typedef enum {
/*! Inverse distance to a power */ GGA_InverseDistanceToAPower = 1,
/*! Moving Average */ GGA_MovingAverage = 2,
/*! Nearest Neighbor */ GGA_NearestNeighbor = 3,
/*! Minimum Value (Data Metric) */ GGA_MetricMinimum = 4,
/*! Maximum Value (Data Metric) */ GGA_MetricMaximum = 5,
/*! Data Range (Data Metric) */ GGA_MetricRange = 6,
/*! Number of Points (Data Metric) */ GGA_MetricCount = 7,
/*! Average Distance (Data Metric) */ GGA_MetricAverageDistance = 8,
/*! Average Distance Between Data Points (Data Metric) */
GGA_MetricAverageDistancePts = 9
} GDALGridAlgorithm;
/** Inverse distance to a power method control options */
typedef struct
{
/*! Weighting power. */
double dfPower;
/*! Smoothing parameter. */
double dfSmoothing;
/*! Reserved for future use. */
double dfAnisotropyRatio;
/*! Reserved for future use. */
double dfAnisotropyAngle;
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! Maximum number of data points to use.
*
* Do not search for more points than this number.
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMaxPoints;
/*! Minimum number of data points to use.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridInverseDistanceToAPowerOptions;
/** Moving average method control options */
typedef struct
{
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! Minimum number of data points to average.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridMovingAverageOptions;
/** Nearest neighbor method control options */
typedef struct
{
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridNearestNeighborOptions;
/** Data metrics method control options */
typedef struct
{
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! Minimum number of data points to average.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridDataMetricsOptions;
CPLErr CPL_DLL
GDALGridCreate( GDALGridAlgorithm, const void *, GUInt32,
const double *, const double *, const double *,
double, double, double, double,
GUInt32, GUInt32, GDALDataType, void *,
GDALProgressFunc, void *);
GDAL_GCP CPL_DLL *
GDALComputeMatchingPoints( GDALDatasetH hFirstImage,
GDALDatasetH hSecondImage,
char **papszOptions,
int *pnGCPCount );
CPL_C_END
#endif /* ndef GDAL_ALG_H_INCLUDED */

View file

@ -0,0 +1,229 @@
/******************************************************************************
* $Id: gdal_alg_priv.h 28826 2015-03-30 17:51:14Z rouault $
*
* Project: GDAL Image Processing Algorithms
* Purpose: Prototypes and definitions for various GDAL based algorithms:
* private declarations.
* Author: Andrey Kiselev, dron@ak4719.spb.edu
*
******************************************************************************
* Copyright (c) 2008, Andrey Kiselev <dron@ak4719.spb.edu>
* Copyright (c) 2010-2013, 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.
****************************************************************************/
#ifndef GDAL_ALG_PRIV_H_INCLUDED
#define GDAL_ALG_PRIV_H_INCLUDED
#include "gdal_alg.h"
CPL_C_START
/** Source of the burn value */
typedef enum {
/*! Use value from padfBurnValue */ GBV_UserBurnValue = 0,
/*! Use value from the Z coordinate */ GBV_Z = 1,
/*! Use value form the M value */ GBV_M = 2
} GDALBurnValueSrc;
typedef enum {
GRMA_Replace = 0,
GRMA_Add = 1,
} GDALRasterMergeAlg;
typedef struct {
unsigned char * pabyChunkBuf;
int nXSize;
int nYSize;
int nBands;
GDALDataType eType;
double *padfBurnValue;
GDALBurnValueSrc eBurnValueSource;
GDALRasterMergeAlg eMergeAlg;
} GDALRasterizeInfo;
/************************************************************************/
/* Low level rasterizer API. */
/************************************************************************/
typedef void (*llScanlineFunc)( void *, int, int, int, double );
typedef void (*llPointFunc)( void *, int, int, double );
void GDALdllImagePoint( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData );
void GDALdllImageLine( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData );
void GDALdllImageLineAllTouched(int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY,
double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData );
void GDALdllImageFilledPolygon(int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY,
double *padfVariant,
llScanlineFunc pfnScanlineFunc, void *pCBData );
CPL_C_END
/************************************************************************/
/* Polygon Enumerator */
/************************************************************************/
#define GP_NODATA_MARKER -51502112
class GDALRasterPolygonEnumerator
{
private:
void MergePolygon( int nSrcId, int nDstId );
int NewPolygon( GInt32 nValue );
public: // these are intended to be readonly.
GInt32 *panPolyIdMap;
GInt32 *panPolyValue;
int nNextPolygonId;
int nPolyAlloc;
int nConnectedness;
public:
GDALRasterPolygonEnumerator( int nConnectedness=4 );
~GDALRasterPolygonEnumerator();
void ProcessLine( GInt32 *panLastLineVal, GInt32 *panThisLineVal,
GInt32 *panLastLineId, GInt32 *panThisLineId,
int nXSize );
void CompleteMerges();
void Clear();
};
#ifdef OGR_ENABLED
/************************************************************************/
/* Polygon Enumerator */
/* */
/* Buffers has float values instead og GInt32 */
/************************************************************************/
class GDALRasterFPolygonEnumerator
{
private:
void MergePolygon( int nSrcId, int nDstId );
int NewPolygon( float fValue );
public: // these are intended to be readonly.
GInt32 *panPolyIdMap;
float *pafPolyValue;
int nNextPolygonId;
int nPolyAlloc;
int nConnectedness;
public:
GDALRasterFPolygonEnumerator( int nConnectedness=4 );
~GDALRasterFPolygonEnumerator();
void ProcessLine( float *pafLastLineVal, float *pafThisLineVal,
GInt32 *panLastLineId, GInt32 *panThisLineId,
int nXSize );
void CompleteMerges();
void Clear();
};
#endif
typedef void* (*GDALTransformDeserializeFunc)( CPLXMLNode *psTree );
void* GDALRegisterTransformDeserializer(const char* pszTransformName,
GDALTransformerFunc pfnTransformerFunc,
GDALTransformDeserializeFunc pfnDeserializeFunc);
void GDALUnregisterTransformDeserializer(void* pData);
void GDALCleanupTransformDeserializerMutex();
/* Transformer cloning */
void* GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed, char** papszOptions );
void CPL_DLL * GDALCloneTransformer( void *pTranformerArg );
/************************************************************************/
/* Color table related */
/************************************************************************/
int
GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GByte* pabyRedBand,
GByte* pabyGreenBand,
GByte* pabyBlueBand,
int (*pfnIncludePixel)(int,int,void*),
int nColors,
int nBits,
int* panHistogram,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg );
int GDALDitherRGB2PCTInternal( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
int nBits,
GInt16* pasDynamicColorMap,
int bDither,
GDALProgressFunc pfnProgress,
void * pProgressArg );
#define PRIME_FOR_65536 98317
#define MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 (6 * sizeof(int) * PRIME_FOR_65536)
/************************************************************************/
/* Float comparison function. */
/************************************************************************/
/**
* Units in the Last Place. This specifies how big an error we are willing to
* accept in terms of the value of the least significant digit of the floating
* point numbers representation. MAX_ULPS can also be interpreted in terms of
* how many representable floats we are willing to accept between A and B.
*/
#define MAX_ULPS 10
GBool GDALFloatEquals(float A, float B);
#endif /* ndef GDAL_ALG_PRIV_H_INCLUDED */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,287 @@
/******************************************************************************
* $Id: gdal_nrgcrs.c 23156 2011-10-01 15:34:16Z rouault $
*
* Project: Mapinfo Image Warper
* Purpose: Implemention of the GDALTransformer wrapper around CRS.C functions
* to build a polynomial transformation based on ground control
* points.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
***************************************************************************
* Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
*
* 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_alg.h"
#include "cpl_conv.h"
#include "cpl_minixml.h"
extern int TwoDPolyFit( double *, double *, int, int, double *, double *, double * );
extern double TwoDPolyEval( double *, int, double, double );
typedef struct
{
double adfToGeoX[20];
double adfToGeoY[20];
double adfFromGeoX[20];
double adfFromGeoY[20];
int nOrder;
int bReversed;
} GCPTransformInfo;
/************************************************************************/
/* GDALCreateGCPTransformer() */
/************************************************************************/
/**
* Create GCP based polynomial transformer.
*
* Computes least squares fit polynomials from a provided set of GCPs,
* and stores the coefficients for later transformation of points between
* pixel/line and georeferenced coordinates.
*
* The return value should be used as a TransformArg in combination with
* the transformation function GDALGCPTransform which fits the
* GDALTransformerFunc signature. The returned transform argument should
* be deallocated with GDALDestroyGCPTransformer when no longer needed.
*
* This function may fail (returning NULL) if the provided set of GCPs
* are inadequate for the requested order, the determinate is zero or they
* are otherwise "ill conditioned".
*
* Note that 2nd order requires at least 6 GCPs, and 3rd order requires at
* least 10 gcps. If nReqOrder is 0 the highest order possible with the
* provided gcp count will be used.
*
* @param nGCPCount the number of GCPs in pasGCPList.
* @param pasGCPList an array of GCPs to be used as input.
* @param nReqOrder the requested polynomial order. It should be 1, 2 or 3.
* @param bReversed set it to TRUE to compute the reversed transformation.
*
* @return the transform argument or NULL if creation fails.
*/
void *GDALCreateGCPTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int nReqOrder, int bReversed )
{
GCPTransformInfo *psInfo;
double *padfGeoX, *padfGeoY, *padfRasterX, *padfRasterY;
int *panStatus, iGCP;
double rms_err;
if( nReqOrder == 0 )
{
if( nGCPCount >= 10 )
nReqOrder = 3;
else if( nGCPCount >= 6 )
nReqOrder = 2;
else
nReqOrder = 1;
}
psInfo = (GCPTransformInfo *) CPLCalloc(sizeof(GCPTransformInfo),1);
psInfo->bReversed = bReversed;
psInfo->nOrder = nReqOrder;
/* -------------------------------------------------------------------- */
/* Allocate and initialize the working points list. */
/* -------------------------------------------------------------------- */
padfGeoX = (double *) CPLCalloc(sizeof(double),nGCPCount);
padfGeoY = (double *) CPLCalloc(sizeof(double),nGCPCount);
padfRasterX = (double *) CPLCalloc(sizeof(double),nGCPCount);
padfRasterY = (double *) CPLCalloc(sizeof(double),nGCPCount);
panStatus = (int *) CPLCalloc(sizeof(int),nGCPCount);
for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
{
panStatus[iGCP] = 1;
padfGeoX[iGCP] = pasGCPList[iGCP].dfGCPX;
padfGeoY[iGCP] = pasGCPList[iGCP].dfGCPY;
padfRasterX[iGCP] = pasGCPList[iGCP].dfGCPPixel;
padfRasterY[iGCP] = pasGCPList[iGCP].dfGCPLine;
}
/* -------------------------------------------------------------------- */
/* Compute the forward and reverse polynomials. */
/* -------------------------------------------------------------------- */
if ( TwoDPolyFit( &rms_err, psInfo->adfFromGeoX, nReqOrder, nGCPCount,
padfRasterX, padfGeoX, padfGeoY ) < 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to compute polynomial equations of desired order\n"
"for provided control points." );
goto CleanupAfterError;
}
if ( TwoDPolyFit( &rms_err, psInfo->adfFromGeoY, nReqOrder, nGCPCount,
padfRasterY, padfGeoX, padfGeoY ) < 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to compute polynomial equations of desired order\n"
"for provided control points." );
goto CleanupAfterError;
}
if ( TwoDPolyFit( &rms_err, psInfo->adfToGeoX, nReqOrder, nGCPCount,
padfGeoX, padfRasterX, padfRasterY ) < 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to compute polynomial equations of desired order\n"
"for provided control points." );
goto CleanupAfterError;
}
if ( TwoDPolyFit( &rms_err, psInfo->adfToGeoY, nReqOrder, nGCPCount,
padfGeoY, padfRasterX, padfRasterY ) < 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to compute polynomial equations of desired order\n"
"for provided control points." );
goto CleanupAfterError;
}
/* -------------------------------------------------------------------- */
/* Dump residuals. */
/* -------------------------------------------------------------------- */
CPLDebug( "GDALCreateGCPTransformer",
"Number of GCPs %d, transformation order %d",
nGCPCount, psInfo->nOrder );
for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
{
double x = pasGCPList[iGCP].dfGCPX;
double y = pasGCPList[iGCP].dfGCPY;
double z = pasGCPList[iGCP].dfGCPZ;
int bSuccess;
GDALGCPTransform( psInfo, TRUE, 1, &x, &y, &z, &bSuccess );
CPLDebug( "GDALCreateGCPTransformer",
"GCP %d. Residuals: X: %f, Y: %f", iGCP,
pasGCPList[iGCP].dfGCPPixel - x, pasGCPList[iGCP].dfGCPLine - y );
}
return psInfo;
CleanupAfterError:
CPLFree( padfGeoX );
CPLFree( padfGeoY );
CPLFree( padfRasterX );
CPLFree( padfRasterX );
CPLFree( panStatus );
CPLFree( psInfo );
return NULL;
}
/************************************************************************/
/* GDALDestroyGCPTransformer() */
/************************************************************************/
/**
* Destroy GCP transformer.
*
* This function is used to destroy information about a GCP based
* polynomial transformation created with GDALCreateGCPTransformer().
*
* @param pTransformArg the transform arg previously returned by
* GDALCreateGCPTransformer().
*/
void GDALDestroyGCPTransformer( void *pTransformArg )
{
CPLFree( pTransformArg );
}
/************************************************************************/
/* GDALGCPTransform() */
/************************************************************************/
/**
* Transforms point based on GCP derived polynomial model.
*
* This function matches the GDALTransformerFunc signature, and can be
* used to transform one or more points from pixel/line coordinates to
* georeferenced coordinates (SrcToDst) or vice versa (DstToSrc).
*
* @param pTransformArg return value from GDALCreateGCPTransformer().
* @param bDstToSrc TRUE if transformation is from the destination
* (georeferenced) coordinates to pixel/line or FALSE when transforming
* from pixel/line to georeferenced coordinates.
* @param nPointCount the number of values in the x, y and z arrays.
* @param x array containing the X values to be transformed.
* @param y array containing the Y values to be transformed.
* @param z array containing the Z values to be transformed.
* @param panSuccess array in which a flag indicating success (TRUE) or
* failure (FALSE) of the transformation are placed.
*
* @return TRUE.
*/
int GDALGCPTransform( void *pTransformArg, int bDstToSrc,
int nPointCount,
double *x, double *y, double *z,
int *panSuccess )
{
int i;
double X, Y;
GCPTransformInfo *psInfo = (GCPTransformInfo *) pTransformArg;
if( psInfo->bReversed )
bDstToSrc = !bDstToSrc;
for( i = 0; i < nPointCount; i++ )
{
X = x[i];
Y = y[i];
if( bDstToSrc )
{
x[i] = TwoDPolyEval( psInfo->adfFromGeoX, psInfo->nOrder, X, Y );
y[i] = TwoDPolyEval( psInfo->adfFromGeoY, psInfo->nOrder, X, Y );
}
else
{
x[i] = TwoDPolyEval( psInfo->adfToGeoX, psInfo->nOrder, X, Y );
y[i] = TwoDPolyEval( psInfo->adfToGeoY, psInfo->nOrder, X, Y );
}
z[i] = 0;
panSuccess[i] = TRUE;
}
return TRUE;
}
CPLXMLNode *GDALSerializeGCPTransformer( void *pTransformArg )
{
CPLError( CE_Failure, CPLE_AppDefined,
"serialization not supported for this type of gcp transformer.");
return NULL;
}
void *GDALDeserializeGCPTransformer( CPLXMLNode *psTree )
{
CPLError( CE_Failure, CPLE_AppDefined,
"deserialization not supported for this type of gcp transformer.");
return NULL;
}

View file

@ -0,0 +1,301 @@
/******************************************************************************
* Project: GDAL
* Purpose: Correlator
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Andrew Migal
*
* 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_simplesurf.h"
CPL_CVSID("$Id");
/************************************************************************/
/* ==================================================================== */
/* GDALIntegralImage */
/* ==================================================================== */
/************************************************************************/
GDALIntegralImage::GDALIntegralImage()
{
pMatrix = 0;
nHeight = 0;
nWidth = 0;
}
int GDALIntegralImage::GetHeight() { return nHeight; }
int GDALIntegralImage::GetWidth() { return nWidth; }
void GDALIntegralImage::Initialize(const double **padfImg, int nHeight, int nWidth)
{
//Memory allocation
pMatrix = new double*[nHeight];
for (int i = 0; i < nHeight; i++)
pMatrix[i] = new double[nWidth];
this->nHeight = nHeight;
this->nWidth = nWidth;
//Integral image calculation
for (int i = 0; i < nHeight; i++)
for (int j = 0; j < nWidth; j++)
{
double val = padfImg[i][j];
double a = 0, b = 0, c = 0;
if (i - 1 >= 0 && j - 1 >= 0)
a = pMatrix[i - 1][j - 1];
if (j - 1 >= 0)
b = pMatrix[i][j - 1];
if (i - 1 >= 0)
c = pMatrix[i - 1][j];
//New value based on previous calculations
pMatrix[i][j] = val - a + b + c;
}
}
/*
* Returns value of specified cell
*/
double GDALIntegralImage::GetValue(int nRow, int nCol)
{
if ((nRow >= 0 && nRow < nHeight) && (nCol >= 0 && nCol < nWidth))
return pMatrix[nRow][nCol];
else
return 0;
}
double GDALIntegralImage::GetRectangleSum(int nRow, int nCol, int nWidth, int nHeight)
{
double a = 0, b = 0, c = 0, d = 0;
//Left top point of rectangle is first
int w = nWidth - 1;
int h = nHeight - 1;
int row = nRow;
int col = nCol;
//Left top point
int lt_row = (row <= this->nHeight) ? (row - 1) : -1;
int lt_col = (col <= this->nWidth) ? (col - 1) : -1;
//Right bottom point of the rectangle
int rb_row = (row + h < this->nHeight) ? (row + h) : (this->nHeight - 1);
int rb_col = (col + w < this->nWidth) ? (col + w) : (this->nWidth - 1);
if (lt_row >= 0 && lt_col >= 0)
a = this->GetValue(lt_row, lt_col);
if (lt_row >= 0 && rb_col >= 0)
b = this->GetValue(lt_row, rb_col);
if (rb_row >= 0 && rb_col >= 0)
c = this->GetValue(rb_row, rb_col);
if (rb_row >= 0 && lt_col >= 0)
d = this->GetValue(rb_row, lt_col);
double res = a + c - b - d;
return (res > 0) ? res : 0;
}
double GDALIntegralImage::HaarWavelet_X(int nRow, int nCol, int nSize)
{
return GetRectangleSum(nRow, nCol + nSize / 2, nSize / 2, nSize)
- GetRectangleSum(nRow, nCol, nSize / 2, nSize);
}
double GDALIntegralImage::HaarWavelet_Y(int nRow, int nCol, int nSize)
{
return GetRectangleSum(nRow + nSize / 2, nCol, nSize, nSize / 2)
- GetRectangleSum(nRow, nCol, nSize, nSize / 2);
}
GDALIntegralImage::~GDALIntegralImage()
{
//Clean up memory
for (int i = 0; i < nHeight; i++)
delete[] pMatrix[i];
delete[] pMatrix;
}
/************************************************************************/
/* ==================================================================== */
/* GDALOctaveLayer */
/* ==================================================================== */
/************************************************************************/
GDALOctaveLayer::GDALOctaveLayer(int nOctave, int nInterval)
{
this->octaveNum = nOctave;
this->filterSize = 3 * ((int)pow(2.0, nOctave) * nInterval + 1);
this->radius = (this->filterSize - 1) / 2;
this->scale = (int)pow(2.0, nOctave);
this->width = 0;
this->height = 0;
this->detHessians = 0;
this->signs = 0;
}
void GDALOctaveLayer::ComputeLayer(GDALIntegralImage *poImg)
{
this->width = poImg->GetWidth();
this->height = poImg->GetHeight();
//Allocate memory for arrays
this->detHessians = new double*[this->height];
this->signs = new int*[this->height];
for (int i = 0; i < this->height; i++)
{
this->detHessians[i] = new double[this->width];
this->signs[i] = new int[this->width];
}
//End Allocate memory for arrays
//Values of Fast Hessian filters
double dxx, dyy, dxy;
// 1/3 of filter side
int lobe = filterSize / 3;
//Length of the longer side of the lobe in dxx and dyy filters
int longPart = 2 * lobe - 1;
int normalization = filterSize * filterSize;
//Loop over image pixels
//Filter should remain into image borders
for (int r = radius; r <= height - radius; r++)
for (int c = radius; c <= width - radius; c++)
{
dxx = poImg->GetRectangleSum(r - lobe + 1, c - radius, filterSize, longPart)
- 3 * poImg->GetRectangleSum(r - lobe + 1, c - (lobe - 1) / 2, lobe, longPart);
dyy = poImg->GetRectangleSum(r - radius, c - lobe - 1, longPart, filterSize)
- 3 * poImg->GetRectangleSum(r - lobe + 1, c - lobe + 1, longPart, lobe);
dxy = poImg->GetRectangleSum(r - lobe, c - lobe, lobe, lobe)
+ poImg->GetRectangleSum(r + 1, c + 1, lobe, lobe)
- poImg->GetRectangleSum(r - lobe, c + 1, lobe, lobe)
- poImg->GetRectangleSum(r + 1, c - lobe, lobe, lobe);
dxx /= normalization;
dyy /= normalization;
dxy /= normalization;
//Memorize Hessian values and their signs
detHessians[r][c] = dxx * dyy - 0.9 * 0.9 * dxy * dxy;
signs[r][c] = (dxx + dyy >= 0) ? 1 : -1;
}
}
GDALOctaveLayer::~GDALOctaveLayer()
{
for (int i = 0; i < height; i++)
{
delete[] detHessians[i];
delete[] signs[i];
}
delete[] detHessians;
delete[] signs;
}
/************************************************************************/
/* ==================================================================== */
/* GDALOctaveMap */
/* ==================================================================== */
/************************************************************************/
GDALOctaveMap::GDALOctaveMap(int nOctaveStart, int nOctaveEnd)
{
this->octaveStart = nOctaveStart;
this->octaveEnd = nOctaveEnd;
pMap = new GDALOctaveLayer**[octaveEnd];
for (int i = 0; i < nOctaveEnd; i++)
pMap[i] = new GDALOctaveLayer*[INTERVALS];
for (int oct = octaveStart; oct <= octaveEnd; oct++)
for (int i = 1; i <= INTERVALS; i++)
pMap[oct - 1][i - 1] = new GDALOctaveLayer(oct, i);
}
void GDALOctaveMap::ComputeMap(GDALIntegralImage *poImg)
{
for (int oct = octaveStart; oct <= octaveEnd; oct++)
for (int i = 1; i <= INTERVALS; i++)
pMap[oct - 1][i - 1]->ComputeLayer(poImg);
}
bool GDALOctaveMap::PointIsExtremum(int row, int col, GDALOctaveLayer *bot,
GDALOctaveLayer *mid, GDALOctaveLayer *top, double threshold)
{
//Check that point in middle layer has all neighbours
if (row <= top->radius || col <= top->radius ||
row + top->radius >= top->height || col + top->radius >= top->width)
return false;
double curPoint = mid->detHessians[row][col];
//Hessian should be higher than threshold
if (curPoint < threshold)
return false;
//Hessian should be higher than hessians of all neighbours
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
{
double topPoint = top->detHessians[row + i][col + j];
double midPoint = mid->detHessians[row + i][col + j];
double botPoint = bot->detHessians[row + i][col + j];
if (topPoint >= curPoint || botPoint >= curPoint)
return false;
if (i != 0 || j != 0)
if (midPoint >= curPoint)
return false;
}
return true;
}
GDALOctaveMap::~GDALOctaveMap()
{
// Clean up Octave layers
for (int oct = octaveStart; oct <= octaveEnd; oct++)
for(int i = 0; i < INTERVALS; i++)
delete pMap[oct - 1][i];
//Clean up allocated memory
for (int oct = 0; oct < octaveEnd; oct++)
delete[] pMap[oct];
delete[] pMap;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,522 @@
/******************************************************************************
* Project: GDAL
* Purpose: Correlator - GDALSimpleSURF and GDALFeaturePoint classes.
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Andrew Migal
*
* 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_simplesurf.h"
CPL_CVSID("$Id");
/************************************************************************/
/* ==================================================================== */
/* GDALFeaturePoint */
/* ==================================================================== */
/************************************************************************/
GDALFeaturePoint::GDALFeaturePoint()
{
nX = -1;
nY = -1;
nScale = -1;
nRadius = -1;
nSign = -1;
padfDescriptor = new double[DESC_SIZE];
}
GDALFeaturePoint::GDALFeaturePoint(const GDALFeaturePoint& fp)
{
nX = fp.nX;
nY = fp.nY;
nScale = fp.nScale;
nRadius = fp.nRadius;
nSign = fp.nSign;
padfDescriptor = new double[DESC_SIZE];
for (int i = 0; i < DESC_SIZE; i++)
padfDescriptor[i] = fp.padfDescriptor[i];
}
GDALFeaturePoint::GDALFeaturePoint(int nX, int nY,
int nScale, int nRadius, int nSign)
{
this->nX = nX;
this->nY = nY;
this->nScale = nScale;
this->nRadius = nRadius;
this->nSign = nSign;
this->padfDescriptor = new double[DESC_SIZE];
}
GDALFeaturePoint& GDALFeaturePoint::operator=(const GDALFeaturePoint& point)
{
if (this != &point)
{
nX = point.nX;
nY = point.nY;
nScale = point.nScale;
nRadius = point.nRadius;
nSign = point.nSign;
//Free memory
delete[] padfDescriptor;
//Copy descriptor values
padfDescriptor = new double[DESC_SIZE];
for (int i = 0; i < DESC_SIZE; i++)
padfDescriptor[i] = point.padfDescriptor[i];
}
return *this;
}
int GDALFeaturePoint::GetX() { return nX; }
void GDALFeaturePoint::SetX(int nX) { this->nX = nX; }
int GDALFeaturePoint::GetY() { return nY; }
void GDALFeaturePoint::SetY(int nY) { this->nY = nY; }
int GDALFeaturePoint::GetScale() { return nScale; }
void GDALFeaturePoint::SetScale(int nScale) { this->nScale = nScale; }
int GDALFeaturePoint::GetRadius() { return nRadius; }
void GDALFeaturePoint::SetRadius(int nRadius) { this->nRadius = nRadius; }
int GDALFeaturePoint::GetSign() { return nSign; }
void GDALFeaturePoint::SetSign(int nSign) { this->nSign = nSign; }
double& GDALFeaturePoint::operator [] (int nIndex)
{
if (nIndex < 0 || nIndex >= DESC_SIZE)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Descriptor index is out of range");
}
return padfDescriptor[nIndex];
}
GDALFeaturePoint::~GDALFeaturePoint() {
delete[] padfDescriptor;
}
/************************************************************************/
/* ==================================================================== */
/* GDALSimpleSurf */
/* ==================================================================== */
/************************************************************************/
GDALSimpleSURF::GDALSimpleSURF(int nOctaveStart, int nOctaveEnd)
{
this->octaveStart = nOctaveStart;
this->octaveEnd = nOctaveEnd;
// Initialize Octave map with custom range
poOctMap = new GDALOctaveMap(octaveStart, octaveEnd);
}
CPLErr GDALSimpleSURF::ConvertRGBToLuminosity(
GDALRasterBand *red, GDALRasterBand *green, GDALRasterBand *blue,
int nXSize, int nYSize, double **padfImg, int nHeight, int nWidth)
{
const double forRed = 0.21;
const double forGreen = 0.72;
const double forBlue = 0.07;
if (red == NULL || green == NULL || blue == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Raster bands are not specified");
return CE_Failure;
}
if (nXSize > red->GetXSize() || nYSize > red->GetYSize())
{
CPLError(CE_Failure, CPLE_AppDefined,
"Red band has less size than has been requested");
return CE_Failure;
}
if (padfImg == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Buffer isn't specified");
return CE_Failure;
}
GDALDataType eRedType = red->GetRasterDataType();
GDALDataType eGreenType = green->GetRasterDataType();
GDALDataType eBlueType = blue->GetRasterDataType();
int dataRedSize = GDALGetDataTypeSize(eRedType) / 8;
int dataGreenSize = GDALGetDataTypeSize(eGreenType) / 8;
int dataBlueSize = GDALGetDataTypeSize(eBlueType) / 8;
void *paRedLayer = CPLMalloc(dataRedSize * nWidth * nHeight);
void *paGreenLayer = CPLMalloc(dataGreenSize * nWidth * nHeight);
void *paBlueLayer = CPLMalloc(dataBlueSize * nWidth * nHeight);
red->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paRedLayer, nWidth, nHeight, eRedType, 0, 0, NULL);
green->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paGreenLayer, nWidth, nHeight, eGreenType, 0, 0, NULL);
blue->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paBlueLayer, nWidth, nHeight, eBlueType, 0, 0, NULL);
double maxValue = 255.0;
for (int row = 0; row < nHeight; row++)
for (int col = 0; col < nWidth; col++)
{
// Get RGB values
double dfRedVal = SRCVAL(paRedLayer, eRedType,
nWidth * row + col * dataRedSize);
double dfGreenVal = SRCVAL(paGreenLayer, eGreenType,
nWidth * row + col * dataGreenSize);
double dfBlueVal = SRCVAL(paBlueLayer, eBlueType,
nWidth * row + col * dataBlueSize);
// Compute luminosity value
padfImg[row][col] = (
dfRedVal * forRed +
dfGreenVal * forGreen +
dfBlueVal * forBlue) / maxValue;
}
CPLFree(paRedLayer);
CPLFree(paGreenLayer);
CPLFree(paBlueLayer);
return CE_None;
}
std::vector<GDALFeaturePoint>*
GDALSimpleSURF::ExtractFeaturePoints(GDALIntegralImage *poImg,
double dfThreshold)
{
std::vector<GDALFeaturePoint>* poCollection =
new std::vector<GDALFeaturePoint>();
//Calc Hessian values for layers
poOctMap->ComputeMap(poImg);
//Search for exremum points
for (int oct = octaveStart; oct <= octaveEnd; oct++)
{
for (int k = 0; k < GDALOctaveMap::INTERVALS - 2; k++)
{
GDALOctaveLayer *bot = poOctMap->pMap[oct - 1][k];
GDALOctaveLayer *mid = poOctMap->pMap[oct - 1][k + 1];
GDALOctaveLayer *top = poOctMap->pMap[oct - 1][k + 2];
for (int i = 0; i < mid->height; i++)
{
for (int j = 0; j < mid->width; j++)
{
if (poOctMap->PointIsExtremum(i, j, bot, mid, top, dfThreshold))
{
GDALFeaturePoint oFP(j, i, mid->scale,
mid->radius, mid->signs[i][j]);
SetDescriptor(&oFP, poImg);
poCollection->push_back(oFP);
}
}
}
}
}
return poCollection;
}
double GDALSimpleSURF::GetEuclideanDistance(
GDALFeaturePoint &firstPoint, GDALFeaturePoint &secondPoint)
{
double sum = 0;
for (int i = 0; i < GDALFeaturePoint::DESC_SIZE; i++)
sum += (firstPoint[i] - secondPoint[i]) * (firstPoint[i] - secondPoint[i]);
return sqrt(sum);
}
void GDALSimpleSURF::NormalizeDistances(std::list<MatchedPointPairInfo> *poList)
{
double max = 0;
std::list<MatchedPointPairInfo>::iterator i;
for (i = poList->begin(); i != poList->end(); i++)
if ((*i).euclideanDist > max)
max = (*i).euclideanDist;
if (max != 0)
{
for (i = poList->begin(); i != poList->end(); i++)
(*i).euclideanDist /= max;
}
}
void GDALSimpleSURF::SetDescriptor(
GDALFeaturePoint *poPoint, GDALIntegralImage *poImg)
{
// Affects to the descriptor area
const int haarScale = 20;
// Side of the Haar wavelet
int haarFilterSize = 2 * poPoint->GetScale();
// Length of the side of the descriptor area
int descSide = haarScale * poPoint->GetScale();
// Side of the quadrant in 4x4 grid
int quadStep = descSide / 4;
// Side of the sub-quadrant in 5x5 regular grid of quadrant
int subQuadStep = quadStep / 5;
int leftTop_row = poPoint->GetY() - (descSide / 2);
int leftTop_col = poPoint->GetX() - (descSide / 2);
int count = 0;
for (int r = leftTop_row; r < leftTop_row + descSide; r += quadStep)
for (int c = leftTop_col; c < leftTop_col + descSide; c += quadStep)
{
double dx = 0;
double dy = 0;
double abs_dx = 0;
double abs_dy = 0;
for (int sub_r = r; sub_r < r + quadStep; sub_r += subQuadStep)
for (int sub_c = c; sub_c < c + quadStep; sub_c += subQuadStep)
{
// Approximate center of sub quadrant
int cntr_r = sub_r + subQuadStep / 2;
int cntr_c = sub_c + subQuadStep / 2;
// Left top point for Haar wavelet computation
int cur_r = cntr_r - haarFilterSize / 2;
int cur_c = cntr_c - haarFilterSize / 2;
// Gradients
double cur_dx = poImg->HaarWavelet_X(cur_r, cur_c, haarFilterSize);
double cur_dy = poImg->HaarWavelet_Y(cur_r, cur_c, haarFilterSize);
dx += cur_dx;
dy += cur_dy;
abs_dx += fabs(cur_dx);
abs_dy += fabs(cur_dy);
}
// Fills point's descriptor
(*poPoint)[count++] = dx;
(*poPoint)[count++] = dy;
(*poPoint)[count++] = abs_dx;
(*poPoint)[count++] = abs_dy;
}
}
/**
* Find corresponding points (equal points in two collections).
*
* @param poMatched Resulting collection for matched points
* @param poFirstCollection Points on the first image
* @param poSecondCollection Points on the second image
* @param dfThreshold Value from 0 to 1. Threshold affects to number of
* matched points. If threshold is higher, amount of corresponding
* points is larger, and vice versa
*
* @note Typical threshold's value is 0,1. BUT it's a very approximate guide.
* It can be 0,001 or even 1. This threshold provides direct adjustment
* of point matching.
* NOTICE that if threshold is lower, matches are more robust and correct, but number of
* matched points is smaller. Therefore if algorithm performs many false
* detections and produces bad results, reduce threshold.
* Otherwise, if algorithm finds nothing, increase threshold.
*
* @return CE_None or CE_Failure if error occurs.
*/
CPLErr GDALSimpleSURF::MatchFeaturePoints(
std::vector<GDALFeaturePoint*> *poMatchPairs,
std::vector<GDALFeaturePoint> *poFirstCollect,
std::vector<GDALFeaturePoint> *poSecondCollect,
double dfThreshold)
{
/* -------------------------------------------------------------------- */
/* Validate parameters. */
/* -------------------------------------------------------------------- */
if (poMatchPairs == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Matched points colection isn't specified");
return CE_Failure;
}
if (poFirstCollect == NULL || poSecondCollect == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Feature point collections are not specified");
return CE_Failure;
}
/* ==================================================================== */
/* Matching algorithm. */
/* ==================================================================== */
// Affects to false matching pruning
const double ratioThreshold = 0.8;
int len_1 = poFirstCollect->size();
int len_2 = poSecondCollect->size();
int minLength = (len_1 < len_2) ? len_1 : len_2;
// Temporary pointers. Used to swap collections
std::vector<GDALFeaturePoint> *p_1;
std::vector<GDALFeaturePoint> *p_2;
bool isSwap = false;
// Assign p_1 - collection with minimal number of points
if (minLength == len_2)
{
p_1 = poSecondCollect;
p_2 = poFirstCollect;
int tmp = 0;
tmp = len_1;
len_1 = len_2;
len_2 = tmp;
isSwap = true;
}
else
{
// Assignment 'as is'
p_1 = poFirstCollect;
p_2 = poSecondCollect;
isSwap = false;
}
// Stores matched point indexes and
// their euclidean distances
std::list<MatchedPointPairInfo> *poPairInfoList =
new std::list<MatchedPointPairInfo>();
// Flags that points in the 2nd collection are matched or not
bool *alreadyMatched = new bool[len_2];
for (int i = 0; i < len_2; i++)
alreadyMatched[i] = false;
for (int i = 0; i < len_1; i++)
{
// Distance to the nearest point
double bestDist = -1;
// Index of the nearest point in p_2 collection
int bestIndex = -1;
// Distance to the 2nd nearest point
double bestDist_2 = -1;
// Find the nearest and 2nd nearest points
for (int j = 0; j < len_2; j++)
if (!alreadyMatched[j])
if (p_1->at(i).GetSign() ==
p_2->at(j).GetSign())
{
// Get distance between two feature points
double curDist = GetEuclideanDistance(
p_1->at(i), p_2->at(j));
if (bestDist == -1)
{
bestDist = curDist;
bestIndex = j;
}
else
{
if (curDist < bestDist)
{
bestDist = curDist;
bestIndex = j;
}
}
// Findes the 2nd nearest point
if (bestDist_2 < 0)
bestDist_2 = curDist;
else
if (curDist > bestDist && curDist < bestDist_2)
bestDist_2 = curDist;
}
/* -------------------------------------------------------------------- */
/* False matching pruning. */
/* If ratio bestDist to bestDist_2 greater than 0.8 => */
/* consider as false detection. */
/* Otherwise, add points as matched pair. */
/*----------------------------------------------------------------------*/
if (bestDist_2 > 0 && bestDist >= 0)
if (bestDist / bestDist_2 < ratioThreshold)
{
MatchedPointPairInfo info(i, bestIndex, bestDist);
poPairInfoList->push_back(info);
alreadyMatched[bestIndex] = true;
}
}
/* -------------------------------------------------------------------- */
/* Pruning based on the provided threshold */
/* -------------------------------------------------------------------- */
NormalizeDistances(poPairInfoList);
std::list<MatchedPointPairInfo>::const_iterator iter;
for (iter = poPairInfoList->begin(); iter != poPairInfoList->end(); iter++)
{
if ((*iter).euclideanDist <= dfThreshold)
{
int i_1 = (*iter).ind_1;
int i_2 = (*iter).ind_2;
// Add copies into MatchedCollection
if(!isSwap)
{
poMatchPairs->push_back( &(p_1->at(i_1)) );
poMatchPairs->push_back( &(p_2->at(i_2)) );
}
else
{
poMatchPairs->push_back( &(p_2->at(i_2)) );
poMatchPairs->push_back( &(p_1->at(i_1)) );
}
}
}
// Clean up
delete[] alreadyMatched;
return CE_None;
}
GDALSimpleSURF::~GDALSimpleSURF()
{
delete poOctMap;
}

View file

@ -0,0 +1,554 @@
/******************************************************************************
* Project: GDAL
* Purpose: Correlator
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Andrew Migal
*
* 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.
****************************************************************************/
/**
* @file
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for searching corresponding points on images.
*/
#ifndef GDALSIMPLESURF_H_
#define GDALSIMPLESURF_H_
#include "gdal_priv.h"
#include "cpl_conv.h"
#include <list>
/**
* @brief Class of "feature point" in raster. Used by SURF-based algorithm.
*
* @details This point presents coordinates of distinctive pixel in image.
* In computer vision, feature points - the most "strong" and "unique"
* pixels (or areas) in picture, which can be distinguished from others.
* For more details, see FAST corner detector, SIFT, SURF and similar algorithms.
*/
class GDALFeaturePoint
{
public:
/**
* Standard constructor. Initializes all parameters with negative numbers
* and allocates memory for descriptor.
*/
GDALFeaturePoint();
/**
* Copy constructor
* @param fp Copied instance of GDALFeaturePoint class
*/
GDALFeaturePoint(const GDALFeaturePoint& fp);
/**
* Create instance of GDALFeaturePoint class
*
* @param nX X-coordinate (pixel)
* @param nY Y-coordinate (line)
* @param nScale Scale which contains this point (2, 4, 8, 16 and so on)
* @param nRadius Half of the side of descriptor area
* @param nSign Sign of Hessian determinant for this point
*
* @note This constructor normally is invoked by SURF-based algorithm,
* which provides all necessary parameters.
*/
GDALFeaturePoint(int nX, int nY, int nScale, int nRadius, int nSign);
virtual ~GDALFeaturePoint();
GDALFeaturePoint& operator=(const GDALFeaturePoint& point);
/**
* Provide access to point's descriptor.
*
* @param nIndex Position of descriptor's value.
* nIndex should be within range from 0 to DESC_SIZE (in current version - 64)
*
* @return Reference to value of descriptor in 'nIndex' position.
* If index is out of range then behaviour is undefined.
*/
double& operator[](int nIndex);
// Descriptor length
static const int DESC_SIZE = 64;
/**
* Fetch X-coordinate (pixel) of point
*
* @return X-coordinate in pixels
*/
int GetX();
/**
* Set X coordinate of point
*
* @param nX X coordinate in pixels
*/
void SetX(int nX);
/**
* Fetch Y-coordinate (line) of point.
*
* @return Y-coordinate in pixels.
*/
int GetY();
/**
* Set Y coordinate of point.
*
* @param nY Y coordinate in pixels.
*/
void SetY(int nY);
/**
* Fetch scale of point.
*
* @return Scale for this point.
*/
int GetScale();
/**
* Set scale of point.
*
* @param nScale Scale for this point.
*/
void SetScale(int nScale);
/**
* Fetch radius of point.
*
* @return Radius for this point.
*/
int GetRadius();
/**
* Set radius of point.
*
* @param nRadius Radius for this point.
*/
void SetRadius(int nRadius);
/**
* Fetch sign of Hessian determinant of point.
*
* @return Sign for this point.
*/
int GetSign();
/**
* Set sign of point.
*
* @param nSign Sign of Hessian determinant for this point.
*/
void SetSign(int nSign);
private:
// Coordinates of point in image
int nX;
int nY;
// --------------------
int nScale;
int nRadius;
int nSign;
// Descriptor array
double *padfDescriptor;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Integral image class (summed area table).
* @details Integral image is a table for fast computing the sum of
* values in rectangular subarea. In more detail, for 2-dimensional array
* of numbers this class provides capabilty to get sum of values in
* rectangular arbitrary area with any size in constant time.
* Integral image is constructed from grayscale picture.
*/
class GDALIntegralImage
{
public:
GDALIntegralImage();
virtual ~GDALIntegralImage();
/**
* Compute integral image for specified array. Result is stored internally.
*
* @param padfImg Pointer to 2-dimensional array of values
* @param nHeight Number of rows in array
* @param nWidth Number of columns in array
*/
void Initialize(const double **padfImg, int nHeight, int nWidth);
/**
* Fetch value of specified position in integral image.
*
* @param nRow Row of this position
* @param nCol Column of this position
*
* @return Value in specified position or zero if parameters are out of range.
*/
double GetValue(int nRow, int nCol);
/**
* Get sum of values in specified rectangular grid. Rectangle is constructed
* from left top point.
*
* @param nRow Row of left top point of rectangle
* @param nCol Column of left top point of rectangle
* @param nWidth Width of rectangular area (number of columns)
* @param nHeight Heigth of rectangular area (number of rows)
*
* @return Sum of values in specified grid.
*/
double GetRectangleSum(int nRow, int nCol, int nWidth, int nHeight);
/**
* Get value of horizontal Haar wavelet in specified square grid.
*
* @param nRow Row of left top point of square
* @param nCol Column of left top point of square
* @param nSize Side of the square
*
* @return Value of horizontal Haar wavelet in specified square grid.
*/
double HaarWavelet_X(int nRow, int nCol, int nSize);
/**
* Get value of vertical Haar wavelet in specified square grid.
*
* @param nRow Row of left top point of square
* @param nCol Column of left top point of square
* @param nSize Side of the square
*
* @return Value of vertical Haar wavelet in specified square grid.
*/
double HaarWavelet_Y(int nRow, int nCol, int nSize);
/**
* Fetch height of integral image.
*
* @return Height of integral image (number of rows).
*/
int GetHeight();
/**
* Fetch width of integral image.
*
* @return Width of integral image (number of columns).
*/
int GetWidth();
private:
double **pMatrix;
int nWidth;
int nHeight;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for computation and storage of Hessian values in SURF-based algorithm.
*
* @details SURF-based algorithm normally uses this class for searching
* feature points on raster images. Class also contains traces of Hessian matrices
* to provide fast computations.
*/
class GDALOctaveLayer
{
public:
GDALOctaveLayer();
/**
* Create instance with provided parameters.
*
* @param nOctave Number of octave which contains this layer
* @param nInterval Number of position in octave
*
* @note Normally constructor is invoked only by SURF-based algorithm.
*/
GDALOctaveLayer(int nOctave, int nInterval);
virtual ~GDALOctaveLayer();
/**
* Perform calculation of Hessian determinats and their signs
* for specified integral image. Result is stored internally.
*
* @param poImg Integral image object, which provides all necessary
* data for computation
*
* @note Normally method is invoked only by SURF-based algorithm.
*/
void ComputeLayer(GDALIntegralImage *poImg);
/**
* Octave which contains this layer (1,2,3...)
*/
int octaveNum;
/**
* Length of the side of filter
*/
int filterSize;
/**
* Length of the border
*/
int radius;
/**
* Scale for this layer
*/
int scale;
/**
* Image width in pixels
*/
int width;
/**
* Image height in pixels
*/
int height;
/**
* Hessian values for image pixels
*/
double **detHessians;
/**
* Hessian signs for speeded matching
*/
int **signs;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for handling octave layers in SURF-based algorithm.
* @details Class contains OctaveLayers and provides capability to construct octave space and distinguish
* feature points. Normally this class is used only by SURF-based algorithm.
*/
class GDALOctaveMap
{
public:
/**
* Create octave space. Octave numbers are start with one. (1, 2, 3, 4, ... )
*
* @param nOctaveStart Number of bottom octave
* @param nOctaveEnd Number of top octave. Should be equal or greater than OctaveStart
*/
GDALOctaveMap(int nOctaveStart, int nOctaveEnd);
virtual ~GDALOctaveMap();
/**
* Calculate Hessian values for octave space
* (for all stored octave layers) using specified integral image
* @param poImg Integral image instance which provides necessary data
* @see GDALOctaveLayer
*/
void ComputeMap(GDALIntegralImage *poImg);
/**
* Method makes decision that specified point
* in middle octave layer is maximum among all points
* from 3x3x3 neighbourhood (surrounding points in
* bottom, middle and top layers). Provided layers should be from the same octave's interval.
* Detects feature points.
*
* @param row Row of point, which is candidate to be feature point
* @param col Column of point, which is candidate to be feature point
* @param bot Bottom octave layer
* @param mid Middle octave layer
* @param top Top octave layer
* @param threshold Threshold for feature point recognition. Detected feature point
* will have Hessian value greater than this provided threshold.
*
* @return TRUE if candidate was evaluated as feature point or FALSE otherwise.
*/
bool PointIsExtremum(int row, int col, GDALOctaveLayer *bot,
GDALOctaveLayer *mid, GDALOctaveLayer *top, double threshold);
/**
* 2-dimensional array of octave layers
*/
GDALOctaveLayer ***pMap;
/**
* Value for constructing internal octave space
*/
static const int INTERVALS = 4;
/**
* Number of bottom octave
*/
int octaveStart;
/**
* Number of top octave. Should be equal or greater than OctaveStart
*/
int octaveEnd;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for searching corresponding points on images.
* @details Provides capability for detection feature points
* and finding equal points on different images.
* Class implements simplified version of SURF algorithm (Speeded Up Robust Features).
* As original, this realization is scale invariant, but sensitive to rotation.
* Images should have similar rotation angles (maximum difference is up to 10-15 degrees),
* otherwise algorithm produces incorrect and very unstable results.
*/
class GDALSimpleSURF
{
private:
/**
* Class stores indexes of pair of point
* and distance between them.
*/
class MatchedPointPairInfo
{
public:
MatchedPointPairInfo(int nInd_1, int nInd_2, double dfDist)
{
ind_1 = nInd_1;
ind_2 = nInd_2;
euclideanDist = dfDist;
}
int ind_1;
int ind_2;
double euclideanDist;
};
public:
/**
* Prepare class according to specified parameters. Octave numbers affects
* to amount of detected points and their robustness.
* Range between bottom and top octaves also affects to required time of detection points
* (if range is large, algorithm should perform more operations).
* @param nOctaveStart Number of bottom octave. Octave numbers starts with one
* @param nOctaveEnd Number of top octave. Should be equal or greater than OctaveStart
*
* @note
* Every octave finds points with specific size. For small images
* use small octave numbers, for high resolution - large.
* For 1024x1024 images it's normal to use any octave numbers from range 1-6.
* (for example, octave start - 1, octave end - 3, or octave start - 2, octave end - 2.)
* For larger images, try 1-10 range or even higher.
* Pay attention that number of detected point decreases quickly per octave
* for particular image. Algorithm finds more points in case of small octave numbers.
* If method detects nothing, reduce bottom bound of octave range.
*
* NOTICE that every octave requires time to compute. Use a little range
* or only one octave if execution time is significant.
*/
GDALSimpleSURF(int nOctaveStart, int nOctaveEnd);
virtual ~GDALSimpleSURF();
/**
* Convert image with RGB channels to grayscale using "luminosity" method.
* Result is used in SURF-based algorithm, but may be used anywhere where
* grayscale images with nice contrast are required.
*
* @param red Image's red channel
* @param green Image's green channel
* @param blue Image's blue channel
* @param nXSize Width of initial image
* @param nYSize Height of initial image
* @param padfImg Array for resulting grayscale image
* @param nHeight Height of resulting image
* @param nWidth Width of resulting image
*
* @return CE_None or CE_Failure if error occurs.
*/
static CPLErr ConvertRGBToLuminosity(
GDALRasterBand *red,
GDALRasterBand *green,
GDALRasterBand *blue,
int nXSize, int nYSize,
double **padfImg, int nHeight, int nWidth);
/**
* Find feature points using specified integral image.
*
* @param poImg Integral image to be used
* @param dfThreshold Threshold for feature point recognition. Detected feature point
* will have Hessian value greater than this provided threshold.
*
* @note Typical threshold's value is 0,001. But this value
* can be various in each case and depends on image's nature.
* For example, value can be 0.002 or 0.005.
* Fill free to experiment with it.
* If threshold is high, than number of detected feature points is small,
* and vice versa.
*/
std::vector<GDALFeaturePoint>*
ExtractFeaturePoints(GDALIntegralImage *poImg, double dfThreshold);
/**
* Find corresponding points (equal points in two collections).
*
* @param poMatchPairs Resulting collection for matched points
* @param poSecondCollect Points on the first image
* @param poSecondCollect Points on the second image
* @param dfThreshold Value from 0 to 1. Threshold affects to number of
* matched points. If threshold is lower, amount of corresponding
* points is larger, and vice versa
*
* @return CE_None or CE_Failure if error occurs.
*/
static CPLErr MatchFeaturePoints(
std::vector<GDALFeaturePoint*> *poMatchPairs,
std::vector<GDALFeaturePoint> *poFirstCollect,
std::vector<GDALFeaturePoint> *poSecondCollect,
double dfThreshold);
private:
/**
* Compute euclidean distance between descriptors of two feature points.
* It's used in comparison and matching of points.
*
* @param firstPoint First feature point to be compared
* @param secondPoint Second feature point to be compared
*
* @return Euclidean distance between descriptors.
*/
static double GetEuclideanDistance(
GDALFeaturePoint &firstPoint, GDALFeaturePoint &secondPoint);
/**
* Set provided distance values to range from 0 to 1.
*
* @param poList List of distances to be normalized
*/
static void NormalizeDistances(std::list<MatchedPointPairInfo> *poList);
/**
* Compute descriptor for specified feature point.
*
* @param poPoint Feature point instance
* @param poImg image where feature point was found
*/
void SetDescriptor(GDALFeaturePoint *poPoint, GDALIntegralImage *poImg);
private:
int octaveStart;
int octaveEnd;
GDALOctaveMap *poOctMap;
};
#endif /* GDALSIMPLESURF_H_ */

View file

@ -0,0 +1,403 @@
/******************************************************************************
* $Id: gdal_tps.cpp 29207 2015-05-18 17:23:45Z mloskot $
*
* Project: High Performance Image Reprojector
* Purpose: Thin Plate Spline transformer (GDAL wrapper portion)
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2011-2013, 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 "thinplatespline.h"
#include "gdal_alg.h"
#include "gdal_alg_priv.h"
#include "gdal_priv.h"
#include "cpl_conv.h"
#include "cpl_string.h"
#include "cpl_atomic_ops.h"
#include "cpl_multiproc.h"
CPL_CVSID("$Id: gdal_tps.cpp 29207 2015-05-18 17:23:45Z mloskot $");
CPL_C_START
CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg );
void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree );
CPL_C_END
typedef struct
{
GDALTransformerInfo sTI;
VizGeorefSpline2D *poForward;
VizGeorefSpline2D *poReverse;
int bForwardSolved;
int bReverseSolved;
int bReversed;
int nGCPCount;
GDAL_GCP *pasGCPList;
volatile int nRefCount;
} TPSTransformInfo;
/************************************************************************/
/* GDALCreateSimilarTPSTransformer() */
/************************************************************************/
static
void* GDALCreateSimilarTPSTransformer( void *hTransformArg, double dfRatioX, double dfRatioY )
{
VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarTPSTransformer", NULL );
TPSTransformInfo *psInfo = (TPSTransformInfo *) hTransformArg;
if( dfRatioX == 1.0 && dfRatioY == 1.0 )
{
/* We can just use a ref count, since using the source transformation */
/* is thread-safe */
CPLAtomicInc(&(psInfo->nRefCount));
}
else
{
GDAL_GCP *pasGCPList = GDALDuplicateGCPs( psInfo->nGCPCount,
psInfo->pasGCPList );
for(int i=0;i<psInfo->nGCPCount;i++)
{
pasGCPList[i].dfGCPPixel /= dfRatioX;
pasGCPList[i].dfGCPLine /= dfRatioY;
}
psInfo = (TPSTransformInfo *) GDALCreateTPSTransformer( psInfo->nGCPCount, pasGCPList,
psInfo->bReversed );
GDALDeinitGCPs( psInfo->nGCPCount, pasGCPList );
CPLFree( pasGCPList );
}
return psInfo;
}
/************************************************************************/
/* GDALCreateTPSTransformer() */
/************************************************************************/
/**
* Create Thin Plate Spline transformer from GCPs.
*
* The thin plate spline transformer produces exact transformation
* at all control points and smoothly varying transformations between
* control points with greatest influence from local control points.
* It is suitable for for many applications not well modelled by polynomial
* transformations.
*
* Creating the TPS transformer involves solving systems of linear equations
* related to the number of control points involved. This solution is
* computed within this function call. It can be quite an expensive operation
* for large numbers of GCPs. For instance, for reference, it takes on the
* order of 10s for 400 GCPs on a 2GHz Athlon processor.
*
* TPS Transformers are serializable.
*
* The GDAL Thin Plate Spline transformer is based on code provided by
* Gilad Ronnen on behalf of VIZRT Inc (http://www.visrt.com). Incorporation
* of the algorithm into GDAL was supported by the Centro di Ecologia Alpina
* (http://www.cealp.it).
*
* @param nGCPCount the number of GCPs in pasGCPList.
* @param pasGCPList an array of GCPs to be used as input.
* @param bReversed set it to TRUE to compute the reversed transformation.
*
* @return the transform argument or NULL if creation fails.
*/
void *GDALCreateTPSTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed )
{
return GDALCreateTPSTransformerInt(nGCPCount, pasGCPList, bReversed, NULL);
}
static void GDALTPSComputeForwardInThread(void* pData)
{
TPSTransformInfo *psInfo = (TPSTransformInfo *)pData;
psInfo->bForwardSolved = psInfo->poForward->solve() != 0;
}
void *GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed, char** papszOptions )
{
TPSTransformInfo *psInfo;
int iGCP;
/* -------------------------------------------------------------------- */
/* Allocate transform info. */
/* -------------------------------------------------------------------- */
psInfo = (TPSTransformInfo *) CPLCalloc(sizeof(TPSTransformInfo),1);
psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
psInfo->nGCPCount = nGCPCount;
psInfo->bReversed = bReversed;
psInfo->poForward = new VizGeorefSpline2D( 2 );
psInfo->poReverse = new VizGeorefSpline2D( 2 );
memcpy( psInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
psInfo->sTI.pszClassName = "GDALTPSTransformer";
psInfo->sTI.pfnTransform = GDALTPSTransform;
psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer;
psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer;
psInfo->sTI.pfnCreateSimilar = GDALCreateSimilarTPSTransformer;
/* -------------------------------------------------------------------- */
/* Attach all the points to the transformation. */
/* -------------------------------------------------------------------- */
for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
{
double afPL[2], afXY[2];
afPL[0] = pasGCPList[iGCP].dfGCPPixel;
afPL[1] = pasGCPList[iGCP].dfGCPLine;
afXY[0] = pasGCPList[iGCP].dfGCPX;
afXY[1] = pasGCPList[iGCP].dfGCPY;
if( bReversed )
{
psInfo->poReverse->add_point( afPL[0], afPL[1], afXY );
psInfo->poForward->add_point( afXY[0], afXY[1], afPL );
}
else
{
psInfo->poForward->add_point( afPL[0], afPL[1], afXY );
psInfo->poReverse->add_point( afXY[0], afXY[1], afPL );
}
}
psInfo->nRefCount = 1;
int nThreads = 1;
if( nGCPCount > 100 )
{
const char* pszWarpThreads = CSLFetchNameValue(papszOptions, "NUM_THREADS");
if (pszWarpThreads == NULL)
pszWarpThreads = CPLGetConfigOption("GDAL_NUM_THREADS", "1");
if (EQUAL(pszWarpThreads, "ALL_CPUS"))
nThreads = CPLGetNumCPUs();
else
nThreads = atoi(pszWarpThreads);
}
if( nThreads > 1 )
{
/* Compute direct and reverse transforms in parallel */
CPLJoinableThread* hThread = CPLCreateJoinableThread(GDALTPSComputeForwardInThread, psInfo);
psInfo->bReverseSolved = psInfo->poReverse->solve() != 0;
if( hThread != NULL )
CPLJoinThread(hThread);
else
psInfo->bForwardSolved = psInfo->poForward->solve() != 0;
}
else
{
psInfo->bForwardSolved = psInfo->poForward->solve() != 0;
psInfo->bReverseSolved = psInfo->poReverse->solve() != 0;
}
if( !psInfo->bForwardSolved || !psInfo->bReverseSolved )
{
GDALDestroyTPSTransformer(psInfo);
return NULL;
}
return psInfo;
}
/************************************************************************/
/* GDALDestroyTPSTransformer() */
/************************************************************************/
/**
* Destroy TPS transformer.
*
* This function is used to destroy information about a GCP based
* polynomial transformation created with GDALCreateTPSTransformer().
*
* @param pTransformArg the transform arg previously returned by
* GDALCreateTPSTransformer().
*/
void GDALDestroyTPSTransformer( void *pTransformArg )
{
if( pTransformArg == NULL )
return;
TPSTransformInfo *psInfo = (TPSTransformInfo *) pTransformArg;
if( CPLAtomicDec(&(psInfo->nRefCount)) == 0 )
{
delete psInfo->poForward;
delete psInfo->poReverse;
GDALDeinitGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
CPLFree( psInfo->pasGCPList );
CPLFree( pTransformArg );
}
}
/************************************************************************/
/* GDALTPSTransform() */
/************************************************************************/
/**
* Transforms point based on GCP derived polynomial model.
*
* This function matches the GDALTransformerFunc signature, and can be
* used to transform one or more points from pixel/line coordinates to
* georeferenced coordinates (SrcToDst) or vice versa (DstToSrc).
*
* @param pTransformArg return value from GDALCreateTPSTransformer().
* @param bDstToSrc TRUE if transformation is from the destination
* (georeferenced) coordinates to pixel/line or FALSE when transforming
* from pixel/line to georeferenced coordinates.
* @param nPointCount the number of values in the x, y and z arrays.
* @param x array containing the X values to be transformed.
* @param y array containing the Y values to be transformed.
* @param z array containing the Z values to be transformed.
* @param panSuccess array in which a flag indicating success (TRUE) or
* failure (FALSE) of the transformation are placed.
*
* @return TRUE.
*/
int GDALTPSTransform( void *pTransformArg, int bDstToSrc,
int nPointCount,
double *x, double *y,
CPL_UNUSED double *z,
int *panSuccess )
{
VALIDATE_POINTER1( pTransformArg, "GDALTPSTransform", 0 );
int i;
TPSTransformInfo *psInfo = (TPSTransformInfo *) pTransformArg;
for( i = 0; i < nPointCount; i++ )
{
double xy_out[2];
if( bDstToSrc )
{
psInfo->poReverse->get_point( x[i], y[i], xy_out );
x[i] = xy_out[0];
y[i] = xy_out[1];
}
else
{
psInfo->poForward->get_point( x[i], y[i], xy_out );
x[i] = xy_out[0];
y[i] = xy_out[1];
}
panSuccess[i] = TRUE;
}
return TRUE;
}
/************************************************************************/
/* GDALSerializeTPSTransformer() */
/************************************************************************/
CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg )
{
VALIDATE_POINTER1( pTransformArg, "GDALSerializeTPSTransformer", NULL );
CPLXMLNode *psTree;
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pTransformArg);
psTree = CPLCreateXMLNode( NULL, CXT_Element, "TPSTransformer" );
/* -------------------------------------------------------------------- */
/* Serialize bReversed. */
/* -------------------------------------------------------------------- */
CPLCreateXMLElementAndValue(
psTree, "Reversed",
CPLString().Printf( "%d", psInfo->bReversed ) );
/* -------------------------------------------------------------------- */
/* Attach GCP List. */
/* -------------------------------------------------------------------- */
if( psInfo->nGCPCount > 0 )
{
GDALSerializeGCPListToXML( psTree,
psInfo->pasGCPList,
psInfo->nGCPCount,
NULL );
}
return psTree;
}
/************************************************************************/
/* GDALDeserializeTPSTransformer() */
/************************************************************************/
void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree )
{
GDAL_GCP *pasGCPList = 0;
int nGCPCount = 0;
void *pResult;
int bReversed;
/* -------------------------------------------------------------------- */
/* Check for GCPs. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
if( psGCPList != NULL )
{
GDALDeserializeGCPListFromXML( psGCPList,
&pasGCPList,
&nGCPCount,
NULL );
}
/* -------------------------------------------------------------------- */
/* Get other flags. */
/* -------------------------------------------------------------------- */
bReversed = atoi(CPLGetXMLValue(psTree,"Reversed","0"));
/* -------------------------------------------------------------------- */
/* Generate transformation. */
/* -------------------------------------------------------------------- */
pResult = GDALCreateTPSTransformer( nGCPCount, pasGCPList, bReversed );
/* -------------------------------------------------------------------- */
/* Cleanup GCP copy. */
/* -------------------------------------------------------------------- */
GDALDeinitGCPs( nGCPCount, pasGCPList );
CPLFree( pasGCPList );
return pResult;
}

View file

@ -0,0 +1,172 @@
/******************************************************************************
* $Id: gdalchecksum.cpp 27044 2014-03-16 23:41:27Z rouault $
*
* Project: GDAL
* Purpose: Compute simple checksum for a region of image data.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2003, Frank Warmerdam
* Copyright (c) 2007-2008, 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_alg.h"
#include "cpl_conv.h"
CPL_CVSID("$Id: gdalchecksum.cpp 27044 2014-03-16 23:41:27Z rouault $");
/************************************************************************/
/* GDALChecksumImage() */
/************************************************************************/
/**
* Compute checksum for image region.
*
* Computes a 16bit (0-65535) checksum from a region of raster data on a GDAL
* supported band. Floating point data is converted to 32bit integer
* so decimal portions of such raster data will not affect the checksum.
* Real and Imaginary components of complex bands influence the result.
*
* @param hBand the raster band to read from.
* @param nXOff pixel offset of window to read.
* @param nYOff line offset of window to read.
* @param nXSize pixel size of window to read.
* @param nYSize line size of window to read.
*
* @return Checksum value.
*/
int CPL_STDCALL
GDALChecksumImage( GDALRasterBandH hBand,
int nXOff, int nYOff, int nXSize, int nYSize )
{
VALIDATE_POINTER1( hBand, "GDALChecksumImage", 0 );
const static int anPrimes[11] =
{ 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43 };
int iLine, i, nChecksum = 0, iPrime = 0, nCount;
GDALDataType eDataType = GDALGetRasterDataType( hBand );
int bComplex = GDALDataTypeIsComplex( eDataType );
if (eDataType == GDT_Float32 || eDataType == GDT_Float64 ||
eDataType == GDT_CFloat32 || eDataType == GDT_CFloat64)
{
double* padfLineData;
GDALDataType eDstDataType = (bComplex) ? GDT_CFloat64 : GDT_Float64;
padfLineData = (double *) VSIMalloc2(nXSize, sizeof(double) * 2);
if (padfLineData == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"VSIMalloc2(): Out of memory in GDALChecksumImage. "
"Checksum value couldn't be computed\n");
return 0;
}
for( iLine = nYOff; iLine < nYOff + nYSize; iLine++ )
{
if (GDALRasterIO( hBand, GF_Read, nXOff, iLine, nXSize, 1,
padfLineData, nXSize, 1, eDstDataType, 0, 0 ) != CE_None)
{
CPLError( CE_Failure, CPLE_FileIO,
"Checksum value couldn't be computed due to I/O read error.\n");
break;
}
nCount = (bComplex) ? nXSize * 2 : nXSize;
for( i = 0; i < nCount; i++ )
{
double dfVal = padfLineData[i];
int nVal;
if (CPLIsNan(dfVal) || CPLIsInf(dfVal))
{
/* Most compilers seem to cast NaN or Inf to 0x80000000. */
/* but VC7 is an exception. So we force the result */
/* of such a cast */
nVal = 0x80000000;
}
else
{
/* Standard behaviour of GDALCopyWords when converting */
/* from floating point to Int32 */
dfVal += 0.5;
if( dfVal < -2147483647.0 )
nVal = -2147483647;
else if( dfVal > 2147483647 )
nVal = 2147483647;
else
nVal = (GInt32) floor(dfVal);
}
nChecksum += (nVal % anPrimes[iPrime++]);
if( iPrime > 10 )
iPrime = 0;
nChecksum &= 0xffff;
}
}
CPLFree(padfLineData);
}
else
{
int *panLineData;
GDALDataType eDstDataType = (bComplex) ? GDT_CInt32 : GDT_Int32;
panLineData = (GInt32 *) VSIMalloc2(nXSize, sizeof(GInt32) * 2);
if (panLineData == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"VSIMalloc2(): Out of memory in GDALChecksumImage. "
"Checksum value couldn't be computed\n");
return 0;
}
for( iLine = nYOff; iLine < nYOff + nYSize; iLine++ )
{
if (GDALRasterIO( hBand, GF_Read, nXOff, iLine, nXSize, 1,
panLineData, nXSize, 1, eDstDataType, 0, 0 ) != CE_None)
{
CPLError( CE_Failure, CPLE_FileIO,
"Checksum value couldn't be computed due to I/O read error.\n");
break;
}
nCount = (bComplex) ? nXSize * 2 : nXSize;
for( i = 0; i < nCount; i++ )
{
nChecksum += (panLineData[i] % anPrimes[iPrime++]);
if( iPrime > 10 )
iPrime = 0;
nChecksum &= 0xffff;
}
}
CPLFree( panLineData );
}
return nChecksum;
}

View file

@ -0,0 +1,418 @@
/******************************************************************************
* $Id: gdalcutline.cpp 28223 2014-12-26 11:28:03Z goatbar $
*
* Project: High Performance Image Reprojector
* Purpose: Implement cutline/blend mask generator.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2008-2013, 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 "gdalwarper.h"
#include "gdal_alg.h"
#include "ogr_api.h"
#include "ogr_geos.h"
#include "ogr_geometry.h"
#include "cpl_string.h"
CPL_CVSID("$Id: gdalcutline.cpp 28223 2014-12-26 11:28:03Z goatbar $");
/************************************************************************/
/* BlendMaskGenerator() */
/************************************************************************/
static CPLErr
BlendMaskGenerator(
#ifndef HAVE_GEOS
CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
CPL_UNUSED GByte *pabyPolyMask,
CPL_UNUSED float *pafValidityMask,
CPL_UNUSED OGRGeometryH hPolygon,
CPL_UNUSED double dfBlendDist
#else
int nXOff, int nYOff, int nXSize, int nYSize,
GByte *pabyPolyMask, float *pafValidityMask,
OGRGeometryH hPolygon, double dfBlendDist
#endif
)
{
#ifndef HAVE_GEOS
CPLError( CE_Failure, CPLE_AppDefined,
"Blend distance support not available without the GEOS library.");
return CE_Failure;
#else /* HAVE_GEOS */
/* -------------------------------------------------------------------- */
/* Convert the polygon into a collection of lines so that we */
/* measure distance from the edge even on the inside. */
/* -------------------------------------------------------------------- */
OGRGeometry *poLines
= OGRGeometryFactory::forceToMultiLineString(
((OGRGeometry *) hPolygon)->clone() );
/* -------------------------------------------------------------------- */
/* Prepare a clipping polygon a bit bigger than the area of */
/* interest in the hopes of simplifying the cutline down to */
/* stuff that will be relavent for this area of interest. */
/* -------------------------------------------------------------------- */
CPLString osClipRectWKT;
osClipRectWKT.Printf( "POLYGON((%g %g,%g %g,%g %g,%g %g,%g %g))",
nXOff - (dfBlendDist+1),
nYOff - (dfBlendDist+1),
nXOff + nXSize + (dfBlendDist+1),
nYOff - (dfBlendDist+1),
nXOff + nXSize + (dfBlendDist+1),
nYOff + nYSize + (dfBlendDist+1),
nXOff - (dfBlendDist+1),
nYOff + nYSize + (dfBlendDist+1),
nXOff - (dfBlendDist+1),
nYOff - (dfBlendDist+1) );
OGRPolygon *poClipRect = NULL;
char *pszWKT = (char *) osClipRectWKT.c_str();
OGRGeometryFactory::createFromWkt( &pszWKT, NULL,
(OGRGeometry**) (&poClipRect) );
if( poClipRect )
{
/***** if it doesnt intersect the polym zero the mask and return *****/
if ( ! ((OGRGeometry *) hPolygon)->Intersects( poClipRect ) )
{
memset( pafValidityMask, 0, sizeof(float) * nXSize * nYSize );
delete poLines;
delete poClipRect;
return CE_None;
}
/***** if it doesnt intersect the line at all just return *****/
else if ( ! ((OGRGeometry *) poLines)->Intersects( poClipRect ) )
{
delete poLines;
delete poClipRect;
return CE_None;
}
OGRGeometry *poClippedLines =
poLines->Intersection( poClipRect );
delete poLines;
poLines = poClippedLines;
delete poClipRect;
}
/* -------------------------------------------------------------------- */
/* Convert our polygon into GEOS format, and compute an */
/* envelope to accelerate later distance operations. */
/* -------------------------------------------------------------------- */
OGREnvelope sEnvelope;
int iXMin, iYMin, iXMax, iYMax;
GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext();
GEOSGeom poGEOSPoly;
poGEOSPoly = poLines->exportToGEOS(hGEOSCtxt);
OGR_G_GetEnvelope( hPolygon, &sEnvelope );
delete poLines;
/***** this check was already done in the calling *****/
/***** function and should never be true *****/
/*if( sEnvelope.MinY - dfBlendDist > nYOff+nYSize
|| sEnvelope.MaxY + dfBlendDist < nYOff
|| sEnvelope.MinX - dfBlendDist > nXOff+nXSize
|| sEnvelope.MaxX + dfBlendDist < nXOff )
return CE_None;
*/
iXMin = MAX(0,(int) floor(sEnvelope.MinX - dfBlendDist - nXOff));
iXMax = MIN(nXSize, (int) ceil(sEnvelope.MaxX + dfBlendDist - nXOff));
iYMin = MAX(0,(int) floor(sEnvelope.MinY - dfBlendDist - nYOff));
iYMax = MIN(nYSize, (int) ceil(sEnvelope.MaxY + dfBlendDist - nYOff));
/* -------------------------------------------------------------------- */
/* Loop over potential area within blend line distance, */
/* processing each pixel. */
/* -------------------------------------------------------------------- */
int iY, iX;
double dfLastDist;
for( iY = 0; iY < nYSize; iY++ )
{
dfLastDist = 0.0;
for( iX = 0; iX < nXSize; iX++ )
{
if( iX < iXMin || iX >= iXMax
|| iY < iYMin || iY > iYMax
|| dfLastDist > dfBlendDist + 1.5 )
{
if( pabyPolyMask[iX + iY * nXSize] == 0 )
pafValidityMask[iX + iY * nXSize] = 0.0;
dfLastDist -= 1.0;
continue;
}
double dfDist, dfRatio;
CPLString osPointWKT;
GEOSGeom poGEOSPoint;
osPointWKT.Printf( "POINT(%d.5 %d.5)", iX + nXOff, iY + nYOff );
poGEOSPoint = GEOSGeomFromWKT_r( hGEOSCtxt, osPointWKT );
GEOSDistance_r( hGEOSCtxt, poGEOSPoly, poGEOSPoint, &dfDist );
GEOSGeom_destroy_r( hGEOSCtxt, poGEOSPoint );
dfLastDist = dfDist;
if( dfDist > dfBlendDist )
{
if( pabyPolyMask[iX + iY * nXSize] == 0 )
pafValidityMask[iX + iY * nXSize] = 0.0;
continue;
}
if( pabyPolyMask[iX + iY * nXSize] == 0 )
{
/* outside */
dfRatio = 0.5 - (dfDist / dfBlendDist) * 0.5;
}
else
{
/* inside */
dfRatio = 0.5 + (dfDist / dfBlendDist) * 0.5;
}
pafValidityMask[iX + iY * nXSize] *= (float)dfRatio;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
GEOSGeom_destroy_r( hGEOSCtxt, poGEOSPoly );
OGRGeometry::freeGEOSContext( hGEOSCtxt );
return CE_None;
#endif /* HAVE_GEOS */
}
/************************************************************************/
/* CutlineTransformer() */
/* */
/* A simple transformer for the cutline that just offsets */
/* relative to the current chunk. */
/************************************************************************/
static int CutlineTransformer( void *pTransformArg,
int bDstToSrc,
int nPointCount,
double *x,
double *y,
CPL_UNUSED double *z,
CPL_UNUSED int *panSuccess )
{
int nXOff = ((int *) pTransformArg)[0];
int nYOff = ((int *) pTransformArg)[1];
int i;
if( bDstToSrc )
{
nXOff *= -1;
nYOff *= -1;
}
for( i = 0; i < nPointCount; i++ )
{
x[i] -= nXOff;
y[i] -= nYOff;
}
return TRUE;
}
/************************************************************************/
/* GDALWarpCutlineMasker() */
/* */
/* This function will generate a source mask based on a */
/* provided cutline, and optional blend distance. */
/************************************************************************/
CPLErr
GDALWarpCutlineMasker( void *pMaskFuncArg,
CPL_UNUSED int nBandCount,
CPL_UNUSED GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask )
{
GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
float *pafMask = (float *) pValidityMask;
CPLErr eErr;
GDALDriverH hMemDriver;
if( nXSize < 1 || nYSize < 1 )
return CE_None;
/* -------------------------------------------------------------------- */
/* Do some minimal checking. */
/* -------------------------------------------------------------------- */
if( !bMaskIsFloat )
{
CPLAssert( FALSE );
return CE_Failure;
}
if( psWO == NULL || psWO->hCutline == NULL )
{
CPLAssert( FALSE );
return CE_Failure;
}
hMemDriver = GDALGetDriverByName("MEM");
if (hMemDriver == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "GDALWarpCutlineMasker needs MEM driver");
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Check the polygon. */
/* -------------------------------------------------------------------- */
OGRGeometryH hPolygon = (OGRGeometryH) psWO->hCutline;
OGREnvelope sEnvelope;
if( wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbPolygon
&& wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbMultiPolygon )
{
CPLAssert( FALSE );
return CE_Failure;
}
OGR_G_GetEnvelope( hPolygon, &sEnvelope );
if( sEnvelope.MaxX + psWO->dfCutlineBlendDist < nXOff
|| sEnvelope.MinX - psWO->dfCutlineBlendDist > nXOff + nXSize
|| sEnvelope.MaxY + psWO->dfCutlineBlendDist < nYOff
|| sEnvelope.MinY - psWO->dfCutlineBlendDist > nYOff + nYSize )
{
// We are far from the blend line - everything is masked to zero.
// It would be nice to realize no work is required for this whole
// chunk!
memset( pafMask, 0, sizeof(float) * nXSize * nYSize );
return CE_None;
}
/* -------------------------------------------------------------------- */
/* Create a byte buffer into which we can burn the */
/* mask polygon and wrap it up as a memory dataset. */
/* -------------------------------------------------------------------- */
GByte *pabyPolyMask = (GByte *) CPLCalloc( nXSize, nYSize );
GDALDatasetH hMemDS;
double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
char szDataPointer[100];
char *apszOptions[] = { szDataPointer, NULL };
memset( szDataPointer, 0, sizeof(szDataPointer) );
sprintf( szDataPointer, "DATAPOINTER=" );
CPLPrintPointer( szDataPointer+strlen(szDataPointer),
pabyPolyMask,
sizeof(szDataPointer) - strlen(szDataPointer) );
hMemDS = GDALCreate( hMemDriver, "warp_temp",
nXSize, nYSize, 0, GDT_Byte, NULL );
GDALAddBand( hMemDS, GDT_Byte, apszOptions );
GDALSetGeoTransform( hMemDS, adfGeoTransform );
/* -------------------------------------------------------------------- */
/* Burn the polygon into the mask with 1.0 values. */
/* -------------------------------------------------------------------- */
int nTargetBand = 1;
double dfBurnValue = 255.0;
int anXYOff[2];
char **papszRasterizeOptions = NULL;
if( CSLFetchBoolean( psWO->papszWarpOptions, "CUTLINE_ALL_TOUCHED", FALSE ))
papszRasterizeOptions =
CSLSetNameValue( papszRasterizeOptions, "ALL_TOUCHED", "TRUE" );
anXYOff[0] = nXOff;
anXYOff[1] = nYOff;
eErr =
GDALRasterizeGeometries( hMemDS, 1, &nTargetBand,
1, &hPolygon,
CutlineTransformer, anXYOff,
&dfBurnValue, papszRasterizeOptions,
NULL, NULL );
CSLDestroy( papszRasterizeOptions );
// Close and ensure data flushed to underlying array.
GDALClose( hMemDS );
/* -------------------------------------------------------------------- */
/* In the case with no blend distance, we just apply this as a */
/* mask, zeroing out everything outside the polygon. */
/* -------------------------------------------------------------------- */
if( psWO->dfCutlineBlendDist == 0.0 )
{
int i;
for( i = nXSize * nYSize - 1; i >= 0; i-- )
{
if( pabyPolyMask[i] == 0 )
((float *) pValidityMask)[i] = 0.0;
}
}
else
{
eErr = BlendMaskGenerator( nXOff, nYOff, nXSize, nYSize,
pabyPolyMask, (float *) pValidityMask,
hPolygon, psWO->dfCutlineBlendDist );
}
/* -------------------------------------------------------------------- */
/* Clean up. */
/* -------------------------------------------------------------------- */
CPLFree( pabyPolyMask );
return eErr;
}

View file

@ -0,0 +1,656 @@
/******************************************************************************
* $Id: gdaldither.cpp 28085 2014-12-07 14:36:00Z rouault $
*
* Project: CIETMap Phase 2
* Purpose: Convert RGB (24bit) to a pseudo-colored approximation using
* Floyd-Steinberg dithering (error diffusion).
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2001, Frank Warmerdam
* Copyright (c) 2007, 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.
******************************************************************************
*
* Notes:
*
* [1] Floyd-Steinberg dither:
* I should point out that the actual fractions we used were, assuming
* you are at X, moving left to right:
*
* X 7/16
* 3/16 5/16 1/16
*
* Note that the error goes to four neighbors, not three. I think this
* will probably do better (at least for black and white) than the
* 3/8-3/8-1/4 distribution, at the cost of greater processing. I have
* seen the 3/8-3/8-1/4 distribution described as "our" algorithm before,
* but I have no idea who the credit really belongs to.
* --
* Lou Steinberg
*
*/
#include "gdal_priv.h"
#include "gdal_alg.h"
#include "gdal_alg_priv.h"
#if defined(__x86_64) || defined(_M_X64)
#define USE_SSE2
#endif
#ifdef USE_SSE2
#include <emmintrin.h>
#define CAST_PCT(x) ((GByte*)x)
#define ALIGN_INT_ARRAY_ON_16_BYTE(x) ( (((GPtrDiff_t)(x) % 16) != 0 ) ? (int*)((GByte*)(x) + 16 - ((GPtrDiff_t)(x) % 16)) : (x) )
#else
#define CAST_PCT(x) x
#endif
#define MAKE_COLOR_CODE(r,g,b) ((r)|((g)<<8)|((b)<<16))
CPL_CVSID("$Id: gdaldither.cpp 28085 2014-12-07 14:36:00Z rouault $");
static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap,
int nCLevels );
static int FindNearestColor( int nColors, int *panPCT,
int nRedValue, int nGreenValue, int nBlueValue );
/* Structure for a hashmap from a color code to a color index of the color table */
typedef struct /* NOTE: if changing the size of this structure, edit MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 */
{
GUInt32 nColorCode;
GUInt32 nColorCode2;
GUInt32 nColorCode3;
GByte nIndex;
GByte nIndex2;
GByte nIndex3;
GByte nPadding;
} ColorIndex;
/************************************************************************/
/* GDALDitherRGB2PCT() */
/************************************************************************/
/**
* 24bit to 8bit conversion with dithering.
*
* This functions utilizes Floyd-Steinberg dithering in the process of
* converting a 24bit RGB image into a pseudocolored 8bit image using a
* provided color table.
*
* The red, green and blue input bands do not necessarily need to come
* from the same file, but they must be the same width and height. They will
* be clipped to 8bit during reading, so non-eight bit bands are generally
* inappropriate. Likewise the hTarget band will be written with 8bit values
* and must match the width and height of the source bands.
*
* The color table cannot have more than 256 entries.
*
* @param hRed Red input band.
* @param hGreen Green input band.
* @param hBlue Blue input band.
* @param hTarget Output band.
* @param hColorTable the color table to use with the output band.
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
int CPL_STDCALL
GDALDitherRGB2PCT( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
return GDALDitherRGB2PCTInternal( hRed, hGreen, hBlue, hTarget,
hColorTable, 5, NULL, TRUE,
pfnProgress, pProgressArg );
}
int GDALDitherRGB2PCTInternal( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
int nBits,
GInt16* pasDynamicColorMap, /* NULL or at least 256 * 256 * 256 * sizeof(GInt16) bytes */
int bDither,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
VALIDATE_POINTER1( hRed, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hGreen, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hBlue, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hTarget, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hColorTable, "GDALDitherRGB2PCT", CE_Failure );
int nXSize, nYSize;
CPLErr err = CE_None;
/* -------------------------------------------------------------------- */
/* Validate parameters. */
/* -------------------------------------------------------------------- */
nXSize = GDALGetRasterBandXSize( hRed );
nYSize = GDALGetRasterBandYSize( hRed );
if( GDALGetRasterBandXSize( hGreen ) != nXSize
|| GDALGetRasterBandYSize( hGreen ) != nYSize
|| GDALGetRasterBandXSize( hBlue ) != nXSize
|| GDALGetRasterBandYSize( hBlue ) != nYSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Green or blue band doesn't match size of red band.\n" );
return CE_Failure;
}
if( GDALGetRasterBandXSize( hTarget ) != nXSize
|| GDALGetRasterBandYSize( hTarget ) != nYSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"GDALDitherRGB2PCT(): "
"Target band doesn't match size of source bands.\n" );
return CE_Failure;
}
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Setup more direct colormap. */
/* -------------------------------------------------------------------- */
int nColors, iColor;
#ifdef USE_SSE2
int anPCTUnaligned[256+4]; /* 4 for alignment on 16-byte boundary */
int* anPCT = ALIGN_INT_ARRAY_ON_16_BYTE(anPCTUnaligned);
#else
int anPCT[256*4];
#endif
nColors = GDALGetColorEntryCount( hColorTable );
if (nColors == 0 )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"GDALDitherRGB2PCT(): "
"Color table must not be empty.\n" );
return CE_Failure;
}
else if (nColors > 256)
{
CPLError( CE_Failure, CPLE_IllegalArg,
"GDALDitherRGB2PCT(): "
"Color table cannot have more than 256 entries.\n" );
return CE_Failure;
}
for( iColor = 0; iColor < nColors; iColor++ )
{
GDALColorEntry sEntry;
GDALGetColorEntryAsRGB( hColorTable, iColor, &sEntry );
CAST_PCT(anPCT)[4*iColor+0] = sEntry.c1;
CAST_PCT(anPCT)[4*iColor+1] = sEntry.c2;
CAST_PCT(anPCT)[4*iColor+2] = sEntry.c3;
CAST_PCT(anPCT)[4*iColor+3] = 0;
}
#ifdef USE_SSE2
/* Pad to multiple of 8 colors */
int nColorsMod8 = nColors % 8;
if( nColorsMod8 )
{
for( iColor = 0; iColor < 8 - nColorsMod8; iColor ++)
{
anPCT[nColors+iColor] = anPCT[nColors-1];
}
}
#endif
/* -------------------------------------------------------------------- */
/* Setup various variables. */
/* -------------------------------------------------------------------- */
GByte *pabyRed, *pabyGreen, *pabyBlue, *pabyIndex;
GByte *pabyColorMap = NULL;
int *panError;
int nCLevels = 1 << nBits;
ColorIndex* psColorIndexMap = NULL;
pabyRed = (GByte *) VSIMalloc(nXSize);
pabyGreen = (GByte *) VSIMalloc(nXSize);
pabyBlue = (GByte *) VSIMalloc(nXSize);
pabyIndex = (GByte *) VSIMalloc(nXSize);
panError = (int *) VSICalloc(sizeof(int),(nXSize+2) * 3);
if (pabyRed == NULL ||
pabyGreen == NULL ||
pabyBlue == NULL ||
pabyIndex == NULL ||
panError == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"VSIMalloc(): Out of memory in GDALDitherRGB2PCT" );
err = CE_Failure;
goto end_and_cleanup;
}
if( pasDynamicColorMap == NULL )
{
/* -------------------------------------------------------------------- */
/* Build a 24bit to 8 bit color mapping. */
/* -------------------------------------------------------------------- */
pabyColorMap = (GByte *) VSIMalloc(nCLevels * nCLevels * nCLevels
* sizeof(GByte));
if( pabyColorMap == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"VSIMalloc(): Out of memory in GDALDitherRGB2PCT" );
err = CE_Failure;
goto end_and_cleanup;
}
FindNearestColor( nColors, anPCT, pabyColorMap, nCLevels);
}
else
{
pabyColorMap = NULL;
if( nBits == 8 && (GIntBig)nXSize * nYSize <= 65536 )
{
/* If the image is small enough, then the number of colors */
/* will be limited and using a hashmap, rather than a full table */
/* will be more efficient */
psColorIndexMap = (ColorIndex*)pasDynamicColorMap;
memset(psColorIndexMap, 0xFF, sizeof(ColorIndex) * PRIME_FOR_65536);
}
else
{
memset(pasDynamicColorMap, 0xFF, 256 * 256 * 256 * sizeof(GInt16));
}
}
/* ==================================================================== */
/* Loop over all scanlines of data to process. */
/* ==================================================================== */
int iScanline;
for( iScanline = 0; iScanline < nYSize; iScanline++ )
{
int nLastRedError, nLastGreenError, nLastBlueError, i;
/* -------------------------------------------------------------------- */
/* Report progress */
/* -------------------------------------------------------------------- */
if( !pfnProgress( iScanline / (double) nYSize, NULL, pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" );
err = CE_Failure;
goto end_and_cleanup;
}
/* -------------------------------------------------------------------- */
/* Read source data. */
/* -------------------------------------------------------------------- */
GDALRasterIO( hRed, GF_Read, 0, iScanline, nXSize, 1,
pabyRed, nXSize, 1, GDT_Byte, 0, 0 );
GDALRasterIO( hGreen, GF_Read, 0, iScanline, nXSize, 1,
pabyGreen, nXSize, 1, GDT_Byte, 0, 0 );
GDALRasterIO( hBlue, GF_Read, 0, iScanline, nXSize, 1,
pabyBlue, nXSize, 1, GDT_Byte, 0, 0 );
/* -------------------------------------------------------------------- */
/* Apply the error from the previous line to this one. */
/* -------------------------------------------------------------------- */
if( bDither )
{
for( i = 0; i < nXSize; i++ )
{
pabyRed[i] = (GByte)
MAX(0,MIN(255,(pabyRed[i] + panError[i*3+0+3])));
pabyGreen[i] = (GByte)
MAX(0,MIN(255,(pabyGreen[i] + panError[i*3+1+3])));
pabyBlue[i] = (GByte)
MAX(0,MIN(255,(pabyBlue[i] + panError[i*3+2+3])));
}
memset( panError, 0, sizeof(int) * (nXSize+2) * 3 );
}
/* -------------------------------------------------------------------- */
/* Figure out the nearest color to the RGB value. */
/* -------------------------------------------------------------------- */
nLastRedError = 0;
nLastGreenError = 0;
nLastBlueError = 0;
for( i = 0; i < nXSize; i++ )
{
int iIndex, nError, nSixth;
int nRedValue, nGreenValue, nBlueValue;
nRedValue = MAX(0,MIN(255, pabyRed[i] + nLastRedError));
nGreenValue = MAX(0,MIN(255, pabyGreen[i] + nLastGreenError));
nBlueValue = MAX(0,MIN(255, pabyBlue[i] + nLastBlueError));
if( psColorIndexMap )
{
GUInt32 nColorCode = MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
//int nCollisions = 0;
//static int nMaxCollisions = 0;
while( TRUE )
{
if( psColorIndexMap[nIdx].nColorCode == nColorCode )
{
iIndex = psColorIndexMap[nIdx].nIndex;
break;
}
if( (int)psColorIndexMap[nIdx].nColorCode < 0 )
{
psColorIndexMap[nIdx].nColorCode = nColorCode;
iIndex = FindNearestColor( nColors, anPCT,
nRedValue, nGreenValue, nBlueValue );
psColorIndexMap[nIdx].nIndex = (GByte) iIndex;
break;
}
if( psColorIndexMap[nIdx].nColorCode2 == nColorCode )
{
iIndex = psColorIndexMap[nIdx].nIndex2;
break;
}
if( (int)psColorIndexMap[nIdx].nColorCode2 < 0 )
{
psColorIndexMap[nIdx].nColorCode2 = nColorCode;
iIndex = FindNearestColor( nColors, anPCT,
nRedValue, nGreenValue, nBlueValue );
psColorIndexMap[nIdx].nIndex2 = (GByte) iIndex;
break;
}
if( psColorIndexMap[nIdx].nColorCode3 == nColorCode )
{
iIndex = psColorIndexMap[nIdx].nIndex3;
break;
}
if( (int)psColorIndexMap[nIdx].nColorCode3 < 0 )
{
psColorIndexMap[nIdx].nColorCode3 = nColorCode;
iIndex = FindNearestColor( nColors, anPCT,
nRedValue, nGreenValue, nBlueValue );
psColorIndexMap[nIdx].nIndex3 = (GByte) iIndex;
break;
}
do
{
//nCollisions ++;
nIdx+=257;
if( nIdx >= PRIME_FOR_65536 )
nIdx -= PRIME_FOR_65536;
}
while( (int)psColorIndexMap[nIdx].nColorCode >= 0 &&
psColorIndexMap[nIdx].nColorCode != nColorCode &&
(int)psColorIndexMap[nIdx].nColorCode2 >= 0 &&
psColorIndexMap[nIdx].nColorCode2 != nColorCode&&
(int)psColorIndexMap[nIdx].nColorCode3 >= 0 &&
psColorIndexMap[nIdx].nColorCode3 != nColorCode );
/*if( nCollisions > nMaxCollisions )
{
nMaxCollisions = nCollisions;
printf("nCollisions = %d for R=%d,G=%d,B=%d\n",
nCollisions, nRedValue, nGreenValue, nBlueValue);
}*/
}
}
else if( pasDynamicColorMap == NULL )
{
int iRed = nRedValue * nCLevels / 256;
int iGreen = nGreenValue * nCLevels / 256;
int iBlue = nBlueValue * nCLevels / 256;
iIndex = pabyColorMap[iRed + iGreen * nCLevels
+ iBlue * nCLevels * nCLevels];
}
else
{
GUInt32 nColorCode = MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
GInt16* psIndex = &pasDynamicColorMap[nColorCode];
if( *psIndex < 0 )
iIndex = *psIndex = FindNearestColor( nColors, anPCT,
nRedValue,
nGreenValue,
nBlueValue );
else
iIndex = *psIndex;
}
pabyIndex[i] = (GByte) iIndex;
if( !bDither )
continue;
/* -------------------------------------------------------------------- */
/* Compute Red error, and carry it on to the next error line. */
/* -------------------------------------------------------------------- */
nError = nRedValue - CAST_PCT(anPCT)[4*iIndex+0];
nSixth = nError / 6;
panError[i*3 ] += nSixth;
panError[i*3+6 ] = nSixth;
panError[i*3+3 ] += nError - 5 * nSixth;
nLastRedError = 2 * nSixth;
/* -------------------------------------------------------------------- */
/* Compute Green error, and carry it on to the next error line. */
/* -------------------------------------------------------------------- */
nError = nGreenValue - CAST_PCT(anPCT)[4*iIndex+1];
nSixth = nError / 6;
panError[i*3 +1] += nSixth;
panError[i*3+6+1] = nSixth;
panError[i*3+3+1] += nError - 5 * nSixth;
nLastGreenError = 2 * nSixth;
/* -------------------------------------------------------------------- */
/* Compute Blue error, and carry it on to the next error line. */
/* -------------------------------------------------------------------- */
nError = nBlueValue - CAST_PCT(anPCT)[4*iIndex+2];
nSixth = nError / 6;
panError[i*3 +2] += nSixth;
panError[i*3+6+2] = nSixth;
panError[i*3+3+2] += nError - 5 * nSixth;
nLastBlueError = 2 * nSixth;
}
/* -------------------------------------------------------------------- */
/* Write results. */
/* -------------------------------------------------------------------- */
GDALRasterIO( hTarget, GF_Write, 0, iScanline, nXSize, 1,
pabyIndex, nXSize, 1, GDT_Byte, 0, 0 );
}
pfnProgress( 1.0, NULL, pProgressArg );
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
end_and_cleanup:
CPLFree( pabyRed );
CPLFree( pabyGreen );
CPLFree( pabyBlue );
CPLFree( pabyIndex );
CPLFree( panError );
CPLFree( pabyColorMap );
return err;
}
static int FindNearestColor( int nColors, int *panPCT,
int nRedValue, int nGreenValue, int nBlueValue )
{
#ifdef USE_SSE2
int iColor;
int nBestDist = 768, nBestIndex = 0;
int anDistanceUnaligned[16+4]; /* 4 for alignment on 16-byte boundary */
int* anDistance = ALIGN_INT_ARRAY_ON_16_BYTE(anDistanceUnaligned);
const __m128i ff = _mm_set1_epi32(0xFFFFFFFF);
const __m128i mask_low = _mm_srli_epi64(ff, 32);
const __m128i mask_high = _mm_slli_epi64(ff, 32);
unsigned int nColorVal = MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
const __m128i thisColor = _mm_set1_epi32(nColorVal);
const __m128i thisColor_low = _mm_srli_epi64(thisColor, 32);
const __m128i thisColor_high = _mm_slli_epi64(thisColor, 32);
for( iColor = 0; iColor < nColors; iColor+=8 )
{
__m128i pctColor = _mm_load_si128((__m128i*)&panPCT[iColor]);
__m128i pctColor2 = _mm_load_si128((__m128i*)&panPCT[iColor+4]);
_mm_store_si128((__m128i*)anDistance,
_mm_sad_epu8(_mm_and_si128(pctColor,mask_low),thisColor_low));
_mm_store_si128((__m128i*)(anDistance+4),
_mm_sad_epu8(_mm_and_si128(pctColor,mask_high),thisColor_high));
_mm_store_si128((__m128i*)(anDistance+8),
_mm_sad_epu8(_mm_and_si128(pctColor2,mask_low),thisColor_low));
_mm_store_si128((__m128i*)(anDistance+12),
_mm_sad_epu8(_mm_and_si128(pctColor2,mask_high),thisColor_high));
if( anDistance[0] < nBestDist )
{
nBestIndex = iColor;
nBestDist = anDistance[0];
}
if( anDistance[4] < nBestDist )
{
nBestIndex = iColor+1;
nBestDist = anDistance[4];
}
if( anDistance[2] < nBestDist )
{
nBestIndex = iColor+2;
nBestDist = anDistance[2];
}
if( anDistance[6] < nBestDist )
{
nBestIndex = iColor+3;
nBestDist = anDistance[6];
}
if( anDistance[8+0] < nBestDist )
{
nBestIndex = iColor+4;
nBestDist = anDistance[8+0];
}
if( anDistance[8+4] < nBestDist )
{
nBestIndex = iColor+4+1;
nBestDist = anDistance[8+4];
}
if( anDistance[8+2] < nBestDist )
{
nBestIndex = iColor+4+2;
nBestDist = anDistance[8+2];
}
if( anDistance[8+6] < nBestDist )
{
nBestIndex = iColor+4+3;
nBestDist = anDistance[8+6];
}
}
return nBestIndex;
#else
int iColor;
int nBestDist = 768, nBestIndex = 0;
for( iColor = 0; iColor < nColors; iColor++ )
{
int nThisDist;
nThisDist = ABS(nRedValue - panPCT[4*iColor+0])
+ ABS(nGreenValue - panPCT[4*iColor+1])
+ ABS(nBlueValue - panPCT[4*iColor+2]);
if( nThisDist < nBestDist )
{
nBestIndex = iColor;
nBestDist = nThisDist;
}
}
return nBestIndex;
#endif
}
/************************************************************************/
/* FindNearestColor() */
/* */
/* Finear near PCT color for any RGB color. */
/************************************************************************/
static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap,
int nCLevels )
{
int iBlue, iGreen, iRed;
/* -------------------------------------------------------------------- */
/* Loop over all the cells in the high density cube. */
/* -------------------------------------------------------------------- */
for( iBlue = 0; iBlue < nCLevels; iBlue++ )
{
for( iGreen = 0; iGreen < nCLevels; iGreen++ )
{
for( iRed = 0; iRed < nCLevels; iRed++ )
{
int nRedValue, nGreenValue, nBlueValue;
nRedValue = (iRed * 255) / (nCLevels-1);
nGreenValue = (iGreen * 255) / (nCLevels-1);
nBlueValue = (iBlue * 255) / (nCLevels-1);
int nBestIndex = FindNearestColor( nColors, panPCT,
nRedValue, nGreenValue, nBlueValue );
pabyColorMap[iRed + iGreen*nCLevels
+ iBlue*nCLevels*nCLevels] = (GByte)nBestIndex;
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,122 @@
/******************************************************************************
* $Id: gdalgrid.h 27044 2014-03-16 23:41:27Z rouault $
*
* Project: GDAL Gridding API.
* Purpose: Prototypes, and definitions for of GDAL scattered data gridder.
* Author: Andrey Kiselev, dron@ak4719.spb.edu
*
******************************************************************************
* Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
* 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.
****************************************************************************/
#ifndef GDALGRID_H_INCLUDED
#define GDALGRID_H_INCLUDED
/**
* \file gdalgrid.h
*
* GDAL gridder related entry points and definitions.
*/
#include "gdal_alg.h"
/*
* GridCreate Algorithm names
*/
static const char szAlgNameInvDist[] = "invdist";
static const char szAlgNameAverage[] = "average";
static const char szAlgNameNearest[] = "nearest";
static const char szAlgNameMinimum[] = "minimum";
static const char szAlgNameMaximum[] = "maximum";
static const char szAlgNameRange[] = "range";
static const char szAlgNameCount[] = "count";
static const char szAlgNameAverageDistance[] = "average_distance";
static const char szAlgNameAverageDistancePts[] = "average_distance_pts";
CPL_C_START
typedef CPLErr (*GDALGridFunction)( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr
GDALGridInverseDistanceToAPower( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr
GDALGridInverseDistanceToAPowerNoSearch( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr
GDALGridMovingAverage( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridNearestNeighbor( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricMinimum( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricMaximum( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricRange( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricCount( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricAverageDistance( const void *, GUInt32,
const double *, const double *,
const double *, double, double, double *,
void* );
CPLErr
GDALGridDataMetricAverageDistancePts( const void *, GUInt32,
const double *, const double *,
const double *, double, double,
double *,
void* );
CPLErr CPL_DLL
ParseAlgorithmAndOptions( const char *,
GDALGridAlgorithm *,
void ** );
CPL_C_END
#endif /* GDALGRID_H_INCLUDED */

View file

@ -0,0 +1,99 @@
/******************************************************************************
* $Id: gdalgrid_priv.h 29314 2015-06-05 20:21:11Z rouault $
*
* Project: GDAL Gridding API.
* Purpose: Prototypes, and definitions for of GDAL scattered data gridder.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2013, 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 "cpl_error.h"
#include "cpl_quad_tree.h"
typedef struct
{
const double* padfX;
const double* padfY;
} GDALGridXYArrays;
typedef struct
{
GDALGridXYArrays* psXYArrays;
int i;
} GDALGridPoint;
typedef struct
{
CPLQuadTree* hQuadTree;
double dfInitialSearchRadius;
const float *pafX;
const float *pafY;
const float *pafZ;
} GDALGridExtraParameters;
#ifdef HAVE_SSE_AT_COMPILE_TIME
int CPLHaveRuntimeSSE();
CPLErr
GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
const void *poOptions,
GUInt32 nPoints,
const double *unused_padfX,
const double *unused_padfY,
const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn );
#endif
#ifdef HAVE_AVX_AT_COMPILE_TIME
int CPLHaveRuntimeAVX();
CPLErr GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX(
const void *poOptions,
GUInt32 nPoints,
const double *unused_padfX,
const double *unused_padfY,
const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn );
#endif
#if defined(__GNUC__)
#if defined(__x86_64)
#define GCC_CPUID(level, a, b, c, d) \
__asm__ ("xchgq %%rbx, %q1\n" \
"cpuid\n" \
"xchgq %%rbx, %q1" \
: "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
: "0" (level))
#else
#define GCC_CPUID(level, a, b, c, d) \
__asm__ ("xchgl %%ebx, %1\n" \
"cpuid\n" \
"xchgl %%ebx, %1" \
: "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
: "0" (level))
#endif
#endif

View file

@ -0,0 +1,225 @@
/******************************************************************************
* $Id: gdalgridavx.cpp 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: GDAL Gridding API.
* Purpose: Implementation of GDAL scattered data gridder.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2013, 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 "gdalgrid.h"
#include "gdalgrid_priv.h"
#ifdef HAVE_AVX_AT_COMPILE_TIME
#include <immintrin.h>
CPL_CVSID("$Id: gdalgridavx.cpp 27745 2014-09-27 16:38:57Z goatbar $");
/************************************************************************/
/* CPLHaveRuntimeAVX() */
/************************************************************************/
#define CPUID_OSXSAVE_ECX_BIT 27
#define CPUID_AVX_ECX_BIT 28
#define BIT_XMM_STATE (1 << 1)
#define BIT_YMM_STATE (2 << 1)
int CPLHaveRuntimeAVX()
{
int cpuinfo[4] = {0,0,0,0};
GCC_CPUID(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
/* Check OSXSAVE feature */
if( (cpuinfo[2] & (1 << CPUID_OSXSAVE_ECX_BIT)) == 0 )
{
return FALSE;
}
/* Check AVX feature */
if( (cpuinfo[2] & (1 << CPUID_AVX_ECX_BIT)) == 0 )
{
return FALSE;
}
/* Issue XGETBV and check the XMM and YMM state bit */
unsigned int nXCRLow;
unsigned int nXCRHigh;
__asm__ ("xgetbv" : "=a" (nXCRLow), "=d" (nXCRHigh) : "c" (0));
if( (nXCRLow & ( BIT_XMM_STATE | BIT_YMM_STATE )) !=
( BIT_XMM_STATE | BIT_YMM_STATE ) )
{
return FALSE;
}
return TRUE;
}
/************************************************************************/
/* GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX() */
/************************************************************************/
#define GDAL_mm256_load1_ps(x) _mm256_set_ps(x, x, x, x, x, x, x, x)
CPLErr
GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX(
const void *poOptions,
GUInt32 nPoints,
CPL_UNUSED const double *unused_padfX,
CPL_UNUSED const double *unused_padfY,
CPL_UNUSED const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn )
{
size_t i = 0;
GDALGridExtraParameters* psExtraParams = (GDALGridExtraParameters*) hExtraParamsIn;
const float* pafX = psExtraParams->pafX;
const float* pafY = psExtraParams->pafY;
const float* pafZ = psExtraParams->pafZ;
const float fEpsilon = 0.0000000000001f;
const float fXPoint = (float)dfXPoint;
const float fYPoint = (float)dfYPoint;
const __m256 ymm_small = GDAL_mm256_load1_ps(fEpsilon);
const __m256 ymm_x = GDAL_mm256_load1_ps(fXPoint);
const __m256 ymm_y = GDAL_mm256_load1_ps(fYPoint);
__m256 ymm_nominator = _mm256_setzero_ps();
__m256 ymm_denominator = _mm256_setzero_ps();
int mask = 0;
#undef LOOP_SIZE
#if defined(__x86_64) || defined(_M_X64)
/* This would also work in 32bit mode, but there are only 8 XMM registers */
/* whereas we have 16 for 64bit */
#define LOOP_SIZE 16
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m256 ymm_rx = _mm256_sub_ps(_mm256_load_ps(pafX + i), ymm_x); /* rx = pafX[i] - fXPoint */
__m256 ymm_rx_8 = _mm256_sub_ps(_mm256_load_ps(pafX + i + 8), ymm_x);
__m256 ymm_ry = _mm256_sub_ps(_mm256_load_ps(pafY + i), ymm_y); /* ry = pafY[i] - fYPoint */
__m256 ymm_ry_8 = _mm256_sub_ps(_mm256_load_ps(pafY + i + 8), ymm_y);
__m256 ymm_r2 = _mm256_add_ps(_mm256_mul_ps(ymm_rx, ymm_rx), /* r2 = rx * rx + ry * ry */
_mm256_mul_ps(ymm_ry, ymm_ry));
__m256 ymm_r2_8 = _mm256_add_ps(_mm256_mul_ps(ymm_rx_8, ymm_rx_8),
_mm256_mul_ps(ymm_ry_8, ymm_ry_8));
__m256 ymm_invr2 = _mm256_rcp_ps(ymm_r2); /* invr2 = 1.0f / r2 */
__m256 ymm_invr2_8 = _mm256_rcp_ps(ymm_r2_8);
ymm_nominator = _mm256_add_ps(ymm_nominator, /* nominator += invr2 * pafZ[i] */
_mm256_mul_ps(ymm_invr2, _mm256_load_ps(pafZ + i)));
ymm_nominator = _mm256_add_ps(ymm_nominator,
_mm256_mul_ps(ymm_invr2_8, _mm256_load_ps(pafZ + i + 8)));
ymm_denominator = _mm256_add_ps(ymm_denominator, ymm_invr2); /* denominator += invr2 */
ymm_denominator = _mm256_add_ps(ymm_denominator, ymm_invr2_8);
mask = _mm256_movemask_ps(_mm256_cmp_ps(ymm_r2, ymm_small, _CMP_LT_OS)) | /* if( r2 < fEpsilon) */
(_mm256_movemask_ps(_mm256_cmp_ps(ymm_r2_8, ymm_small, _CMP_LT_OS)) << 8);
if( mask )
break;
}
#else
#define LOOP_SIZE 8
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m256 ymm_rx = _mm256_sub_ps(_mm256_load_ps((float*)pafX + i), ymm_x); /* rx = pafX[i] - fXPoint */
__m256 ymm_ry = _mm256_sub_ps(_mm256_load_ps((float*)pafY + i), ymm_y); /* ry = pafY[i] - fYPoint */
__m256 ymm_r2 = _mm256_add_ps(_mm256_mul_ps(ymm_rx, ymm_rx), /* r2 = rx * rx + ry * ry */
_mm256_mul_ps(ymm_ry, ymm_ry));
__m256 ymm_invr2 = _mm256_rcp_ps(ymm_r2); /* invr2 = 1.0f / r2 */
ymm_nominator = _mm256_add_ps(ymm_nominator, /* nominator += invr2 * pafZ[i] */
_mm256_mul_ps(ymm_invr2, _mm256_load_ps((float*)pafZ + i)));
ymm_denominator = _mm256_add_ps(ymm_denominator, ymm_invr2); /* denominator += invr2 */
mask = _mm256_movemask_ps(_mm256_cmp_ps(ymm_r2, ymm_small, _CMP_LT_OS)); /* if( r2 < fEpsilon) */
if( mask )
break;
}
#endif
/* Find which i triggered r2 < fEpsilon */
if( mask )
{
for(int j = 0; j < LOOP_SIZE; j++ )
{
if( mask & (1 << j) )
{
(*pdfValue) = (pafZ)[i + j];
return CE_None;
}
}
}
#undef LOOP_SIZE
/* Get back nominator and denominator values for YMM registers */
float afNominator[8], afDenominator[8];
_mm256_storeu_ps(afNominator, ymm_nominator);
_mm256_storeu_ps(afDenominator, ymm_denominator);
float fNominator = afNominator[0] + afNominator[1] +
afNominator[2] + afNominator[3] +
afNominator[4] + afNominator[5] +
afNominator[6] + afNominator[7];
float fDenominator = afDenominator[0] + afDenominator[1] +
afDenominator[2] + afDenominator[3] +
afDenominator[4] + afDenominator[5] +
afDenominator[6] + afDenominator[7];
/* Do the few remaining loop iterations */
for ( ; i < nPoints; i++ )
{
const float fRX = pafX[i] - fXPoint;
const float fRY = pafY[i] - fYPoint;
const float fR2 =
fRX * fRX + fRY * fRY;
// If the test point is close to the grid node, use the point
// value directly as a node value to avoid singularity.
if ( fR2 < 0.0000000000001 )
{
break;
}
else
{
const float fInvR2 = 1.0f / fR2;
fNominator += fInvR2 * pafZ[i];
fDenominator += fInvR2;
}
}
if( i != nPoints )
{
(*pdfValue) = pafZ[i];
}
else
if ( fDenominator == 0.0 )
{
(*pdfValue) =
((GDALGridInverseDistanceToAPowerOptions*)poOptions)->dfNoDataValue;
}
else
(*pdfValue) = fNominator / fDenominator;
return CE_None;
}
#endif

View file

@ -0,0 +1,241 @@
/******************************************************************************
* $Id: gdalgridsse.cpp 28033 2014-11-30 16:37:24Z rouault $
*
* Project: GDAL Gridding API.
* Purpose: Implementation of GDAL scattered data gridder.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2013, 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 "gdalgrid.h"
#include "gdalgrid_priv.h"
#ifdef HAVE_SSE_AT_COMPILE_TIME
#include <xmmintrin.h>
CPL_CVSID("$Id: gdalgridsse.cpp 28033 2014-11-30 16:37:24Z rouault $");
/************************************************************************/
/* CPLHaveRuntimeSSE() */
/************************************************************************/
#define CPUID_SSE_EDX_BIT 25
#if (defined(_M_X64) || defined(__x86_64))
int CPLHaveRuntimeSSE()
{
return TRUE;
}
#elif defined(__GNUC__) && defined(__i386__)
int CPLHaveRuntimeSSE()
{
int cpuinfo[4] = {0,0,0,0};
GCC_CPUID(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
return (cpuinfo[3] & (1 << CPUID_SSE_EDX_BIT)) != 0;
}
#elif defined(_MSC_VER) && defined(_M_IX86)
#if _MSC_VER <= 1310
static void inline __cpuid(int cpuinfo[4], int level)
{
__asm
{
push ebx
push esi
mov esi,cpuinfo
mov eax,level
cpuid
mov dword ptr [esi], eax
mov dword ptr [esi+4],ebx
mov dword ptr [esi+8],ecx
mov dword ptr [esi+0Ch],edx
pop esi
pop ebx
}
}
#else
#include <intrin.h>
#endif
int CPLHaveRuntimeSSE()
{
int cpuinfo[4] = {0,0,0,0};
__cpuid(cpuinfo, 1);
return (cpuinfo[3] & (1 << CPUID_SSE_EDX_BIT)) != 0;
}
#else
int CPLHaveRuntimeSSE()
{
return FALSE;
}
#endif
/************************************************************************/
/* GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE() */
/************************************************************************/
CPLErr
GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
const void *poOptions,
GUInt32 nPoints,
CPL_UNUSED const double *unused_padfX,
CPL_UNUSED const double *unused_padfY,
CPL_UNUSED const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn )
{
size_t i = 0;
GDALGridExtraParameters* psExtraParams = (GDALGridExtraParameters*) hExtraParamsIn;
const float* pafX = psExtraParams->pafX;
const float* pafY = psExtraParams->pafY;
const float* pafZ = psExtraParams->pafZ;
const float fEpsilon = 0.0000000000001f;
const float fXPoint = (float)dfXPoint;
const float fYPoint = (float)dfYPoint;
const __m128 xmm_small = _mm_load1_ps((float*)&fEpsilon);
const __m128 xmm_x = _mm_load1_ps((float*)&fXPoint);
const __m128 xmm_y = _mm_load1_ps((float*)&fYPoint);
__m128 xmm_nominator = _mm_setzero_ps();
__m128 xmm_denominator = _mm_setzero_ps();
int mask = 0;
#if defined(__x86_64) || defined(_M_X64)
/* This would also work in 32bit mode, but there are only 8 XMM registers */
/* whereas we have 16 for 64bit */
#define LOOP_SIZE 8
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m128 xmm_rx = _mm_sub_ps(_mm_load_ps(pafX + i), xmm_x); /* rx = pafX[i] - fXPoint */
__m128 xmm_rx_4 = _mm_sub_ps(_mm_load_ps(pafX + i + 4), xmm_x);
__m128 xmm_ry = _mm_sub_ps(_mm_load_ps(pafY + i), xmm_y); /* ry = pafY[i] - fYPoint */
__m128 xmm_ry_4 = _mm_sub_ps(_mm_load_ps(pafY + i + 4), xmm_y);
__m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx), /* r2 = rx * rx + ry * ry */
_mm_mul_ps(xmm_ry, xmm_ry));
__m128 xmm_r2_4 = _mm_add_ps(_mm_mul_ps(xmm_rx_4, xmm_rx_4),
_mm_mul_ps(xmm_ry_4, xmm_ry_4));
__m128 xmm_invr2 = _mm_rcp_ps(xmm_r2); /* invr2 = 1.0f / r2 */
__m128 xmm_invr2_4 = _mm_rcp_ps(xmm_r2_4);
xmm_nominator = _mm_add_ps(xmm_nominator, /* nominator += invr2 * pafZ[i] */
_mm_mul_ps(xmm_invr2, _mm_load_ps(pafZ + i)));
xmm_nominator = _mm_add_ps(xmm_nominator,
_mm_mul_ps(xmm_invr2_4, _mm_load_ps(pafZ + i + 4)));
xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2); /* denominator += invr2 */
xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2_4);
mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small)) | /* if( r2 < fEpsilon) */
(_mm_movemask_ps(_mm_cmplt_ps(xmm_r2_4, xmm_small)) << 4);
if( mask )
break;
}
#else
#define LOOP_SIZE 4
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m128 xmm_rx = _mm_sub_ps(_mm_load_ps((float*)pafX + i), xmm_x); /* rx = pafX[i] - fXPoint */
__m128 xmm_ry = _mm_sub_ps(_mm_load_ps((float*)pafY + i), xmm_y); /* ry = pafY[i] - fYPoint */
__m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx), /* r2 = rx * rx + ry * ry */
_mm_mul_ps(xmm_ry, xmm_ry));
__m128 xmm_invr2 = _mm_rcp_ps(xmm_r2); /* invr2 = 1.0f / r2 */
xmm_nominator = _mm_add_ps(xmm_nominator, /* nominator += invr2 * pafZ[i] */
_mm_mul_ps(xmm_invr2, _mm_load_ps((float*)pafZ + i)));
xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2); /* denominator += invr2 */
mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small)); /* if( r2 < fEpsilon) */
if( mask )
break;
}
#endif
/* Find which i triggered r2 < fEpsilon */
if( mask )
{
for(int j = 0; j < LOOP_SIZE; j++ )
{
if( mask & (1 << j) )
{
(*pdfValue) = (pafZ)[i + j];
return CE_None;
}
}
}
/* Get back nominator and denominator values for XMM registers */
float afNominator[4], afDenominator[4];
_mm_storeu_ps(afNominator, xmm_nominator);
_mm_storeu_ps(afDenominator, xmm_denominator);
float fNominator = afNominator[0] + afNominator[1] +
afNominator[2] + afNominator[3];
float fDenominator = afDenominator[0] + afDenominator[1] +
afDenominator[2] + afDenominator[3];
/* Do the few remaining loop iterations */
for ( ; i < nPoints; i++ )
{
const float fRX = pafX[i] - fXPoint;
const float fRY = pafY[i] - fYPoint;
const float fR2 =
fRX * fRX + fRY * fRY;
// If the test point is close to the grid node, use the point
// value directly as a node value to avoid singularity.
if ( fR2 < 0.0000000000001 )
{
break;
}
else
{
const float fInvR2 = 1.0f / fR2;
fNominator += fInvR2 * pafZ[i];
fDenominator += fInvR2;
}
}
if( i != nPoints )
{
(*pdfValue) = pafZ[i];
}
else
if ( fDenominator == 0.0 )
{
(*pdfValue) =
((GDALGridInverseDistanceToAPowerOptions*)poOptions)->dfNoDataValue;
}
else
(*pdfValue) = fNominator / fDenominator;
return CE_None;
}
#endif /* HAVE_SSE_AT_COMPILE_TIME */

View file

@ -0,0 +1,299 @@
/******************************************************************************
* $Id$
*
* Project: GDAL
* Purpose: GDAL Wrapper for image matching via corellation algorithm.
* Author: Frank Warmerdam, warmerdam@pobox.com
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Frank Warmerdam
*
* 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_alg.h"
#include "gdal_simplesurf.h"
CPL_CVSID("$Id");
/**
* @file
* @author Andrew Migal migal.drew@gmail.com
* @brief Algorithms for searching corresponding points on images.
* @details This implementation is based on an simplified version
* of SURF algorithm (Speeded Up Robust Features).
* Provides capability for detection feature points
* and finding equal points on different images.
* As original, this realization is scale invariant, but sensitive to rotation.
* Images should have similar rotation angles (maximum difference is up to 10-15 degrees),
* otherwise algorithm produces incorrect and very unstable results.
*/
/**
* Detect feature points on provided image. Please carefully read documentation below.
*
* @param poDataset Image on which feature points will be detected
* @param panBands Array of 3 raster bands numbers, for Red, Green, Blue bands (in that order)
* @param nOctaveStart Number of bottom octave. Octave numbers starts from one.
* This value directly and strongly affects to amount of recognized points
* @param nOctaveEnd Number of top octave. Should be equal or greater than octaveStart
* @param dfThreshold Value from 0 to 1. Threshold for feature point recognition.
* Number of detected points is larger if threshold is lower
*
* @see GDALFeaturePoint, GDALSimpleSURF class for detailes.
*
* @note Every octave finds points in specific size. For small images
* use small octave numbers, for high resolution - large.
* For 1024x1024 images it's normal to use any octave numbers from range 1-6.
* (for example, octave start - 1, octave end - 3, or octave start - 2, octave end - 2.)
* For larger images, try 1-10 range or even higher.
* Pay attention that number of detected point decreases quickly per octave
* for particular image. Algorithm finds more points in case of small octave number.
* If method detects nothing, reduce octave start value.
* In addition, if many feature points are required (the largest possible amount),
* use the lowest octave start value (1) and wide octave range.
*
* @note Typical threshold's value is 0,001. It's pretty good for all images.
* But this value depends on image's nature and may be various in each particular case.
* For example, value can be 0,002 or 0,005.
* Notice that number of detected points is larger if threshold is lower.
* But with high threshold feature points will be better - "stronger", more "unique" and distinctive.
*
* Feel free to experiment with parameters, because character, robustness and number of points
* entirely depend on provided range of octaves and threshold.
*
* NOTICE that every octave requires time to compute. Use a little range
* or only one octave, if execution time is significant.
*
* @return CE_None or CE_Failure if error occurs.
*/
static std::vector<GDALFeaturePoint> *
GatherFeaturePoints(GDALDataset* poDataset, int* panBands,
int nOctaveStart, int nOctaveEnd, double dfThreshold)
{
if (poDataset == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "GDALDataset isn't specified");
return NULL;
}
if (panBands == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Raster bands are not specified");
return NULL;
}
if (nOctaveStart <= 0 || nOctaveEnd < 0 ||
nOctaveStart > nOctaveEnd)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Octave numbers are invalid");
return NULL;
}
if (dfThreshold < 0)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Threshold have to be greater than zero");
return NULL;
}
GDALRasterBand *poRstRedBand = poDataset->GetRasterBand(panBands[0]);
GDALRasterBand *poRstGreenBand = poDataset->GetRasterBand(panBands[1]);
GDALRasterBand *poRstBlueBand = poDataset->GetRasterBand(panBands[2]);
int nWidth = poRstRedBand->GetXSize();
int nHeight = poRstRedBand->GetYSize();
// Allocate memory for grayscale image
double **padfImg = NULL;
padfImg = new double*[nHeight];
for (int i = 0; i < nHeight; i++)
padfImg[i] = new double[nWidth];
// Create grayscale image
GDALSimpleSURF::ConvertRGBToLuminosity(
poRstRedBand, poRstGreenBand, poRstBlueBand, nWidth, nHeight,
padfImg, nHeight, nWidth);
// Prepare integral image
GDALIntegralImage *poImg = new GDALIntegralImage();
poImg->Initialize((const double**)padfImg, nHeight, nWidth);
// Get feature points
GDALSimpleSURF *poSurf = new GDALSimpleSURF(nOctaveStart, nOctaveEnd);
std::vector<GDALFeaturePoint> *poCollection =
poSurf->ExtractFeaturePoints(poImg, dfThreshold);
// Clean up
delete poImg;
delete poSurf;
for (int i = 0; i < nHeight; i++)
delete[] padfImg[i];
delete[] padfImg;
return poCollection;
}
/************************************************************************/
/* GDALComputeMatchingPoints() */
/************************************************************************/
GDAL_GCP CPL_DLL *
GDALComputeMatchingPoints( GDALDatasetH hFirstImage,
GDALDatasetH hSecondImage,
char **papszOptions,
int *pnGCPCount )
{
*pnGCPCount = 0;
/* -------------------------------------------------------------------- */
/* Override default algorithm parameters. */
/* -------------------------------------------------------------------- */
int nOctaveStart, nOctaveEnd;
double dfSURFThreshold;
double dfMatchingThreshold = 0.015;
nOctaveStart =atoi(CSLFetchNameValueDef(papszOptions, "OCTAVE_START", "2"));
nOctaveEnd = atoi(CSLFetchNameValueDef(papszOptions, "OCTAVE_END", "2"));
dfSURFThreshold = CPLAtof(
CSLFetchNameValueDef(papszOptions, "SURF_THRESHOLD", "0.001"));
dfMatchingThreshold = CPLAtof(
CSLFetchNameValueDef(papszOptions, "MATCHING_THRESHOLD", "0.015"));
/* -------------------------------------------------------------------- */
/* Identify the bands to use. For now we are effectively */
/* limited to using RGB input so if we have one band only treat */
/* it as red=green=blue=band 1. Disallow non eightbit imagery. */
/* -------------------------------------------------------------------- */
int anBandMap1[3], anBandMap2[3];
if( GDALGetRasterCount(hFirstImage) >= 3 )
{
anBandMap1[0] = 1;
anBandMap1[1] = 2;
anBandMap1[2] = 3;
}
else
{
anBandMap1[0] = anBandMap1[1] = anBandMap1[2] = 1;
}
if( GDALGetRasterCount(hSecondImage) >= 3 )
{
anBandMap2[0] = 1;
anBandMap2[1] = 2;
anBandMap2[2] = 3;
}
else
{
anBandMap2[0] = anBandMap2[1] = anBandMap2[2] = 1;
}
/* -------------------------------------------------------------------- */
/* Collect reference points on each image. */
/* -------------------------------------------------------------------- */
std::vector<GDALFeaturePoint> *poFPCollection1 =
GatherFeaturePoints((GDALDataset *) hFirstImage, anBandMap1,
nOctaveStart, nOctaveEnd, dfSURFThreshold);
if( poFPCollection1 == NULL )
return NULL;
std::vector<GDALFeaturePoint> *poFPCollection2 =
GatherFeaturePoints((GDALDataset *) hSecondImage, anBandMap2,
nOctaveStart, nOctaveEnd,
dfSURFThreshold);
if( poFPCollection2 == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Try to find corresponding locations. */
/* -------------------------------------------------------------------- */
CPLErr eErr;
std::vector<GDALFeaturePoint *> oMatchPairs;
eErr = GDALSimpleSURF::MatchFeaturePoints(
&oMatchPairs, poFPCollection1, poFPCollection2,
dfMatchingThreshold );
if( eErr != CE_None )
return NULL;
*pnGCPCount = oMatchPairs.size() / 2;
/* -------------------------------------------------------------------- */
/* Translate these into GCPs - but with the output coordinate */
/* system being pixel/line on the second image. */
/* -------------------------------------------------------------------- */
GDAL_GCP *pasGCPList = (GDAL_GCP*) CPLCalloc(*pnGCPCount, sizeof(GDAL_GCP));
GDALInitGCPs(*pnGCPCount, pasGCPList);
for (int i=0; i < *pnGCPCount; i++)
{
GDALFeaturePoint *poPoint1 = oMatchPairs[i*2 ];
GDALFeaturePoint *poPoint2 = oMatchPairs[i*2+1];
pasGCPList[i].dfGCPPixel = poPoint1->GetX() + 0.5;
pasGCPList[i].dfGCPLine = poPoint1->GetY() + 0.5;
pasGCPList[i].dfGCPX = poPoint2->GetX() + 0.5;
pasGCPList[i].dfGCPY = poPoint2->GetY() + 0.5;
pasGCPList[i].dfGCPZ = 0.0;
}
// Cleanup the feature point lists.
delete poFPCollection1;
delete poFPCollection2;
/* -------------------------------------------------------------------- */
/* Optionally transform into the georef coordinates of the */
/* output image. */
/* -------------------------------------------------------------------- */
int bGeorefOutput =
CSLTestBoolean(CSLFetchNameValueDef(papszOptions,"OUTPUT_GEOREF","NO"));
if( bGeorefOutput )
{
double adfGeoTransform[6];
GDALGetGeoTransform( hSecondImage, adfGeoTransform );
for (int i=0; i < *pnGCPCount; i++)
{
GDALApplyGeoTransform(adfGeoTransform,
pasGCPList[i].dfGCPX,
pasGCPList[i].dfGCPY,
&(pasGCPList[i].dfGCPX),
&(pasGCPList[i].dfGCPY));
}
}
return pasGCPList;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,560 @@
/******************************************************************************
* $Id: gdalproximity.cpp 28882 2015-04-09 15:59:38Z rouault $
*
* Project: GDAL
* Purpose: Compute each pixel's proximity to a set of target pixels.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2009-2010, 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_alg.h"
#include "cpl_conv.h"
#include "cpl_string.h"
CPL_CVSID("$Id: gdalproximity.cpp 28882 2015-04-09 15:59:38Z rouault $");
static CPLErr
ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY,
int bForward, int iLine, int nXSize, double nMaxDist,
float *pafProximity, double *pdfSrcNoDataValue,
int nTargetValues, int *panTargetValues );
/************************************************************************/
/* GDALComputeProximity() */
/************************************************************************/
/**
Compute the proximity of all pixels in the image to a set of pixels in the source image.
This function attempts to compute the proximity of all pixels in
the image to a set of pixels in the source image. The following
options are used to define the behavior of the function. By
default all non-zero pixels in hSrcBand will be considered the
"target", and all proximities will be computed in pixels. Note
that target pixels are set to the value corresponding to a distance
of zero.
The progress function args may be NULL or a valid progress reporting function
such as GDALTermProgress/NULL.
Options:
VALUES=n[,n]*
A list of target pixel values to measure the distance from. If this
option is not provided proximity will be computed from non-zero
pixel values. Currently pixel values are internally processed as
integers.
DISTUNITS=[PIXEL]/GEO
Indicates whether distances will be computed in pixel units or
in georeferenced units. The default is pixel units. This also
determines the interpretation of MAXDIST.
MAXDIST=n
The maximum distance to search. Proximity distances greater than
this value will not be computed. Instead output pixels will be
set to a nodata value.
NODATA=n
The NODATA value to use on the output band for pixels that are
beyond MAXDIST. If not provided, the hProximityBand will be
queried for a nodata value. If one is not found, 65535 will be used.
USE_INPUT_NODATA=YES/NO
If this option is set, the input data set no-data value will be
respected. Leaving no data pixels in the input as no data pixels in
the proximity output.
FIXED_BUF_VAL=n
If this option is set, all pixels within the MAXDIST threadhold are
set to this fixed value instead of to a proximity distance.
*/
CPLErr CPL_STDCALL
GDALComputeProximity( GDALRasterBandH hSrcBand,
GDALRasterBandH hProximityBand,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
int nXSize, nYSize, i, bFixedBufVal = FALSE;
const char *pszOpt;
double dfMaxDist;
double dfFixedBufVal = 0.0;
VALIDATE_POINTER1( hSrcBand, "GDALComputeProximity", CE_Failure );
VALIDATE_POINTER1( hProximityBand, "GDALComputeProximity", CE_Failure );
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Are we using pixels or georeferenced coordinates for distances? */
/* -------------------------------------------------------------------- */
double dfDistMult = 1.0;
pszOpt = CSLFetchNameValue( papszOptions, "DISTUNITS" );
if( pszOpt )
{
if( EQUAL(pszOpt,"GEO") )
{
GDALDatasetH hSrcDS = GDALGetBandDataset( hSrcBand );
if( hSrcDS )
{
double adfGeoTransform[6];
GDALGetGeoTransform( hSrcDS, adfGeoTransform );
if( ABS(adfGeoTransform[1]) != ABS(adfGeoTransform[5]) )
CPLError( CE_Warning, CPLE_AppDefined,
"Pixels not square, distances will be inaccurate." );
dfDistMult = ABS(adfGeoTransform[1]);
}
}
else if( !EQUAL(pszOpt,"PIXEL") )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Unrecognised DISTUNITS value '%s', should be GEO or PIXEL.",
pszOpt );
return CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* What is our maxdist value? */
/* -------------------------------------------------------------------- */
pszOpt = CSLFetchNameValue( papszOptions, "MAXDIST" );
if( pszOpt )
dfMaxDist = CPLAtof(pszOpt) / dfDistMult;
else
dfMaxDist = GDALGetRasterBandXSize(hSrcBand) + GDALGetRasterBandYSize(hSrcBand);
CPLDebug( "GDAL", "MAXDIST=%g, DISTMULT=%g", dfMaxDist, dfDistMult );
/* -------------------------------------------------------------------- */
/* Verify the source and destination are compatible. */
/* -------------------------------------------------------------------- */
nXSize = GDALGetRasterBandXSize( hSrcBand );
nYSize = GDALGetRasterBandYSize( hSrcBand );
if( nXSize != GDALGetRasterBandXSize( hProximityBand )
|| nYSize != GDALGetRasterBandYSize( hProximityBand ))
{
CPLError( CE_Failure, CPLE_AppDefined,
"Source and proximity bands are not the same size." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Get input NODATA value. */
/* -------------------------------------------------------------------- */
double dfSrcNoDataValue = 0.0;
double *pdfSrcNoData = NULL;
if( CSLFetchBoolean( papszOptions, "USE_INPUT_NODATA", FALSE ) )
{
int bSrcHasNoData = 0;
dfSrcNoDataValue = GDALGetRasterNoDataValue( hSrcBand, &bSrcHasNoData );
if( bSrcHasNoData )
pdfSrcNoData = &dfSrcNoDataValue;
}
/* -------------------------------------------------------------------- */
/* Get output NODATA value. */
/* -------------------------------------------------------------------- */
float fNoDataValue;
pszOpt = CSLFetchNameValue( papszOptions, "NODATA" );
if( pszOpt != NULL )
fNoDataValue = (float) CPLAtof(pszOpt);
else
{
int bSuccess;
fNoDataValue = (float) GDALGetRasterNoDataValue( hProximityBand, &bSuccess );
if( !bSuccess )
fNoDataValue = 65535.0;
}
/* -------------------------------------------------------------------- */
/* Is there a fixed value we wish to force the buffer area to? */
/* -------------------------------------------------------------------- */
pszOpt = CSLFetchNameValue( papszOptions, "FIXED_BUF_VAL" );
if( pszOpt )
{
dfFixedBufVal = CPLAtof(pszOpt);
bFixedBufVal = TRUE;
}
/* -------------------------------------------------------------------- */
/* Get the target value(s). */
/* -------------------------------------------------------------------- */
int *panTargetValues = NULL;
int nTargetValues = 0;
pszOpt = CSLFetchNameValue( papszOptions, "VALUES" );
if( pszOpt != NULL )
{
char **papszValuesTokens;
papszValuesTokens = CSLTokenizeStringComplex( pszOpt, ",", FALSE,FALSE);
nTargetValues = CSLCount(papszValuesTokens);
panTargetValues = (int *) CPLCalloc(sizeof(int),nTargetValues);
for( i = 0; i < nTargetValues; i++ )
panTargetValues[i] = atoi(papszValuesTokens[i]);
CSLDestroy( papszValuesTokens );
}
/* -------------------------------------------------------------------- */
/* Initialize progress counter. */
/* -------------------------------------------------------------------- */
if( !pfnProgress( 0.0, "", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
CPLFree(panTargetValues);
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* We need a signed type for the working proximity values kept */
/* on disk. If our proximity band is not signed, then create a */
/* temporary file for this purpose. */
/* -------------------------------------------------------------------- */
GDALRasterBandH hWorkProximityBand = hProximityBand;
GDALDatasetH hWorkProximityDS = NULL;
GDALDataType eProxType = GDALGetRasterDataType( hProximityBand );
int *panNearX = NULL, *panNearY = NULL;
float *pafProximity = NULL;
GInt32 *panSrcScanline = NULL;
int iLine;
CPLErr eErr = CE_None;
if( eProxType == GDT_Byte
|| eProxType == GDT_UInt16
|| eProxType == GDT_UInt32 )
{
GDALDriverH hDriver = GDALGetDriverByName("GTiff");
if (hDriver == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"GDALComputeProximity needs GTiff driver");
eErr = CE_Failure;
goto end;
}
CPLString osTmpFile = CPLGenerateTempFilename( "proximity" );
hWorkProximityDS =
GDALCreate( hDriver, osTmpFile,
nXSize, nYSize, 1, GDT_Float32, NULL );
if (hWorkProximityDS == NULL)
{
eErr = CE_Failure;
goto end;
}
hWorkProximityBand = GDALGetRasterBand( hWorkProximityDS, 1 );
}
/* -------------------------------------------------------------------- */
/* Allocate buffer for two scanlines of distances as floats */
/* (the current and last line). */
/* -------------------------------------------------------------------- */
pafProximity = (float *) VSIMalloc2(sizeof(float), nXSize);
panNearX = (int *) VSIMalloc2(sizeof(int), nXSize);
panNearY = (int *) VSIMalloc2(sizeof(int), nXSize);
panSrcScanline = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
if( pafProximity== NULL
|| panNearX == NULL
|| panNearY == NULL
|| panSrcScanline == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Out of memory allocating working buffers.");
eErr = CE_Failure;
goto end;
}
/* -------------------------------------------------------------------- */
/* Loop from top to bottom of the image. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nXSize; i++ )
panNearX[i] = panNearY[i] = -1;
for( iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ )
{
// Read for target values.
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iLine, nXSize, 1,
panSrcScanline, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr != CE_None )
break;
for( i = 0; i < nXSize; i++ )
pafProximity[i] = -1.0;
// Left to right
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
TRUE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Right to Left
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
FALSE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Write out results.
eErr =
GDALRasterIO( hWorkProximityBand, GF_Write, 0, iLine, nXSize, 1,
pafProximity, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
if( !pfnProgress( 0.5 * (iLine+1) / (double) nYSize,
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Loop from bottom to top of the image. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nXSize; i++ )
panNearX[i] = panNearY[i] = -1;
for( iLine = nYSize-1; eErr == CE_None && iLine >= 0; iLine-- )
{
// Read first pass proximity
eErr =
GDALRasterIO( hWorkProximityBand, GF_Read, 0, iLine, nXSize, 1,
pafProximity, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
// Read pixel values.
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iLine, nXSize, 1,
panSrcScanline, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr != CE_None )
break;
// Right to left
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
FALSE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Left to right
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
TRUE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Final post processing of distances.
for( i = 0; i < nXSize; i++ )
{
if( pafProximity[i] < 0.0 )
pafProximity[i] = fNoDataValue;
else if( pafProximity[i] > 0.0 )
{
if( bFixedBufVal )
pafProximity[i] = (float) dfFixedBufVal;
else
pafProximity[i] = (float)(pafProximity[i] * dfDistMult);
}
}
// Write out results.
eErr =
GDALRasterIO( hProximityBand, GF_Write, 0, iLine, nXSize, 1,
pafProximity, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
if( !pfnProgress( 0.5 + 0.5 * (nYSize-iLine) / (double) nYSize,
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
end:
CPLFree( panNearX );
CPLFree( panNearY );
CPLFree( panSrcScanline );
CPLFree( pafProximity );
CPLFree(panTargetValues);
if( hWorkProximityDS != NULL )
{
CPLString osProxFile = GDALGetDescription( hWorkProximityDS );
GDALClose( hWorkProximityDS );
GDALDeleteDataset( GDALGetDriverByName( "GTiff" ), osProxFile );
}
return eErr;
}
/************************************************************************/
/* ProcessProximityLine() */
/************************************************************************/
static CPLErr
ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY,
int bForward, int iLine, int nXSize, double dfMaxDist,
float *pafProximity, double *pdfSrcNoDataValue,
int nTargetValues, int *panTargetValues )
{
int iStart, iEnd, iStep, iPixel;
if( bForward )
{
iStart = 0;
iEnd = nXSize;
iStep = 1;
}
else
{
iStart = nXSize-1;
iEnd = -1;
iStep = -1;
}
for( iPixel = iStart; iPixel != iEnd; iPixel += iStep )
{
int bIsTarget = FALSE;
/* -------------------------------------------------------------------- */
/* Is the current pixel a target pixel? */
/* -------------------------------------------------------------------- */
if( nTargetValues == 0 )
bIsTarget = (panSrcScanline[iPixel] != 0);
else
{
int i;
for( i = 0; i < nTargetValues; i++ )
{
if( panSrcScanline[iPixel] == panTargetValues[i] )
bIsTarget = TRUE;
}
}
if( bIsTarget )
{
pafProximity[iPixel] = 0.0;
panNearX[iPixel] = iPixel;
panNearY[iPixel] = iLine;
continue;
}
/* -------------------------------------------------------------------- */
/* Are we near(er) to the closest target to the above (below) */
/* pixel? */
/* -------------------------------------------------------------------- */
float fNearDistSq = (float) (MAX(dfMaxDist,nXSize) * MAX(dfMaxDist,nXSize) * 2);
float fDistSq;
if( panNearX[iPixel] != -1 )
{
fDistSq = (float)
((panNearX[iPixel] - iPixel) * (panNearX[iPixel] - iPixel)
+ (panNearY[iPixel] - iLine) * (panNearY[iPixel] - iLine));
if( fDistSq < fNearDistSq )
{
fNearDistSq = fDistSq;
}
else
{
panNearX[iPixel] = -1;
panNearY[iPixel] = -1;
}
}
/* -------------------------------------------------------------------- */
/* Are we near(er) to the closest target to the left (right) */
/* pixel? */
/* -------------------------------------------------------------------- */
int iLast = iPixel-iStep;
if( iPixel != iStart && panNearX[iLast] != -1 )
{
fDistSq = (float)
((panNearX[iLast] - iPixel) * (panNearX[iLast] - iPixel)
+ (panNearY[iLast] - iLine) * (panNearY[iLast] - iLine));
if( fDistSq < fNearDistSq )
{
fNearDistSq = fDistSq;
panNearX[iPixel] = panNearX[iLast];
panNearY[iPixel] = panNearY[iLast];
}
}
/* -------------------------------------------------------------------- */
/* Are we near(er) to the closest target to the topright */
/* (bottom left) pixel? */
/* -------------------------------------------------------------------- */
int iTR = iPixel+iStep;
if( iTR != iEnd && panNearX[iTR] != -1 )
{
fDistSq = (float)
((panNearX[iTR] - iPixel) * (panNearX[iTR] - iPixel)
+ (panNearY[iTR] - iLine) * (panNearY[iTR] - iLine));
if( fDistSq < fNearDistSq )
{
fNearDistSq = fDistSq;
panNearX[iPixel] = panNearX[iTR];
panNearY[iPixel] = panNearY[iTR];
}
}
/* -------------------------------------------------------------------- */
/* Update our proximity value. */
/* -------------------------------------------------------------------- */
if( panNearX[iPixel] != -1
&& (pdfSrcNoDataValue == NULL
|| panSrcScanline[iPixel] != *pdfSrcNoDataValue)
&& fNearDistSq <= dfMaxDist * dfMaxDist
&& (pafProximity[iPixel] < 0
|| fNearDistSq < pafProximity[iPixel] * pafProximity[iPixel]) )
pafProximity[iPixel] = sqrt(fNearDistSq);
}
return CE_None;
}

View file

@ -0,0 +1,250 @@
/******************************************************************************
* $Id: gdalrasterfpolygonenumerator.cpp 24379 2012-05-04 01:26:19Z warmerdam $
*
* Project: GDAL
* Purpose: Version of Raster Polygon Enumerator using float buffers.
* Author: Jorge Arevalo, jorge.arevalo@deimos-space.com. Most of the code
* taken from GDALRasterFPolygonEnumerator, by Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2011, Jorge Arevalo
* Copyright (c) 2008, Frank Warmerdam
*
* 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_alg_priv.h"
#include "cpl_conv.h"
#include <vector>
CPL_CVSID("$Id: gdalrasterfpolygonenumerator.cpp 24379 2012-05-04 01:26:19Z warmerdam $");
#ifdef OGR_ENABLED
/************************************************************************/
/* GDALRasterFPolygonEnumerator() */
/************************************************************************/
GDALRasterFPolygonEnumerator::GDALRasterFPolygonEnumerator(
int nConnectedness )
{
panPolyIdMap = NULL;
pafPolyValue = NULL;
nNextPolygonId = 0;
nPolyAlloc = 0;
this->nConnectedness = nConnectedness;
CPLAssert( nConnectedness == 4 || nConnectedness == 8 );
}
/************************************************************************/
/* ~GDALRasterFPolygonEnumerator() */
/************************************************************************/
GDALRasterFPolygonEnumerator::~GDALRasterFPolygonEnumerator()
{
Clear();
}
/************************************************************************/
/* Clear() */
/************************************************************************/
void GDALRasterFPolygonEnumerator::Clear()
{
CPLFree( panPolyIdMap );
CPLFree( pafPolyValue );
panPolyIdMap = NULL;
pafPolyValue = NULL;
nNextPolygonId = 0;
nPolyAlloc = 0;
}
/************************************************************************/
/* MergePolygon() */
/* */
/* Update the polygon map to indicate the merger of two polygons. */
/************************************************************************/
void GDALRasterFPolygonEnumerator::MergePolygon( int nSrcId, int nDstId )
{
while( panPolyIdMap[nDstId] != nDstId )
nDstId = panPolyIdMap[nDstId];
while( panPolyIdMap[nSrcId] != nSrcId )
nSrcId = panPolyIdMap[nSrcId];
if( nSrcId == nDstId )
return;
panPolyIdMap[nSrcId] = nDstId;
}
/************************************************************************/
/* NewPolygon() */
/* */
/* Allocate a new polygon id, and reallocate the polygon maps */
/* if needed. */
/************************************************************************/
int GDALRasterFPolygonEnumerator::NewPolygon( float fValue )
{
int nPolyId = nNextPolygonId;
if( nNextPolygonId >= nPolyAlloc )
{
nPolyAlloc = nPolyAlloc * 2 + 20;
panPolyIdMap = (GInt32 *) CPLRealloc(panPolyIdMap,nPolyAlloc*4);
pafPolyValue = (float *) CPLRealloc(pafPolyValue,nPolyAlloc*4);
}
nNextPolygonId++;
panPolyIdMap[nPolyId] = nPolyId;
pafPolyValue[nPolyId] = fValue;
return nPolyId;
}
/************************************************************************/
/* CompleteMerges() */
/* */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/************************************************************************/
void GDALRasterFPolygonEnumerator::CompleteMerges()
{
int iPoly;
int nFinalPolyCount = 0;
for( iPoly = 0; iPoly < nNextPolygonId; iPoly++ )
{
while( panPolyIdMap[iPoly]
!= panPolyIdMap[panPolyIdMap[iPoly]] )
panPolyIdMap[iPoly] = panPolyIdMap[panPolyIdMap[iPoly]];
if( panPolyIdMap[iPoly] == iPoly )
nFinalPolyCount++;
}
CPLDebug( "GDALRasterFPolygonEnumerator",
"Counted %d polygon fragments forming %d final polygons.",
nNextPolygonId, nFinalPolyCount );
}
/************************************************************************/
/* ProcessLine() */
/* */
/* Assign ids to polygons, one line at a time. */
/************************************************************************/
void GDALRasterFPolygonEnumerator::ProcessLine(
float *pafLastLineVal, float *pafThisLineVal,
GInt32 *panLastLineId, GInt32 *panThisLineId,
int nXSize )
{
int i;
/* -------------------------------------------------------------------- */
/* Special case for the first line. */
/* -------------------------------------------------------------------- */
if( pafLastLineVal == NULL )
{
for( i=0; i < nXSize; i++ )
{
if( i == 0 || !GDALFloatEquals(pafThisLineVal[i], pafThisLineVal[i-1]) )
{
panThisLineId[i] = NewPolygon( pafThisLineVal[i] );
}
else
panThisLineId[i] = panThisLineId[i-1];
}
return;
}
/* -------------------------------------------------------------------- */
/* Process each pixel comparing to the previous pixel, and to */
/* the last line. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nXSize; i++ )
{
if( i > 0 && GDALFloatEquals(pafThisLineVal[i], pafThisLineVal[i-1]) )
{
panThisLineId[i] = panThisLineId[i-1];
if( GDALFloatEquals(pafLastLineVal[i], pafThisLineVal[i])
&& (panPolyIdMap[panLastLineId[i]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i], panThisLineId[i] );
}
if( nConnectedness == 8
&& pafLastLineVal[i-1] == pafThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i-1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i-1], panThisLineId[i] );
}
if( nConnectedness == 8 && i < nXSize-1
&& pafLastLineVal[i+1] == pafThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i+1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i+1], panThisLineId[i] );
}
}
else if( GDALFloatEquals(pafLastLineVal[i], pafThisLineVal[i]) )
{
panThisLineId[i] = panLastLineId[i];
}
else if( i > 0 && nConnectedness == 8
&& GDALFloatEquals(pafLastLineVal[i-1], pafThisLineVal[i]) )
{
panThisLineId[i] = panLastLineId[i-1];
if( i < nXSize-1 && pafLastLineVal[i+1] == pafThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i+1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i+1], panThisLineId[i] );
}
}
else if( i < nXSize-1 && nConnectedness == 8
&& GDALFloatEquals(pafLastLineVal[i+1], pafThisLineVal[i]) )
{
panThisLineId[i] = panLastLineId[i+1];
}
else
panThisLineId[i] =
NewPolygon( pafThisLineVal[i] );
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,255 @@
/******************************************************************************
* $Id: gdalrasterpolygonenumerator.cpp 28826 2015-03-30 17:51:14Z rouault $
*
* Project: GDAL
* Purpose: Raster Polygon Enumerator
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
*
* 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_alg_priv.h"
#include "cpl_conv.h"
#include <vector>
CPL_CVSID("$Id: gdalrasterpolygonenumerator.cpp 28826 2015-03-30 17:51:14Z rouault $");
/************************************************************************/
/* GDALRasterPolygonEnumerator() */
/************************************************************************/
GDALRasterPolygonEnumerator::GDALRasterPolygonEnumerator(
int nConnectedness )
{
panPolyIdMap = NULL;
panPolyValue = NULL;
nNextPolygonId = 0;
nPolyAlloc = 0;
this->nConnectedness = nConnectedness;
CPLAssert( nConnectedness == 4 || nConnectedness == 8 );
}
/************************************************************************/
/* ~GDALRasterPolygonEnumerator() */
/************************************************************************/
GDALRasterPolygonEnumerator::~GDALRasterPolygonEnumerator()
{
Clear();
}
/************************************************************************/
/* Clear() */
/************************************************************************/
void GDALRasterPolygonEnumerator::Clear()
{
CPLFree( panPolyIdMap );
CPLFree( panPolyValue );
panPolyIdMap = NULL;
panPolyValue = NULL;
nNextPolygonId = 0;
nPolyAlloc = 0;
}
/************************************************************************/
/* MergePolygon() */
/* */
/* Update the polygon map to indicate the merger of two polygons. */
/************************************************************************/
void GDALRasterPolygonEnumerator::MergePolygon( int nSrcId, int nDstId )
{
while( panPolyIdMap[nDstId] != nDstId )
nDstId = panPolyIdMap[nDstId];
while( panPolyIdMap[nSrcId] != nSrcId )
nSrcId = panPolyIdMap[nSrcId];
if( nSrcId == nDstId )
return;
panPolyIdMap[nSrcId] = nDstId;
}
/************************************************************************/
/* NewPolygon() */
/* */
/* Allocate a new polygon id, and reallocate the polygon maps */
/* if needed. */
/************************************************************************/
int GDALRasterPolygonEnumerator::NewPolygon( GInt32 nValue )
{
int nPolyId = nNextPolygonId;
if( nNextPolygonId >= nPolyAlloc )
{
nPolyAlloc = nPolyAlloc * 2 + 20;
panPolyIdMap = (GInt32 *) CPLRealloc(panPolyIdMap,nPolyAlloc*4);
panPolyValue = (GInt32 *) CPLRealloc(panPolyValue,nPolyAlloc*4);
}
nNextPolygonId++;
panPolyIdMap[nPolyId] = nPolyId;
panPolyValue[nPolyId] = nValue;
return nPolyId;
}
/************************************************************************/
/* CompleteMerges() */
/* */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/************************************************************************/
void GDALRasterPolygonEnumerator::CompleteMerges()
{
int iPoly;
int nFinalPolyCount = 0;
for( iPoly = 0; iPoly < nNextPolygonId; iPoly++ )
{
while( panPolyIdMap[iPoly]
!= panPolyIdMap[panPolyIdMap[iPoly]] )
panPolyIdMap[iPoly] = panPolyIdMap[panPolyIdMap[iPoly]];
if( panPolyIdMap[iPoly] == iPoly )
nFinalPolyCount++;
}
CPLDebug( "GDALRasterPolygonEnumerator",
"Counted %d polygon fragments forming %d final polygons.",
nNextPolygonId, nFinalPolyCount );
}
/************************************************************************/
/* ProcessLine() */
/* */
/* Assign ids to polygons, one line at a time. */
/************************************************************************/
void GDALRasterPolygonEnumerator::ProcessLine(
GInt32 *panLastLineVal, GInt32 *panThisLineVal,
GInt32 *panLastLineId, GInt32 *panThisLineId,
int nXSize )
{
int i;
/* -------------------------------------------------------------------- */
/* Special case for the first line. */
/* -------------------------------------------------------------------- */
if( panLastLineVal == NULL )
{
for( i=0; i < nXSize; i++ )
{
if( panThisLineVal[i] == GP_NODATA_MARKER )
{
panThisLineId[i] = -1;
}
else if( i == 0 || panThisLineVal[i] != panThisLineVal[i-1] )
{
panThisLineId[i] = NewPolygon( panThisLineVal[i] );
}
else
panThisLineId[i] = panThisLineId[i-1];
}
return;
}
/* -------------------------------------------------------------------- */
/* Process each pixel comparing to the previous pixel, and to */
/* the last line. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nXSize; i++ )
{
if( panThisLineVal[i] == GP_NODATA_MARKER )
{
panThisLineId[i] = -1;
}
else if( i > 0 && panThisLineVal[i] == panThisLineVal[i-1] )
{
panThisLineId[i] = panThisLineId[i-1];
if( panLastLineVal[i] == panThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i], panThisLineId[i] );
}
if( nConnectedness == 8
&& panLastLineVal[i-1] == panThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i-1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i-1], panThisLineId[i] );
}
if( nConnectedness == 8 && i < nXSize-1
&& panLastLineVal[i+1] == panThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i+1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i+1], panThisLineId[i] );
}
}
else if( panLastLineVal[i] == panThisLineVal[i] )
{
panThisLineId[i] = panLastLineId[i];
}
else if( i > 0 && nConnectedness == 8
&& panLastLineVal[i-1] == panThisLineVal[i] )
{
panThisLineId[i] = panLastLineId[i-1];
if( i < nXSize-1 && panLastLineVal[i+1] == panThisLineVal[i]
&& (panPolyIdMap[panLastLineId[i+1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i+1], panThisLineId[i] );
}
}
else if( i < nXSize-1 && nConnectedness == 8
&& panLastLineVal[i+1] == panThisLineVal[i] )
{
panThisLineId[i] = panLastLineId[i+1];
}
else
panThisLineId[i] =
NewPolygon( panThisLineVal[i] );
}
}

View file

@ -0,0 +1,578 @@
/******************************************************************************
* $Id: gdalsievefilter.cpp 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: GDAL
* Purpose: Raster to Polygon Converter
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2009-2011, 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_alg_priv.h"
#include "cpl_conv.h"
#include <vector>
CPL_CVSID("$Id: gdalsievefilter.cpp 27745 2014-09-27 16:38:57Z goatbar $");
#define GP_NODATA_MARKER -51502112
#define MY_MAX_INT 2147483647
/*
* General Plan
*
* 1) make a pass with the polygon enumerator to build up the
* polygon map array. Also accumulate polygon size information.
*
* 2) Identify the polygons that need to be merged.
*
* 3) Make a pass with the polygon enumerator. For each "to be merged"
* polygon keep track of it's largest neighbour.
*
* 4) Fix up remappings that would go to polygons smaller than the seive
* size. Ensure these in term map to the largest neighbour of the
* "to be seieved" polygons.
*
* 5) Make another pass with the polygon enumerator. This time we remap
* the actual pixel values of all polygons to be merged.
*
*/
/************************************************************************/
/* GPMaskImageData() */
/* */
/* Mask out image pixels to a special nodata value if the mask */
/* band is zero. */
/************************************************************************/
static CPLErr
GPMaskImageData( GDALRasterBandH hMaskBand, GByte *pabyMaskLine, int iY, int nXSize,
GInt32 *panImageLine )
{
CPLErr eErr;
eErr = GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr == CE_None )
{
int i;
for( i = 0; i < nXSize; i++ )
{
if( pabyMaskLine[i] == 0 )
panImageLine[i] = GP_NODATA_MARKER;
}
}
return eErr;
}
/************************************************************************/
/* CompareNeighbour() */
/* */
/* Compare two neighbouring polygons, and update eaches */
/* "biggest neighbour" if the other is larger than it's current */
/* largest neighbour. */
/* */
/* Note that this should end up with each polygon knowing the */
/* id of it's largest neighbour. No attempt is made to */
/* restrict things to small polygons that we will be merging, */
/* nor to exclude assigning "biggest neighbours" that are still */
/* smaller than our sieve threshold. */
/************************************************************************/
static inline void CompareNeighbour( int nPolyId1, int nPolyId2,
int *panPolyIdMap,
int *panPolyValue,
std::vector<int> &anPolySizes,
std::vector<int> &anBigNeighbour )
{
// make sure we are working with the final merged polygon ids.
nPolyId1 = panPolyIdMap[nPolyId1];
nPolyId2 = panPolyIdMap[nPolyId2];
if( nPolyId1 == nPolyId2 )
return;
// nodata polygon do not need neighbours, and cannot be neighbours
// to valid polygons.
if( panPolyValue[nPolyId1] == GP_NODATA_MARKER
|| panPolyValue[nPolyId2] == GP_NODATA_MARKER )
return;
if( anBigNeighbour[nPolyId1] == -1
|| anPolySizes[anBigNeighbour[nPolyId1]] < anPolySizes[nPolyId2] )
anBigNeighbour[nPolyId1] = nPolyId2;
if( anBigNeighbour[nPolyId2] == -1
|| anPolySizes[anBigNeighbour[nPolyId2]] < anPolySizes[nPolyId1] )
anBigNeighbour[nPolyId2] = nPolyId1;
}
/************************************************************************/
/* GDALSieveFilter() */
/************************************************************************/
/**
* Removes small raster polygons.
*
* The function removes raster polygons smaller than a provided
* threshold size (in pixels) and replaces replaces them with the pixel value
* of the largest neighbour polygon.
*
* Polygon are determined (per GDALRasterPolygonEnumerator) as regions of
* the raster where the pixels all have the same value, and that are contiguous
* (connected).
*
* Pixels determined to be "nodata" per hMaskBand will not be treated as part
* of a polygon regardless of their pixel values. Nodata areas will never be
* changed nor affect polygon sizes.
*
* Polygons smaller than the threshold with no neighbours that are as large
* as the threshold will not be altered. Polygons surrounded by nodata areas
* will therefore not be altered.
*
* The algorithm makes three passes over the input file to enumerate the
* polygons and collect limited information about them. Memory use is
* proportional to the number of polygons (roughly 24 bytes per polygon), but
* is not directly related to the size of the raster. So very large raster
* files can be processed effectively if there aren't too many polygons. But
* extremely noisy rasters with many one pixel polygons will end up being
* expensive (in memory) to process.
*
* @param hSrcBand the source raster band to be processed.
* @param hMaskBand an optional mask band. All pixels in the mask band with a
* value other than zero will be considered suitable for inclusion in polygons.
* @param hDstBand the output raster band. It may be the same as hSrcBand
* to update the source in place.
* @param nSizeThreshold raster polygons with sizes smaller than this will
* be merged into their largest neighbour.
* @param nConnectedness either 4 indicating that diagonal pixels are not
* considered directly adjacent for polygon membership purposes or 8
* indicating they are.
* @param papszOptions algorithm options in name=value list form. None currently
* supported.
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
CPLErr CPL_STDCALL
GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
GDALRasterBandH hDstBand,
int nSizeThreshold, int nConnectedness,
CPL_UNUSED char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
VALIDATE_POINTER1( hSrcBand, "GDALSieveFilter", CE_Failure );
VALIDATE_POINTER1( hDstBand, "GDALSieveFilter", CE_Failure );
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Allocate working buffers. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
int nXSize = GDALGetRasterBandXSize( hSrcBand );
int nYSize = GDALGetRasterBandYSize( hSrcBand );
GInt32 *panLastLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
GInt32 *panThisLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
GInt32 *panLastLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
GInt32 *panThisLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
GInt32 *panThisLineWriteVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
GByte *pabyMaskLine = (hMaskBand != NULL) ? (GByte *) VSIMalloc(nXSize) : NULL;
if (panLastLineVal == NULL || panThisLineVal == NULL ||
panLastLineId == NULL || panThisLineId == NULL ||
panThisLineWriteVal == NULL ||
(hMaskBand != NULL && pabyMaskLine == NULL))
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate enough memory for temporary buffers");
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( panThisLineVal );
CPLFree( panLastLineVal );
CPLFree( panThisLineWriteVal );
CPLFree( pabyMaskLine );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* The first pass over the raster is only used to build up the */
/* polygon id map so we will know in advance what polygons are */
/* what on the second pass. */
/* -------------------------------------------------------------------- */
int iY, iX, iPoly;
GDALRasterPolygonEnumerator oFirstEnum( nConnectedness );
std::vector<int> anPolySizes;
for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
eErr = GDALRasterIO(
hSrcBand,
GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
if( iY == 0 )
oFirstEnum.ProcessLine(
NULL, panThisLineVal, NULL, panThisLineId, nXSize );
else
oFirstEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
/* -------------------------------------------------------------------- */
/* Accumulate polygon sizes. */
/* -------------------------------------------------------------------- */
if( oFirstEnum.nNextPolygonId > (int) anPolySizes.size() )
anPolySizes.resize( oFirstEnum.nNextPolygonId );
for( iX = 0; iX < nXSize; iX++ )
{
iPoly = panThisLineId[iX];
CPLAssert( iPoly >= 0 );
if( anPolySizes[iPoly] < MY_MAX_INT )
anPolySizes[iPoly] += 1;
}
/* -------------------------------------------------------------------- */
/* swap this/last lines. */
/* -------------------------------------------------------------------- */
GInt32 *panTmp = panLastLineVal;
panLastLineVal = panThisLineVal;
panThisLineVal = panTmp;
panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.25 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/* -------------------------------------------------------------------- */
oFirstEnum.CompleteMerges();
/* -------------------------------------------------------------------- */
/* Push the sizes of merged polygon fragments into the the */
/* merged polygon id's count. */
/* -------------------------------------------------------------------- */
for( iPoly = 0; iPoly < oFirstEnum.nNextPolygonId; iPoly++ )
{
if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
{
GIntBig nSize = anPolySizes[oFirstEnum.panPolyIdMap[iPoly]];
nSize += anPolySizes[iPoly];
if( nSize > MY_MAX_INT )
nSize = MY_MAX_INT;
anPolySizes[oFirstEnum.panPolyIdMap[iPoly]] = (int)nSize;
anPolySizes[iPoly] = 0;
}
}
/* -------------------------------------------------------------------- */
/* We will use a new enumerator for the second pass primariliy */
/* so we can preserve the first pass map. */
/* -------------------------------------------------------------------- */
GDALRasterPolygonEnumerator oSecondEnum( nConnectedness );
std::vector<int> anBigNeighbour;
anBigNeighbour.resize( anPolySizes.size() );
for( iPoly = 0; iPoly < (int) anPolySizes.size(); iPoly++ )
anBigNeighbour[iPoly] = -1;
/* ==================================================================== */
/* Second pass ... identify the largest neighbour for each */
/* polygon. */
/* ==================================================================== */
for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read the image data. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
if( eErr != CE_None )
continue;
/* -------------------------------------------------------------------- */
/* Determine what polygon the various pixels belong to (redoing */
/* the same thing done in the first pass above). */
/* -------------------------------------------------------------------- */
if( iY == 0 )
oSecondEnum.ProcessLine(
NULL, panThisLineVal, NULL, panThisLineId, nXSize );
else
oSecondEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
/* -------------------------------------------------------------------- */
/* Check our neighbours, and update our biggest neighbour map */
/* as appropriate. */
/* -------------------------------------------------------------------- */
for( iX = 0; iX < nXSize; iX++ )
{
if( iY > 0 )
{
CompareNeighbour( panThisLineId[iX],
panLastLineId[iX],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
if( iX > 0 && nConnectedness == 8 )
CompareNeighbour( panThisLineId[iX],
panLastLineId[iX-1],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
if( iX < nXSize-1 && nConnectedness == 8 )
CompareNeighbour( panThisLineId[iX],
panLastLineId[iX+1],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
}
if( iX > 0 )
CompareNeighbour( panThisLineId[iX],
panThisLineId[iX-1],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
// We don't need to compare to next pixel or next line
// since they will be compared to us.
}
/* -------------------------------------------------------------------- */
/* Swap pixel value, and polygon id lines to be ready for the */
/* next line. */
/* -------------------------------------------------------------------- */
GInt32 *panTmp = panLastLineVal;
panLastLineVal = panThisLineVal;
panThisLineVal = panTmp;
panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.25 + 0.25 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* If our biggest neighbour is still smaller than the */
/* threshold, then try tracking to that polygons biggest */
/* neighbour, and so forth. */
/* -------------------------------------------------------------------- */
int nFailedMerges = 0;
int nIsolatedSmall = 0;
int nSieveTargets = 0;
for( iPoly = 0; iPoly < (int) anPolySizes.size(); iPoly++ )
{
if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
continue;
// Ignore nodata polygons.
if( oFirstEnum.panPolyValue[iPoly] == GP_NODATA_MARKER )
continue;
// Don't try to merge polygons larger than the threshold.
if( anPolySizes[iPoly] >= nSizeThreshold )
{
anBigNeighbour[iPoly] = -1;
continue;
}
nSieveTargets++;
// if we have no neighbours but we are small, what shall we do?
if( anBigNeighbour[iPoly] == -1 )
{
nIsolatedSmall++;
continue;
}
// If our biggest neighbour is larger than the threshold
// then we are golden.
if( anPolySizes[anBigNeighbour[iPoly]] >= nSizeThreshold )
continue;
#ifdef notdef
// Will our neighbours biggest neighbour do?
// Eventually we need something sort of recursive here with
// loop detection.
if( anPolySizes[anBigNeighbour[anBigNeighbour[iPoly]]]
>= nSizeThreshold )
{
anBigNeighbour[iPoly] = anBigNeighbour[anBigNeighbour[iPoly]];
continue;
}
#endif
nFailedMerges++;
anBigNeighbour[iPoly] = -1;
}
CPLDebug( "GDALSieveFilter",
"Small Polygons: %d, Isolated: %d, Unmergable: %d",
nSieveTargets, nIsolatedSmall, nFailedMerges );
/* ==================================================================== */
/* Make a third pass over the image, actually applying the */
/* merges. We reuse the second enumerator but preserve the */
/* "final maps" from the first. */
/* ==================================================================== */
oSecondEnum.Clear();
for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read the image data. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
memcpy( panThisLineWriteVal, panThisLineVal, 4 * nXSize );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
if( eErr != CE_None )
continue;
/* -------------------------------------------------------------------- */
/* Determine what polygon the various pixels belong to (redoing */
/* the same thing done in the first pass above). */
/* -------------------------------------------------------------------- */
if( iY == 0 )
oSecondEnum.ProcessLine(
NULL, panThisLineVal, NULL, panThisLineId, nXSize );
else
oSecondEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
/* -------------------------------------------------------------------- */
/* Reprocess the actual pixel values according to the polygon */
/* merging, and write out this line of image data. */
/* -------------------------------------------------------------------- */
for( iX = 0; iX < nXSize; iX++ )
{
int iThisPoly = oFirstEnum.panPolyIdMap[panThisLineId[iX]];
if( anBigNeighbour[iThisPoly] != -1 )
{
panThisLineWriteVal[iX] =
oFirstEnum.panPolyValue[
anBigNeighbour[iThisPoly]];
}
}
/* -------------------------------------------------------------------- */
/* Write the update data out. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hDstBand, GF_Write, 0, iY, nXSize, 1,
panThisLineWriteVal, nXSize, 1, GDT_Int32, 0, 0 );
/* -------------------------------------------------------------------- */
/* Swap pixel value, and polygon id lines to be ready for the */
/* next line. */
/* -------------------------------------------------------------------- */
GInt32 *panTmp = panLastLineVal;
panLastLineVal = panThisLineVal;
panThisLineVal = panTmp;
panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.5 + 0.5 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( panThisLineVal );
CPLFree( panLastLineVal );
CPLFree( panThisLineWriteVal );
CPLFree( pabyMaskLine );
return eErr;
}

View file

@ -0,0 +1,446 @@
/******************************************************************************
* $Id: gdalsimplewarp.cpp 15436 2008-09-24 19:26:31Z rouault $
*
* Project: Mapinfo Image Warper
* Purpose: Simple (source in memory) warp algorithm.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2002, i3 - information integration and imaging, Fort Collin,CO
*
* 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_priv.h"
#include "gdal_alg.h"
#include "cpl_string.h"
CPL_CVSID("$Id: gdalsimplewarp.cpp 15436 2008-09-24 19:26:31Z rouault $");
static void
GDALSimpleWarpRemapping( int nBandCount, GByte **papabySrcData,
int nSrcXSize, int nSrcYSize,
char **papszWarpOptions );
/************************************************************************/
/* GDALSimpleImageWarp() */
/************************************************************************/
/**
* Perform simple image warp.
*
* Copies an image from a source dataset to a destination dataset applying
* an application defined transformation. This algorithm is called simple
* because it lacks many options such as resampling kernels (other than
* nearest neighbour), support for data types other than 8bit, and the
* ability to warp images without holding the entire source and destination
* image in memory.
*
* The following option(s) may be passed in papszWarpOptions.
* <ul>
* <li> "INIT=v[,v...]": This option indicates that the output dataset should
* be initialized to the indicated value in any area valid data is not written.
* Distinct values may be listed for each band separated by columns.
* </ul>
*
* @param hSrcDS the source image dataset.
* @param hDstDS the destination image dataset.
* @param nBandCount the number of bands to be warped. If zero, all bands
* will be processed.
* @param panBandList the list of bands to translate.
* @param pfnTransform the transformation function to call. See
* GDALTransformerFunc().
* @param pTransformArg the callback handle to pass to pfnTransform.
* @param pfnProgress the function used to report progress. See
* GDALProgressFunc().
* @param pProgressArg the callback handle to pass to pfnProgress.
* @param papszWarpOptions additional options controlling the warp.
*
* @return TRUE if the operation completes, or FALSE if an error occurs.
*/
int CPL_STDCALL
GDALSimpleImageWarp( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
int nBandCount, int *panBandList,
GDALTransformerFunc pfnTransform, void *pTransformArg,
GDALProgressFunc pfnProgress, void *pProgressArg,
char **papszWarpOptions )
{
VALIDATE_POINTER1( hSrcDS, "GDALSimpleImageWarp", 0 );
VALIDATE_POINTER1( hDstDS, "GDALSimpleImageWarp", 0 );
int iBand, bCancelled = FALSE;
/* -------------------------------------------------------------------- */
/* If no bands provided assume we should process all bands. */
/* -------------------------------------------------------------------- */
if( nBandCount == 0 )
{
int nResult;
nBandCount = GDALGetRasterCount( hSrcDS );
if (nBandCount == 0)
{
CPLError(CE_Failure, CPLE_AppDefined,
"No raster band in source dataset");
return FALSE;
}
panBandList = (int *) CPLCalloc(sizeof(int),nBandCount);
for( iBand = 0; iBand < nBandCount; iBand++ )
panBandList[iBand] = iBand+1;
nResult = GDALSimpleImageWarp( hSrcDS, hDstDS, nBandCount, panBandList,
pfnTransform, pTransformArg,
pfnProgress, pProgressArg,
papszWarpOptions );
CPLFree( panBandList );
return nResult;
}
/* -------------------------------------------------------------------- */
/* Post initial progress. */
/* -------------------------------------------------------------------- */
if( pfnProgress )
{
if( !pfnProgress( 0.0, "", pProgressArg ) )
return FALSE;
}
/* -------------------------------------------------------------------- */
/* Load the source image band(s). */
/* -------------------------------------------------------------------- */
int nSrcXSize = GDALGetRasterXSize(hSrcDS);
int nSrcYSize = GDALGetRasterYSize(hSrcDS);
GByte **papabySrcData;
papabySrcData = (GByte **) CPLCalloc(nBandCount,sizeof(GByte*));
for( iBand = 0; iBand < nBandCount; iBand++ )
{
papabySrcData[iBand] = (GByte *) VSIMalloc(nSrcXSize*nSrcYSize);
GDALRasterIO( GDALGetRasterBand(hSrcDS,panBandList[iBand]), GF_Read,
0, 0, nSrcXSize, nSrcYSize,
papabySrcData[iBand], nSrcXSize, nSrcYSize, GDT_Byte,
0, 0 );
}
/* -------------------------------------------------------------------- */
/* Check for remap request(s). */
/* -------------------------------------------------------------------- */
GDALSimpleWarpRemapping( nBandCount, papabySrcData, nSrcXSize, nSrcYSize,
papszWarpOptions );
/* -------------------------------------------------------------------- */
/* Allocate scanline buffers for output image. */
/* -------------------------------------------------------------------- */
int nDstXSize = GDALGetRasterXSize( hDstDS );
int nDstYSize = GDALGetRasterYSize( hDstDS );
GByte **papabyDstLine;
papabyDstLine = (GByte **) CPLCalloc(nBandCount,sizeof(GByte*));
for( iBand = 0; iBand < nBandCount; iBand++ )
papabyDstLine[iBand] = (GByte *) CPLMalloc( nDstXSize );
/* -------------------------------------------------------------------- */
/* Allocate x,y,z coordinate arrays for transformation ... one */
/* scanlines worth of positions. */
/* -------------------------------------------------------------------- */
double *padfX, *padfY, *padfZ;
int *pabSuccess;
padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
/* -------------------------------------------------------------------- */
/* Establish the value we will use to initialize the bands. We */
/* default to -1 indicating the initial value should be read */
/* and preserved from the source file, but allow this to be */
/* overridden by passed */
/* option(s). */
/* -------------------------------------------------------------------- */
int *panBandInit;
panBandInit = (int *) CPLCalloc(sizeof(int),nBandCount);
if( CSLFetchNameValue( papszWarpOptions, "INIT" ) )
{
int iBand, nTokenCount;
char **papszTokens =
CSLTokenizeStringComplex( CSLFetchNameValue( papszWarpOptions,
"INIT" ),
" ,", FALSE, FALSE );
nTokenCount = CSLCount(papszTokens);
for( iBand = 0; iBand < nBandCount; iBand++ )
{
if( nTokenCount == 0 )
panBandInit[iBand] = 0;
else
panBandInit[iBand] =
atoi(papszTokens[MIN(iBand,nTokenCount-1)]);
}
CSLDestroy(papszTokens);
}
/* -------------------------------------------------------------------- */
/* Loop over all the scanlines in the output image. */
/* -------------------------------------------------------------------- */
int iDstY;
for( iDstY = 0; iDstY < nDstYSize; iDstY++ )
{
int iDstX;
// Clear output buffer to "transparent" value. Shouldn't we
// really be reading from the destination file to support overlay?
for( iBand = 0; iBand < nBandCount; iBand++ )
{
if( panBandInit[iBand] == -1 )
GDALRasterIO( GDALGetRasterBand(hDstDS,iBand+1), GF_Read,
0, iDstY, nDstXSize, 1,
papabyDstLine[iBand], nDstXSize, 1, GDT_Byte,
0, 0 );
else
memset( papabyDstLine[iBand], panBandInit[iBand], nDstXSize );
}
// Set point to transform.
for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
{
padfX[iDstX] = iDstX + 0.5;
padfY[iDstX] = iDstY + 0.5;
padfZ[iDstX] = 0.0;
}
// Transform the points from destination pixel/line coordinates
// to source pixel/line coordinates.
pfnTransform( pTransformArg, TRUE, nDstXSize,
padfX, padfY, padfZ, pabSuccess );
// Loop over the output scanline.
for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
{
if( !pabSuccess[iDstX] )
continue;
// We test against the value before casting to avoid the
// problem of asymmetric truncation effects around zero. That is
// -0.5 will be 0 when cast to an int.
if( padfX[iDstX] < 0.0 || padfY[iDstX] < 0.0 )
continue;
int iSrcX, iSrcY, iSrcOffset;
iSrcX = (int) padfX[iDstX];
iSrcY = (int) padfY[iDstX];
if( iSrcX >= nSrcXSize || iSrcY >= nSrcYSize )
continue;
iSrcOffset = iSrcX + iSrcY * nSrcXSize;
for( iBand = 0; iBand < nBandCount; iBand++ )
papabyDstLine[iBand][iDstX] = papabySrcData[iBand][iSrcOffset];
}
// Write scanline to disk.
for( iBand = 0; iBand < nBandCount; iBand++ )
{
GDALRasterIO( GDALGetRasterBand(hDstDS,iBand+1), GF_Write,
0, iDstY, nDstXSize, 1,
papabyDstLine[iBand], nDstXSize, 1, GDT_Byte, 0, 0 );
}
if( pfnProgress != NULL )
{
if( !pfnProgress( (iDstY+1) / (double) nDstYSize,
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
bCancelled = TRUE;
break;
}
}
}
/* -------------------------------------------------------------------- */
/* Cleanup working buffers. */
/* -------------------------------------------------------------------- */
for( iBand = 0; iBand < nBandCount; iBand++ )
{
CPLFree( papabyDstLine[iBand] );
CPLFree( papabySrcData[iBand] );
}
CPLFree( panBandInit );
CPLFree( papabyDstLine );
CPLFree( papabySrcData );
CPLFree( padfX );
CPLFree( padfY );
CPLFree( padfZ );
CPLFree( pabSuccess );
return !bCancelled;
}
/************************************************************************/
/* GDALSimpleWarpRemapping() */
/* */
/* This function implements any raster remapping requested in */
/* the options list. The remappings are applied to the source */
/* data before warping. Two kinds are support ... REMAP */
/* commands which remap selected pixel values for any band and */
/* REMAP_MULTI which only remap pixels matching the input in */
/* all bands at once (ie. to remap an RGB value to another). */
/************************************************************************/
static void
GDALSimpleWarpRemapping( int nBandCount, GByte **papabySrcData,
int nSrcXSize, int nSrcYSize,
char **papszWarpOptions )
{
/* ==================================================================== */
/* Process any and all single value REMAP commands. */
/* ==================================================================== */
int iRemap;
char **papszRemaps = CSLFetchNameValueMultiple( papszWarpOptions,
"REMAP" );
for( iRemap = 0; iRemap < CSLCount(papszRemaps); iRemap++ )
{
/* -------------------------------------------------------------------- */
/* What are the pixel values to map from and to? */
/* -------------------------------------------------------------------- */
char **papszTokens = CSLTokenizeString( papszRemaps[iRemap] );
int nFromValue, nToValue;
if( CSLCount(papszTokens) != 2 )
{
CPLError( CE_Warning, CPLE_AppDefined,
"Ill formed REMAP `%s' ignored in GDALSimpleWarpRemapping()",
papszRemaps[iRemap] );
continue;
}
nFromValue = atoi(papszTokens[0]);
nToValue = atoi(papszTokens[1]);
CSLDestroy( papszTokens );
/* -------------------------------------------------------------------- */
/* Pass over each band searching for matches. */
/* -------------------------------------------------------------------- */
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
GByte *pabyData = papabySrcData[iBand];
int nPixelCount = nSrcXSize * nSrcYSize;
while( nPixelCount != 0 )
{
if( *pabyData == nFromValue )
*pabyData = (GByte) nToValue;
pabyData++;
nPixelCount--;
}
}
}
CSLDestroy( papszRemaps );
/* ==================================================================== */
/* Process any and all REMAP_MULTI commands. */
/* ==================================================================== */
papszRemaps = CSLFetchNameValueMultiple( papszWarpOptions,
"REMAP_MULTI" );
for( iRemap = 0; iRemap < CSLCount(papszRemaps); iRemap++ )
{
/* -------------------------------------------------------------------- */
/* What are the pixel values to map from and to? */
/* -------------------------------------------------------------------- */
char **papszTokens = CSLTokenizeString( papszRemaps[iRemap] );
int *panFromValue, *panToValue;
int nMapBandCount, iBand;
if( CSLCount(papszTokens) % 2 == 1
|| CSLCount(papszTokens) == 0
|| CSLCount(papszTokens) > nBandCount * 2 )
{
CPLError( CE_Warning, CPLE_AppDefined,
"Ill formed REMAP_MULTI `%s' ignored in GDALSimpleWarpRemapping()",
papszRemaps[iRemap] );
continue;
}
nMapBandCount = CSLCount(papszTokens) / 2;
panFromValue = (int *) CPLMalloc(sizeof(int) * nMapBandCount );
panToValue = (int *) CPLMalloc(sizeof(int) * nMapBandCount );
for( iBand = 0; iBand < nMapBandCount; iBand++ )
{
panFromValue[iBand] = atoi(papszTokens[iBand]);
panToValue[iBand] = atoi(papszTokens[iBand+nMapBandCount]);
}
CSLDestroy( papszTokens );
/* -------------------------------------------------------------------- */
/* Search for matching values to replace. */
/* -------------------------------------------------------------------- */
int nPixelCount = nSrcXSize * nSrcYSize;
int iPixel;
for( iPixel = 0; iPixel < nPixelCount; iPixel++ )
{
if( papabySrcData[0][iPixel] != panFromValue[0] )
continue;
int bMatch = TRUE;
for( iBand = 1; iBand < nMapBandCount; iBand++ )
{
if( papabySrcData[iBand][iPixel] != panFromValue[iBand] )
bMatch = FALSE;
}
if( !bMatch )
continue;
for( iBand = 0; iBand < nMapBandCount; iBand++ )
papabySrcData[iBand][iPixel] = (GByte) panToValue[iBand];
}
CPLFree( panFromValue );
CPLFree( panToValue );
}
CSLDestroy( papszRemaps );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,151 @@
/******************************************************************************
* $Id$
*
* Project: GDAL
* Purpose: Algorithm to apply a transformer to geolocation style bands.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2012, Frank Warmerdam
*
* 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_alg_priv.h"
#include "gdal_priv.h"
#include "cpl_conv.h"
CPL_CVSID("$Id$");
/************************************************************************/
/* GDALTransformGeolocations() */
/************************************************************************/
/**
* Transform locations held in bands.
*
* The X/Y and possibly Z values in the identified bands are transformed
* using a spatial transformer. The changes values are written back to the
* source bands so they need to updatable.
*
* @param hXBand the band containing the X locations (usually long/easting).
* @param hYBand the band containing the Y locations (usually lat/northing).
* @param hZBand the band containing the Z locations (may be NULL).
* @param pfnTransformer the transformer function.
* @param pTransformArg the callback data for the transformer function.
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
* @param papszOptions list of name/value options - none currently supported.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
CPLErr
GDALTransformGeolocations( GDALRasterBandH hXBand,
GDALRasterBandH hYBand,
GDALRasterBandH hZBand,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
GDALProgressFunc pfnProgress,
void *pProgressArg,
CPL_UNUSED char **papszOptions )
{
VALIDATE_POINTER1( hXBand, "GDALTransformGeolocations", CE_Failure );
VALIDATE_POINTER1( hYBand, "GDALTransformGeolocations", CE_Failure );
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Ensure the bands are matching in size. */
/* -------------------------------------------------------------------- */
GDALRasterBand *poXBand = (GDALRasterBand *) hXBand;
GDALRasterBand *poYBand = (GDALRasterBand *) hYBand;
GDALRasterBand *poZBand = (GDALRasterBand *) hZBand;
int nXSize = poXBand->GetXSize();
int nYSize = poXBand->GetYSize();
if( nXSize != poYBand->GetXSize()
|| nYSize != poYBand->GetYSize()
|| (poZBand != NULL && nXSize != poZBand->GetXSize())
|| (poZBand != NULL && nYSize != poZBand->GetYSize()) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Size of X, Y and/or Z bands do not match." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Allocate a buffer large enough to hold one whole row. */
/* -------------------------------------------------------------------- */
double *padfX = (double*) CPLMalloc(sizeof(double) * nXSize);
double *padfY = (double*) CPLMalloc(sizeof(double) * nXSize);
double *padfZ = (double*) CPLMalloc(sizeof(double) * nXSize);
int *panSuccess = (int*) CPLMalloc(sizeof(int) * nXSize);
int iLine;
CPLErr eErr = CE_None;
pfnProgress( 0.0, "", pProgressArg );
for( iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ )
{
eErr = poXBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
padfX, nXSize, 1, GDT_Float64, 0, 0, NULL );
if( eErr == CE_None )
eErr = poYBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
padfY, nXSize, 1, GDT_Float64, 0, 0, NULL );
if( eErr == CE_None && poZBand != NULL )
eErr = poZBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
padfZ, nXSize, 1, GDT_Float64, 0, 0, NULL );
else
memset( padfZ, 0, sizeof(double) * nXSize);
if( eErr == CE_None )
{
pfnTransformer( pTransformArg, FALSE, nXSize,
padfX, padfY, padfZ, panSuccess );
}
if( eErr == CE_None )
eErr = poXBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
padfX, nXSize, 1, GDT_Float64, 0, 0, NULL );
if( eErr == CE_None )
eErr = poYBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
padfY, nXSize, 1, GDT_Float64, 0, 0, NULL );
if( eErr == CE_None && poZBand != NULL )
eErr = poZBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
padfZ, nXSize, 1, GDT_Float64, 0, 0, NULL );
if( eErr == CE_None )
pfnProgress( (iLine+1) / (double) nYSize, "", pProgressArg );
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( padfX );
CPLFree( padfY );
CPLFree( padfZ );
CPLFree( panSuccess );
return eErr;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,450 @@
/******************************************************************************
* $Id: gdalwarper.h 29330 2015-06-14 12:11:11Z rouault $
*
* Project: GDAL High Performance Warper
* Purpose: Prototypes, and definitions for warping related work.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2003, Frank Warmerdam
* Copyright (c) 2009-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.
****************************************************************************/
#ifndef GDALWARPER_H_INCLUDED
#define GDALWARPER_H_INCLUDED
/**
* \file gdalwarper.h
*
* GDAL warper related entry points and definitions. Eventually it is
* expected that this file will be mostly private to the implementation,
* and the public C entry points will be available in gdal_alg.h.
*/
#include "gdal_alg.h"
#include "cpl_minixml.h"
#include "cpl_multiproc.h"
CPL_C_START
/* Note: values are selected to be consistent with GDALRIOResampleAlg of gcore/gdal.h */
/*! Warp Resampling Algorithm */
typedef enum {
/*! Nearest neighbour (select on one input pixel) */ GRA_NearestNeighbour=0,
/*! Bilinear (2x2 kernel) */ GRA_Bilinear=1,
/*! Cubic Convolution Approximation (4x4 kernel) */ GRA_Cubic=2,
/*! Cubic B-Spline Approximation (4x4 kernel) */ GRA_CubicSpline=3,
/*! Lanczos windowed sinc interpolation (6x6 kernel) */ GRA_Lanczos=4,
/*! Average (computes the average of all non-NODATA contributing pixels) */ GRA_Average=5,
/*! Mode (selects the value which appears most often of all the sampled points) */ GRA_Mode=6,
// GRA_Gauss=7 reserved.
/*! Max (selects maximum of all non-NODATA contributing pixels) */ GRA_Max=8,
/*! Min (selects minimum of all non-NODATA contributing pixels) */ GRA_Min=9,
/*! Med (selects median of all non-NODATA contributing pixels) */ GRA_Med=10,
/*! Q1 (selects first quartile of all non-NODATA contributing pixels) */ GRA_Q1=11,
/*! Q3 (selects third quartile of all non-NODATA contributing pixels) */ GRA_Q3=12
} GDALResampleAlg;
/*! GWKAverageOrMode Algorithm */
typedef enum {
/*! Average */ GWKAOM_Average=1,
/*! Mode */ GWKAOM_Fmode=2,
/*! Mode of GDT_Byte, GDT_UInt16, or GDT_Int16 */ GWKAOM_Imode=3,
/*! Maximum */ GWKAOM_Max=4,
/*! Minimum */ GWKAOM_Min=5,
/*! Quantile */ GWKAOM_Quant=6
} GWKAverageOrModeAlg;
typedef int
(*GDALMaskFunc)( void *pMaskFuncArg,
int nBandCount, GDALDataType eType,
int nXOff, int nYOff,
int nXSize, int nYSize,
GByte **papabyImageData,
int bMaskIsFloat, void *pMask );
CPLErr CPL_DLL
GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte **papabyImageData, int bMaskIsFloat,
void *pValidityMask, int* pbOutAllValid );
CPLErr CPL_DLL
GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask );
CPLErr CPL_DLL
GDALWarpSrcAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask, int* pbOutAllOpaque );
CPLErr CPL_DLL
GDALWarpSrcMaskMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask );
CPLErr CPL_DLL
GDALWarpCutlineMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /* ppImageData */,
int bMaskIsFloat, void *pValidityMask );
/************************************************************************/
/* GDALWarpOptions */
/************************************************************************/
/** Warp control options for use with GDALWarpOperation::Initialize() */
typedef struct {
char **papszWarpOptions;
/*! In bytes, 0.0 for internal default */
double dfWarpMemoryLimit;
/*! Resampling algorithm to use */
GDALResampleAlg eResampleAlg;
/*! data type to use during warp operation, GDT_Unknown lets the algorithm
select the type */
GDALDataType eWorkingDataType;
/*! Source image dataset. */
GDALDatasetH hSrcDS;
/*! Destination image dataset - may be NULL if only using GDALWarpOperation::WarpRegionToBuffer(). */
GDALDatasetH hDstDS;
/*! Number of bands to process, may be 0 to select all bands. */
int nBandCount;
/*! The band numbers for the source bands to process (1 based) */
int *panSrcBands;
/*! The band numbers for the destination bands to process (1 based) */
int *panDstBands;
/*! The source band so use as an alpha (transparency) value, 0=disabled */
int nSrcAlphaBand;
/*! The dest. band so use as an alpha (transparency) value, 0=disabled */
int nDstAlphaBand;
/*! The "nodata" value real component for each input band, if NULL there isn't one */
double *padfSrcNoDataReal;
/*! The "nodata" value imaginary component - may be NULL even if real
component is provided. */
double *padfSrcNoDataImag;
/*! The "nodata" value real component for each output band, if NULL there isn't one */
double *padfDstNoDataReal;
/*! The "nodata" value imaginary component - may be NULL even if real
component is provided. */
double *padfDstNoDataImag;
/*! GDALProgressFunc() compatible progress reporting function, or NULL
if there isn't one. */
GDALProgressFunc pfnProgress;
/*! Callback argument to be passed to pfnProgress. */
void *pProgressArg;
/*! Type of spatial point transformer function */
GDALTransformerFunc pfnTransformer;
/*! Handle to image transformer setup structure */
void *pTransformerArg;
GDALMaskFunc *papfnSrcPerBandValidityMaskFunc;
void **papSrcPerBandValidityMaskFuncArg;
GDALMaskFunc pfnSrcValidityMaskFunc;
void *pSrcValidityMaskFuncArg;
GDALMaskFunc pfnSrcDensityMaskFunc;
void *pSrcDensityMaskFuncArg;
GDALMaskFunc pfnDstDensityMaskFunc;
void *pDstDensityMaskFuncArg;
GDALMaskFunc pfnDstValidityMaskFunc;
void *pDstValidityMaskFuncArg;
CPLErr (*pfnPreWarpChunkProcessor)( void *pKern, void *pArg );
void *pPreWarpProcessorArg;
CPLErr (*pfnPostWarpChunkProcessor)( void *pKern, void *pArg);
void *pPostWarpProcessorArg;
/*! Optional OGRPolygonH for a masking cutline. */
void *hCutline;
/*! Optional blending distance to apply across cutline in pixels, default is zero. */
double dfCutlineBlendDist;
} GDALWarpOptions;
GDALWarpOptions CPL_DLL * CPL_STDCALL GDALCreateWarpOptions(void);
void CPL_DLL CPL_STDCALL GDALDestroyWarpOptions( GDALWarpOptions * );
GDALWarpOptions CPL_DLL * CPL_STDCALL
GDALCloneWarpOptions( const GDALWarpOptions * );
CPLXMLNode CPL_DLL * CPL_STDCALL
GDALSerializeWarpOptions( const GDALWarpOptions * );
GDALWarpOptions CPL_DLL * CPL_STDCALL
GDALDeserializeWarpOptions( CPLXMLNode * );
/************************************************************************/
/* GDALReprojectImage() */
/************************************************************************/
CPLErr CPL_DLL CPL_STDCALL
GDALReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
GDALDatasetH hDstDS, const char *pszDstWKT,
GDALResampleAlg eResampleAlg, double dfWarpMemoryLimit,
double dfMaxError,
GDALProgressFunc pfnProgress, void *pProgressArg,
GDALWarpOptions *psOptions );
CPLErr CPL_DLL CPL_STDCALL
GDALCreateAndReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
const char *pszDstFilename, const char *pszDstWKT,
GDALDriverH hDstDriver, char **papszCreateOptions,
GDALResampleAlg eResampleAlg, double dfWarpMemoryLimit,
double dfMaxError,
GDALProgressFunc pfnProgress, void *pProgressArg,
GDALWarpOptions *psOptions );
/************************************************************************/
/* VRTWarpedDataset */
/************************************************************************/
GDALDatasetH CPL_DLL CPL_STDCALL
GDALAutoCreateWarpedVRT( GDALDatasetH hSrcDS,
const char *pszSrcWKT, const char *pszDstWKT,
GDALResampleAlg eResampleAlg,
double dfMaxError, const GDALWarpOptions *psOptions );
GDALDatasetH CPL_DLL CPL_STDCALL
GDALCreateWarpedVRT( GDALDatasetH hSrcDS,
int nPixels, int nLines, double *padfGeoTransform,
GDALWarpOptions *psOptions );
CPLErr CPL_DLL CPL_STDCALL
GDALInitializeWarpedVRT( GDALDatasetH hDS,
GDALWarpOptions *psWO );
CPL_C_END
#ifdef __cplusplus
/************************************************************************/
/* GDALWarpKernel */
/* */
/* This class represents the lowest level of abstraction. It */
/* is holds the imagery for one "chunk" of a warp, and the */
/* pre-prepared masks. All IO is done before and after it's */
/* operation. This class is not normally used by the */
/* application. */
/************************************************************************/
// This is the number of dummy pixels that must be reserved in source arrays
// in order to satisfy assumptions made in GWKResample(), and more specifically
// by GWKGetPixelRow() that always read a even number of pixels. So if we are
// in the situation to read the last pixel of the source array, we need 1 extra
// dummy pixel to avoid reading out of bounds.
#define WARP_EXTRA_ELTS 1
class CPL_DLL GDALWarpKernel
{
public:
char **papszWarpOptions;
GDALResampleAlg eResample;
GDALDataType eWorkingDataType;
int nBands;
int nSrcXSize;
int nSrcYSize;
int nSrcXExtraSize; /* extra pixels (included in nSrcXSize) reserved for filter window. Should be ignored in scale computation */
int nSrcYExtraSize; /* extra pixels (included in nSrcYSize) reserved for filter window. Should be ignored in scale computation */
GByte **papabySrcImage; /* each subarray must have WARP_EXTRA_ELTS at the end */
GUInt32 **papanBandSrcValid; /* each subarray must have WARP_EXTRA_ELTS at the end */
GUInt32 *panUnifiedSrcValid; /* must have WARP_EXTRA_ELTS at the end */
float *pafUnifiedSrcDensity; /* must have WARP_EXTRA_ELTS at the end */
int nDstXSize;
int nDstYSize;
GByte **papabyDstImage;
GUInt32 *panDstValid;
float *pafDstDensity;
double dfXScale; // Resampling scale, i.e.
double dfYScale; // nDstSize/nSrcSize.
double dfXFilter; // Size of filter kernel.
double dfYFilter;
int nXRadius; // Size of window to filter.
int nYRadius;
int nFiltInitX; // Filtering offset
int nFiltInitY;
int nSrcXOff;
int nSrcYOff;
int nDstXOff;
int nDstYOff;
GDALTransformerFunc pfnTransformer;
void *pTransformerArg;
GDALProgressFunc pfnProgress;
void *pProgress;
double dfProgressBase;
double dfProgressScale;
double *padfDstNoDataReal;
GDALWarpKernel();
virtual ~GDALWarpKernel();
CPLErr Validate();
CPLErr PerformWarp();
};
/************************************************************************/
/* GDALWarpOperation() */
/* */
/* This object is application created, or created by a higher */
/* level convenience function. It is responsible for */
/* subdividing the operation into chunks, loading and saving */
/* imagery, and establishing the varios validity and density */
/* masks. Actual resampling is done by the GDALWarpKernel. */
/************************************************************************/
typedef struct _GDALWarpChunk GDALWarpChunk;
class CPL_DLL GDALWarpOperation {
private:
GDALWarpOptions *psOptions;
void WipeOptions();
int ValidateOptions();
CPLErr ComputeSourceWindow( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
int *pnSrcXOff, int *pnSrcYOff,
int *pnSrcXSize, int *pnSrcYSize,
int *pnSrcXExtraSize, int *pnSrcYExtraSize,
double* pdfSrcFillRatio );
CPLErr CreateKernelMask( GDALWarpKernel *, int iBand,
const char *pszType );
CPLMutex *hIOMutex;
CPLMutex *hWarpMutex;
int nChunkListCount;
int nChunkListMax;
GDALWarpChunk *pasChunkList;
int bReportTimings;
unsigned long nLastTimeReported;
void WipeChunkList();
CPLErr CollectChunkList( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
void ReportTiming( const char * );
public:
GDALWarpOperation();
virtual ~GDALWarpOperation();
CPLErr Initialize( const GDALWarpOptions *psNewOptions );
const GDALWarpOptions *GetOptions();
CPLErr ChunkAndWarpImage( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
CPLErr ChunkAndWarpMulti( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
CPLErr WarpRegion( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
int nSrcXOff=0, int nSrcYOff=0,
int nSrcXSize=0, int nSrcYSize=0,
double dfProgressBase=0.0, double dfProgressScale=1.0);
CPLErr WarpRegion( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
int nSrcXOff, int nSrcYOff,
int nSrcXSize, int nSrcYSize,
int nSrcXExtraSize, int nSrcYExtraSize,
double dfProgressBase, double dfProgressScale);
CPLErr WarpRegionToBuffer( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
void *pDataBuf,
GDALDataType eBufDataType,
int nSrcXOff=0, int nSrcYOff=0,
int nSrcXSize=0, int nSrcYSize=0,
double dfProgressBase=0.0, double dfProgressScale=1.0);
CPLErr WarpRegionToBuffer( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
void *pDataBuf,
GDALDataType eBufDataType,
int nSrcXOff, int nSrcYOff,
int nSrcXSize, int nSrcYSize,
int nSrcXExtraSize, int nSrcYExtraSize,
double dfProgressBase, double dfProgressScale);
};
#endif /* def __cplusplus */
CPL_C_START
typedef void * GDALWarpOperationH;
GDALWarpOperationH CPL_DLL GDALCreateWarpOperation(const GDALWarpOptions* );
void CPL_DLL GDALDestroyWarpOperation( GDALWarpOperationH );
CPLErr CPL_DLL GDALChunkAndWarpImage( GDALWarpOperationH, int, int, int, int );
CPLErr CPL_DLL GDALChunkAndWarpMulti( GDALWarpOperationH, int, int, int, int );
CPLErr CPL_DLL GDALWarpRegion( GDALWarpOperationH,
int, int, int, int, int, int, int, int );
CPLErr CPL_DLL GDALWarpRegionToBuffer( GDALWarpOperationH, int, int, int, int,
void *, GDALDataType,
int, int, int, int );
/************************************************************************/
/* Warping kernel functions */
/************************************************************************/
int GWKGetFilterRadius(GDALResampleAlg eResampleAlg);
typedef double (*FilterFuncType)(double dfX);
FilterFuncType GWKGetFilterFunc(GDALResampleAlg eResampleAlg);
typedef double (*FilterFunc4ValuesType)(double* padfVals);
FilterFunc4ValuesType GWKGetFilterFunc4Values(GDALResampleAlg eResampleAlg);
CPL_C_END
#endif /* ndef GDAL_ALG_H_INCLUDED */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,198 @@
/******************************************************************************
* $Id: gdalwarpkernel_opencl.h 25068 2012-10-07 14:01:47Z rouault $
*
* Project: OpenCL Image Reprojector
* Purpose: Implementation of the GDALWarpKernel reprojector in OpenCL.
* Author: Seth Price, seth@pricepages.org
*
******************************************************************************
* Copyright (c) 2010, Seth Price <seth@pricepages.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.
****************************************************************************/
#if defined(HAVE_OPENCL)
/* The following relates to the profiling calls to
clSetCommandQueueProperty() which are not available by default
with some OpenCL implementation (ie. ATI) */
#if defined(DEBUG_OPENCL) && DEBUG_OPENCL == 1
#define CL_USE_DEPRECATED_OPENCL_1_0_APIS
#endif
#ifdef __APPLE__
#include <OpenCL/OpenCL.h>
#else
#include <CL/opencl.h>
#endif
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
typedef enum {
OCL_Bilinear=10,
OCL_Cubic=11,
OCL_CubicSpline=12,
OCL_Lanczos=13
} OCLResampAlg;
typedef enum
{
VENDOR_OTHER,
VENDOR_AMD,
VENDOR_INTEL
} OCLVendor;
struct oclWarper {
cl_command_queue queue;
cl_context context;
cl_device_id dev;
cl_kernel kern1;
cl_kernel kern4;
int srcWidth;
int srcHeight;
int dstWidth;
int dstHeight;
int useUnifiedSrcDensity;
int useUnifiedSrcValid;
int useDstDensity;
int useDstValid;
int numBands;
int numImages;
OCLResampAlg resampAlg;
cl_channel_type imageFormat;
cl_mem *realWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} realWork;
cl_mem *imagWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} imagWork;
cl_mem *dstRealWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} dstRealWork;
cl_mem *dstImagWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} dstImagWork;
unsigned int imgChSize1;
cl_channel_order imgChOrder1;
unsigned int imgChSize4;
cl_channel_order imgChOrder4;
char useVec;
cl_mem useBandSrcValidCL;
char *useBandSrcValid;
cl_mem nBandSrcValidCL;
float *nBandSrcValid;
cl_mem xyWorkCL;
float *xyWork;
int xyWidth;
int xyHeight;
int coordMult;
unsigned int xyChSize;
cl_channel_order xyChOrder;
cl_mem fDstNoDataRealCL;
float *fDstNoDataReal;
OCLVendor eCLVendor;
};
struct oclWarper* GDALWarpKernelOpenCL_createEnv(int srcWidth, int srcHeight,
int dstWidth, int dstHeight,
cl_channel_type imageFormat,
int numBands, int coordMult,
int useImag, int useBandSrcValid,
float *fDstDensity,
double *dfDstNoDataReal,
OCLResampAlg resampAlg, cl_int *envErr);
cl_int GDALWarpKernelOpenCL_setSrcValid(struct oclWarper *warper,
int *bandSrcValid, int bandNum);
cl_int GDALWarpKernelOpenCL_setSrcImg(struct oclWarper *warper, void *imgData,
int bandNum);
cl_int GDALWarpKernelOpenCL_setDstImg(struct oclWarper *warper, void *imgData,
int bandNum);
cl_int GDALWarpKernelOpenCL_setCoordRow(struct oclWarper *warper,
double *rowSrcX, double *rowSrcY,
double srcXOff, double srcYOff,
int *success, int rowNum);
cl_int GDALWarpKernelOpenCL_runResamp(struct oclWarper *warper,
float *unifiedSrcDensity,
unsigned int *unifiedSrcValid,
float *dstDensity,
unsigned int *dstValid,
double dfXScale, double dfYScale,
double dfXFilter, double dfYFilter,
int nXRadius, int nYRadius,
int nFiltInitX, int nFiltInitY);
cl_int GDALWarpKernelOpenCL_getRow(struct oclWarper *warper,
void **rowReal, void **rowImag,
int rowNum, int bandNum);
cl_int GDALWarpKernelOpenCL_deleteEnv(struct oclWarper *warper);
#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
}
#endif
#endif /* defined(HAVE_OPENCL) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,94 @@
#ifndef _GVGCPFIT_H_INCLUDED
#define _GVGCPFIT_H_INCLUDED
#include "cpl_port.h"
#include "cpl_conv.h"
#include "cpl_error.h"
#define EXTERNAL
#define LOCAL static
#define SUCCESS 0
#define ABORT -1
/*------------------------ Start of file CURVEFIT.H -----------------------*/
/*
******************************************************************************
* *
* CURVEFIT.H *
* ========= *
* *
* This file contains the function prototype for CURVEFIT.C. *
******************************************************************************
*/
#ifndef CURVEFIT_H
#define CURVEFIT_H
/*- Function prototypes in CURVEFIT.C. -*/
EXTERNAL int svdfit(float x[], float y[], int ndata,
double a[], int ma, double **u, double **v, double w[],
double *chisq, void (*funcs)(double, double *, int));
EXTERNAL void svbksb(double **u, double w[], double **v, int m,int n,
double b[], double x[]);
EXTERNAL void svdvar(double **v, int ma, double w[], double **cvm);
EXTERNAL int svdcmp(double **a, int m, int n, double *w, double **v);
#endif
/*-------------------------- End of file CURVEFIT.H -----------------------*/
/*----------------------------- FILE polyfit.h ----------------------------*/
#ifndef __POLYFIT_H
#define __POLYFIT_H
EXTERNAL int OneDPolyFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *f_array, double *x_array );
EXTERNAL double OneDPolyEval( double *coeff, int order, double x );
EXTERNAL int TwoDPolyFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *f_array, double *x_array,
double *y_array );
EXTERNAL double TwoDPolyEval( double *coeff, int order, double x, double y );
EXTERNAL int TwoDPolyGradFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *gradxy_array,
double *x_array, double *y_array );
EXTERNAL void TwoDPolyGradEval(double *fgradx, double *fgrady,
double *coeff, int order, double x, double y);
EXTERNAL void GetPolyInX (double *xcoeffs, double *xycoeffs, int order,
double y);
EXTERNAL void GetPolyInY(double *ycoeffs, double *xycoeffs, int order,
double x);
EXTERNAL int ThreeDPolyFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *f_array, double *x_array,
double *y_array, double *z_array );
EXTERNAL double ThreeDPolyEval( double *coeff, int order, double x, double y, double z );
#endif /* __POLYFIT_H */
/*---------------------- End of FILE polyfit.h ----------------------------*/
#endif /* ndef _GVGCPFIT_INCLUDED */

View file

@ -0,0 +1,606 @@
/******************************************************************************
* $Id: llrasterize.cpp 29117 2015-05-02 20:50:05Z rouault $
*
* Project: GDAL
* Purpose: Vector polygon rasterization code.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2011, 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_alg.h"
#include "gdal_alg_priv.h"
static int llCompareInt(const void *a, const void *b)
{
return (*(const int *)a) - (*(const int *)b);
}
static void llSwapDouble(double *a, double *b)
{
double temp = *a;
*a = *b;
*b = temp;
}
/************************************************************************/
/* dllImageFilledPolygon() */
/* */
/* Perform scanline conversion of the passed multi-ring */
/* polygon. Note the polygon does not need to be explicitly */
/* closed. The scanline function will be called with */
/* horizontal scanline chunks which may not be entirely */
/* contained within the valid raster area (in the X */
/* direction). */
/* */
/* NEW: Nodes' coordinate are kept as double in order */
/* to compute accurately the intersections with the lines */
/* */
/* Two methods for determining the border pixels: */
/* */
/* 1) method = 0 */
/* Inherits algorithm from version above but with several bugs */
/* fixed except for the cone facing down. */
/* A pixel on which a line intersects a segment of a */
/* polygon will always be considered as inside the shape. */
/* Note that we only compute intersections with lines that */
/* passes through the middle of a pixel (line coord = 0.5, */
/* 1.5, 2.5, etc.) */
/* */
/* 2) method = 1: */
/* A pixel is considered inside a polygon if its center */
/* falls inside the polygon. This is somehow more robust unless */
/* the nodes are placed in the center of the pixels in which */
/* case, due to numerical inaccuracies, it's hard to predict */
/* if the pixel will be considered inside or outside the shape. */
/************************************************************************/
/*
* NOTE: This code was originally adapted from the gdImageFilledPolygon()
* function in libgd.
*
* http://www.boutell.com/gd/
*
* It was later adapted for direct inclusion in GDAL and relicensed under
* the GDAL MIT/X license (pulled from the OpenEV distribution).
*/
void GDALdllImageFilledPolygon(int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY,
double *dfVariant,
llScanlineFunc pfnScanlineFunc, void *pCBData )
{
/*************************************************************************
2nd Method (method=1):
=====================
No known bug
*************************************************************************/
int i;
int y;
int miny, maxy,minx,maxx;
double dminy, dmaxy;
double dx1, dy1;
double dx2, dy2;
double dy;
double intersect;
int ind1, ind2;
int ints, n, part;
int *polyInts;
int horizontal_x1, horizontal_x2;
if (!nPartCount) {
return;
}
n = 0;
for( part = 0; part < nPartCount; part++ )
n += panPartSize[part];
polyInts = (int *) malloc(sizeof(int) * n);
dminy = padfY[0];
dmaxy = padfY[0];
for (i=1; (i < n); i++) {
if (padfY[i] < dminy) {
dminy = padfY[i];
}
if (padfY[i] > dmaxy) {
dmaxy = padfY[i];
}
}
miny = (int) dminy;
maxy = (int) dmaxy;
if( miny < 0 )
miny = 0;
if( maxy >= nRasterYSize )
maxy = nRasterYSize-1;
minx = 0;
maxx = nRasterXSize - 1;
/* Fix in 1.3: count a vertex only once */
for (y=miny; y <= maxy; y++) {
int partoffset = 0;
dy = y +0.5; /* center height of line*/
part = 0;
ints = 0;
/*Initialize polyInts, otherwise it can sometimes causes a seg fault */
memset(polyInts, -1, sizeof(int) * n);
for (i=0; (i < n); i++) {
if( i == partoffset + panPartSize[part] ) {
partoffset += panPartSize[part];
part++;
}
if( i == partoffset ) {
ind1 = partoffset + panPartSize[part] - 1;
ind2 = partoffset;
} else {
ind1 = i-1;
ind2 = i;
}
dy1 = padfY[ind1];
dy2 = padfY[ind2];
if( (dy1 < dy && dy2 < dy) || (dy1 > dy && dy2 > dy) )
continue;
if (dy1 < dy2) {
dx1 = padfX[ind1];
dx2 = padfX[ind2];
} else if (dy1 > dy2) {
dy2 = padfY[ind1];
dy1 = padfY[ind2];
dx2 = padfX[ind1];
dx1 = padfX[ind2];
} else /* if (fabs(dy1-dy2)< 1.e-6) */
{
/*AE: DO NOT skip bottom horizontal segments
-Fill them separately-
They are not taken into account twice.*/
if (padfX[ind1] > padfX[ind2])
{
horizontal_x1 = (int) floor(padfX[ind2]+0.5);
horizontal_x2 = (int) floor(padfX[ind1]+0.5);
if ( (horizontal_x1 > maxx) || (horizontal_x2 <= minx) )
continue;
/*fill the horizontal segment (separately from the rest)*/
pfnScanlineFunc( pCBData, y, horizontal_x1, horizontal_x2 - 1, (dfVariant == NULL)?0:dfVariant[0] );
continue;
}
else /*skip top horizontal segments (they are already filled in the regular loop)*/
continue;
}
if(( dy < dy2 ) && (dy >= dy1))
{
intersect = (dy-dy1) * (dx2-dx1) / (dy2-dy1) + dx1;
polyInts[ints++] = (int) floor(intersect+0.5);
}
}
/*
* It would be more efficient to do this inline, to avoid
* a function call for each comparison.
* NOTE - mloskot: make llCompareInt a functor and use std
* algorithm and it will be optimized and expanded
* automatically in compile-time, with modularity preserved.
*/
qsort(polyInts, ints, sizeof(int), llCompareInt);
for (i=0; (i < (ints)); i+=2)
{
if( polyInts[i] <= maxx && polyInts[i+1] > minx )
{
pfnScanlineFunc( pCBData, y, polyInts[i], polyInts[i+1] - 1, (dfVariant == NULL)?0:dfVariant[0] );
}
}
}
free( polyInts );
}
/************************************************************************/
/* GDALdllImagePoint() */
/************************************************************************/
void GDALdllImagePoint( int nRasterXSize, int nRasterYSize,
int nPartCount,
CPL_UNUSED int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData )
{
int i;
for ( i = 0; i < nPartCount; i++ )
{
int nX = (int)floor( padfX[i] );
int nY = (int)floor( padfY[i] );
double dfVariant = 0;
if( padfVariant != NULL )
dfVariant = padfVariant[i];
if ( 0 <= nX && nX < nRasterXSize && 0 <= nY && nY < nRasterYSize )
pfnPointFunc( pCBData, nY, nX, dfVariant );
}
}
/************************************************************************/
/* GDALdllImageLine() */
/************************************************************************/
void GDALdllImageLine( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData )
{
int i, n;
if ( !nPartCount )
return;
for ( i = 0, n = 0; i < nPartCount; n += panPartSize[i++] )
{
int j;
for ( j = 1; j < panPartSize[i]; j++ )
{
int iX = (int)floor( padfX[n + j - 1] );
int iY = (int)floor( padfY[n + j - 1] );
const int iX1 = (int)floor( padfX[n + j] );
const int iY1 = (int)floor( padfY[n + j] );
double dfVariant = 0, dfVariant1 = 0;
if( padfVariant != NULL &&
((GDALRasterizeInfo *)pCBData)->eBurnValueSource !=
GBV_UserBurnValue )
{
dfVariant = padfVariant[n + j - 1];
dfVariant1 = padfVariant[n + j];
}
int nDeltaX = ABS( iX1 - iX );
int nDeltaY = ABS( iY1 - iY );
// Step direction depends on line direction.
const int nXStep = ( iX > iX1 ) ? -1 : 1;
const int nYStep = ( iY > iY1 ) ? -1 : 1;
// Determine the line slope.
if ( nDeltaX >= nDeltaY )
{
const int nXError = nDeltaY << 1;
const int nYError = nXError - (nDeltaX << 1);
int nError = nXError - nDeltaX;
/* == 0 makes clang -fcatch-undefined-behavior -ftrapv happy, but if */
/* it is == 0, dfDeltaVariant is not really used, so any value is OK */
double dfDeltaVariant = (nDeltaX == 0) ? 0 : (dfVariant1 - dfVariant) /
(double)nDeltaX;
while ( nDeltaX-- >= 0 )
{
if ( 0 <= iX && iX < nRasterXSize
&& 0 <= iY && iY < nRasterYSize )
pfnPointFunc( pCBData, iY, iX, dfVariant );
dfVariant += dfDeltaVariant;
iX += nXStep;
if ( nError > 0 )
{
iY += nYStep;
nError += nYError;
}
else
nError += nXError;
}
}
else
{
const int nXError = nDeltaX << 1;
const int nYError = nXError - (nDeltaY << 1);
int nError = nXError - nDeltaY;
/* == 0 makes clang -fcatch-undefined-behavior -ftrapv happy, but if */
/* it is == 0, dfDeltaVariant is not really used, so any value is OK */
double dfDeltaVariant = (nDeltaY == 0) ? 0 : (dfVariant1 - dfVariant) /
(double)nDeltaY;
while ( nDeltaY-- >= 0 )
{
if ( 0 <= iX && iX < nRasterXSize
&& 0 <= iY && iY < nRasterYSize )
pfnPointFunc( pCBData, iY, iX, dfVariant );
dfVariant += dfDeltaVariant;
iY += nYStep;
if ( nError > 0 )
{
iX += nXStep;
nError += nYError;
}
else
nError += nXError;
}
}
}
}
}
/************************************************************************/
/* GDALdllImageLineAllTouched() */
/* */
/* This alternate line drawing algorithm attempts to ensure */
/* that every pixel touched at all by the line will get set. */
/* @param padfVariant should contain the values that are to be */
/* added to the burn value. The values along the line between the */
/* points will be linearly interpolated. These values are used */
/* only if pCBData->eBurnValueSource is set to something other */
/* than GBV_UserBurnValue. If NULL is passed, a monotonous line */
/* will be drawn with the burn value. */
/************************************************************************/
void
GDALdllImageLineAllTouched(int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData )
{
int i, n;
if ( !nPartCount )
return;
for ( i = 0, n = 0; i < nPartCount; n += panPartSize[i++] )
{
int j;
for ( j = 1; j < panPartSize[i]; j++ )
{
double dfX = padfX[n + j - 1];
double dfY = padfY[n + j - 1];
double dfXEnd = padfX[n + j];
double dfYEnd = padfY[n + j];
double dfVariant = 0, dfVariantEnd = 0;
if( padfVariant != NULL &&
((GDALRasterizeInfo *)pCBData)->eBurnValueSource !=
GBV_UserBurnValue )
{
dfVariant = padfVariant[n + j - 1];
dfVariantEnd = padfVariant[n + j];
}
// Skip segments that are off the target region.
if( (dfY < 0 && dfYEnd < 0)
|| (dfY > nRasterYSize && dfYEnd > nRasterYSize)
|| (dfX < 0 && dfXEnd < 0)
|| (dfX > nRasterXSize && dfXEnd > nRasterXSize) )
continue;
// Swap if needed so we can proceed from left2right (X increasing)
if( dfX > dfXEnd )
{
llSwapDouble( &dfX, &dfXEnd );
llSwapDouble( &dfY, &dfYEnd );
llSwapDouble( &dfVariant, &dfVariantEnd );
}
// Special case for vertical lines.
if( floor(dfX) == floor(dfXEnd) )
{
if( dfYEnd < dfY )
{
llSwapDouble( &dfY, &dfYEnd );
llSwapDouble( &dfVariant, &dfVariantEnd );
}
int iX = (int) floor(dfX);
int iY = (int) floor(dfY);
int iYEnd = (int) floor(dfYEnd);
if( iX >= nRasterXSize )
continue;
double dfDeltaVariant = 0;
if(( dfYEnd - dfY ) > 0)
dfDeltaVariant = ( dfVariantEnd - dfVariant )
/ ( dfYEnd - dfY );//per unit change in iY
// Clip to the borders of the target region
if( iY < 0 )
iY = 0;
if( iYEnd >= nRasterYSize )
iYEnd = nRasterYSize - 1;
dfVariant += dfDeltaVariant * ( (double)iY - dfY );
if( padfVariant == NULL )
for( ; iY <= iYEnd; iY++ )
pfnPointFunc( pCBData, iY, iX, 0.0 );
else
for( ; iY <= iYEnd; iY++, dfVariant += dfDeltaVariant )
pfnPointFunc( pCBData, iY, iX, dfVariant );
continue; // next segment
}
double dfDeltaVariant = ( dfVariantEnd - dfVariant )
/ ( dfXEnd - dfX );//per unit change in iX
// special case for horizontal lines
if( floor(dfY) == floor(dfYEnd) )
{
if( dfXEnd < dfX )
{
llSwapDouble( &dfX, &dfXEnd );
llSwapDouble( &dfVariant, &dfVariantEnd );
}
int iX = (int) floor(dfX);
int iY = (int) floor(dfY);
int iXEnd = (int) floor(dfXEnd);
if( iY >= nRasterYSize )
continue;
// Clip to the borders of the target region
if( iX < 0 )
iX = 0;
if( iXEnd >= nRasterXSize )
iXEnd = nRasterXSize - 1;
dfVariant += dfDeltaVariant * ( (double)iX - dfX );
if( padfVariant == NULL )
for( ; iX <= iXEnd; iX++ )
pfnPointFunc( pCBData, iY, iX, 0.0 );
else
for( ; iX <= iXEnd; iX++, dfVariant += dfDeltaVariant )
pfnPointFunc( pCBData, iY, iX, dfVariant );
continue; // next segment
}
/* -------------------------------------------------------------------- */
/* General case - left to right sloped. */
/* -------------------------------------------------------------------- */
double dfSlope = (dfYEnd - dfY) / (dfXEnd - dfX);
// clip segment in X
if( dfXEnd > nRasterXSize )
{
dfYEnd -= ( dfXEnd - (double)nRasterXSize ) * dfSlope;
dfXEnd = nRasterXSize;
}
if( dfX < 0 )
{
dfY += (0 - dfX) * dfSlope;
dfVariant += dfDeltaVariant * (0.0 - dfX);
dfX = 0.0;
}
// clip segment in Y
double dfDiffX;
if( dfYEnd > dfY )
{
if( dfY < 0 )
{
dfX += (dfDiffX = (0 - dfY) / dfSlope);
dfVariant += dfDeltaVariant * dfDiffX;
dfY = 0.0;
}
if( dfYEnd >= nRasterYSize )
{
dfXEnd += ( dfYEnd - (double)nRasterYSize ) / dfSlope;
dfYEnd = nRasterXSize;
}
}
else
{
if( dfY >= nRasterYSize )
{
dfX += (dfDiffX = ((double)nRasterYSize - dfY) / dfSlope);
dfVariant += dfDeltaVariant * dfDiffX;
dfY = nRasterYSize;
}
if( dfYEnd < 0 )
{
dfXEnd -= ( dfYEnd - 0 ) / dfSlope;
dfYEnd = 0;
}
}
// step from pixel to pixel.
while( dfX >= 0 && dfX < dfXEnd )
{
int iX = (int) floor(dfX);
int iY = (int) floor(dfY);
// burn in the current point.
// We should be able to drop the Y check because we cliped in Y,
// but there may be some error with all the small steps.
if( iY >= 0 && iY < nRasterYSize )
pfnPointFunc( pCBData, iY, iX, dfVariant );
double dfStepX = floor(dfX+1.0) - dfX;
double dfStepY = dfStepX * dfSlope;
// step to right pixel without changing scanline?
if( (int) floor(dfY + dfStepY) == iY )
{
dfX += dfStepX;
dfY += dfStepY;
dfVariant += dfDeltaVariant * dfStepX;
}
else if( dfSlope < 0 )
{
dfStepY = iY - dfY;
if( dfStepY > -0.000000001 )
dfStepY = -0.000000001;
dfStepX = dfStepY / dfSlope;
dfX += dfStepX;
dfY += dfStepY;
dfVariant += dfDeltaVariant * dfStepX;
}
else
{
dfStepY = (iY + 1) - dfY;
if( dfStepY < 0.000000001 )
dfStepY = 0.000000001;
dfStepX = dfStepY / dfSlope;
dfX += dfStepX;
dfY += dfStepY;
dfVariant += dfDeltaVariant * dfStepX;
}
} // next step along sement.
} // next segment
} // next part
}

View file

@ -0,0 +1,31 @@
#
# Algorithms
#
GDAL_ROOT = ..
EXTRAFLAGS = -I../ogr/ogrsf_frmts $(GEOS_CFLAGS)
!INCLUDE ..\nmake.opt
!IFDEF INCLUDE_OGR_FRMTS
EXTRAFLAGS = $(EXTRAFLAGS) -DOGR_ENABLED
!ENDIF
OBJ = gdaldither.obj gdalmediancut.obj gdal_crs.obj gdaltransformer.obj \
gdalsimplewarp.obj gdalwarper.obj gdalwarpkernel.obj \
thinplatespline.obj gdal_tps.obj gdalrasterize.obj llrasterize.obj \
gdalwarpoperation.obj gdalchecksum.obj gdal_rpc.obj gdalgeoloc.obj \
gdalgrid.obj gdalgridsse.obj gdalcutline.obj gdalproximity.obj rasterfill.obj \
gdalsievefilter.obj gdalrasterpolygonenumerator.obj polygonize.obj \
gdalrasterfpolygonenumerator.obj fpolygonize.obj contour.obj \
gdal_octave.obj gdal_simplesurf.obj gdalmatching.obj \
gdaltransformgeolocs.obj
default: $(OBJ)
clean:
-del *.obj

View file

@ -0,0 +1,761 @@
/******************************************************************************
* $Id: polygonize.cpp 28826 2015-03-30 17:51:14Z rouault $
* Project: GDAL
* Purpose: Raster to Polygon Converter
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2009-2011, 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_alg_priv.h"
#include "cpl_conv.h"
#include "cpl_string.h"
#include <vector>
CPL_CVSID("$Id: polygonize.cpp 28826 2015-03-30 17:51:14Z rouault $");
#ifdef OGR_ENABLED
/************************************************************************/
/* ==================================================================== */
/* RPolygon */
/* */
/* This is a helper class to hold polygons while they are being */
/* formed in memory, and to provide services to coalesce a much */
/* of edge sections into complete rings. */
/* ==================================================================== */
/************************************************************************/
class RPolygon {
public:
RPolygon( int nValue ) { nPolyValue = nValue; nLastLineUpdated = -1; }
int nPolyValue;
int nLastLineUpdated;
std::vector< std::vector<int> > aanXY;
void AddSegment( int x1, int y1, int x2, int y2 );
void Dump();
void Coalesce();
void Merge( int iBaseString, int iSrcString, int iDirection );
};
/************************************************************************/
/* Dump() */
/************************************************************************/
void RPolygon::Dump()
{
size_t iString;
printf( "RPolygon: Value=%d, LastLineUpdated=%d\n",
nPolyValue, nLastLineUpdated );
for( iString = 0; iString < aanXY.size(); iString++ )
{
std::vector<int> &anString = aanXY[iString];
size_t iVert;
printf( " String %d:\n", (int) iString );
for( iVert = 0; iVert < anString.size(); iVert += 2 )
{
printf( " (%d,%d)\n", anString[iVert], anString[iVert+1] );
}
}
}
/************************************************************************/
/* Coalesce() */
/************************************************************************/
void RPolygon::Coalesce()
{
size_t iBaseString;
/* -------------------------------------------------------------------- */
/* Iterate over loops starting from the first, trying to merge */
/* other segments into them. */
/* -------------------------------------------------------------------- */
for( iBaseString = 0; iBaseString < aanXY.size(); iBaseString++ )
{
std::vector<int> &anBase = aanXY[iBaseString];
int bMergeHappened = TRUE;
/* -------------------------------------------------------------------- */
/* Keep trying to merge the following strings into our target */
/* "base" string till we have tried them all once without any */
/* mergers. */
/* -------------------------------------------------------------------- */
while( bMergeHappened )
{
size_t iString;
bMergeHappened = FALSE;
/* -------------------------------------------------------------------- */
/* Loop over the following strings, trying to find one we can */
/* merge onto the end of our base string. */
/* -------------------------------------------------------------------- */
for( iString = iBaseString+1;
iString < aanXY.size();
iString++ )
{
std::vector<int> &anString = aanXY[iString];
if( anBase[anBase.size()-2] == anString[0]
&& anBase[anBase.size()-1] == anString[1] )
{
Merge( iBaseString, iString, 1 );
bMergeHappened = TRUE;
}
else if( anBase[anBase.size()-2] == anString[anString.size()-2]
&& anBase[anBase.size()-1] == anString[anString.size()-1] )
{
Merge( iBaseString, iString, -1 );
bMergeHappened = TRUE;
}
}
}
/* At this point our loop *should* be closed! */
CPLAssert( anBase[0] == anBase[anBase.size()-2]
&& anBase[1] == anBase[anBase.size()-1] );
}
}
/************************************************************************/
/* Merge() */
/************************************************************************/
void RPolygon::Merge( int iBaseString, int iSrcString, int iDirection )
{
std::vector<int> &anBase = aanXY[iBaseString];
std::vector<int> &anString = aanXY[iSrcString];
int iStart, iEnd, i;
if( iDirection == 1 )
{
iStart = 1;
iEnd = anString.size() / 2;
}
else
{
iStart = anString.size() / 2 - 2;
iEnd = -1;
}
for( i = iStart; i != iEnd; i += iDirection )
{
anBase.push_back( anString[i*2+0] );
anBase.push_back( anString[i*2+1] );
}
if( iSrcString < ((int) aanXY.size())-1 )
aanXY[iSrcString] = aanXY[aanXY.size()-1];
size_t nSize = aanXY.size();
aanXY.resize(nSize-1);
}
/************************************************************************/
/* AddSegment() */
/************************************************************************/
void RPolygon::AddSegment( int x1, int y1, int x2, int y2 )
{
nLastLineUpdated = MAX(y1, y2);
/* -------------------------------------------------------------------- */
/* Is there an existing string ending with this? */
/* -------------------------------------------------------------------- */
size_t iString;
for( iString = 0; iString < aanXY.size(); iString++ )
{
std::vector<int> &anString = aanXY[iString];
size_t nSSize = anString.size();
if( anString[nSSize-2] == x1
&& anString[nSSize-1] == y1 )
{
int nTemp;
nTemp = x2;
x2 = x1;
x1 = nTemp;
nTemp = y2;
y2 = y1;
y1 = nTemp;
}
if( anString[nSSize-2] == x2
&& anString[nSSize-1] == y2 )
{
// We are going to add a segment, but should we just extend
// an existing segment already going in the right direction?
int nLastLen = MAX(ABS(anString[nSSize-4]-anString[nSSize-2]),
ABS(anString[nSSize-3]-anString[nSSize-1]));
if( nSSize >= 4
&& (anString[nSSize-4] - anString[nSSize-2]
== (anString[nSSize-2] - x1)*nLastLen)
&& (anString[nSSize-3] - anString[nSSize-1]
== (anString[nSSize-1] - y1)*nLastLen) )
{
anString.pop_back();
anString.pop_back();
}
anString.push_back( x1 );
anString.push_back( y1 );
return;
}
}
/* -------------------------------------------------------------------- */
/* Create a new string. */
/* -------------------------------------------------------------------- */
size_t nSize = aanXY.size();
aanXY.resize(nSize + 1);
std::vector<int> &anString = aanXY[nSize];
anString.push_back( x1 );
anString.push_back( y1 );
anString.push_back( x2 );
anString.push_back( y2 );
return;
}
/************************************************************************/
/* ==================================================================== */
/* End of RPolygon */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* AddEdges() */
/* */
/* Examine one pixel and compare to its neighbour above */
/* (previous) and right. If they are different polygon ids */
/* then add the pixel edge to this polygon and the one on the */
/* other side of the edge. */
/************************************************************************/
static void AddEdges( GInt32 *panThisLineId, GInt32 *panLastLineId,
GInt32 *panPolyIdMap, GInt32 *panPolyValue,
RPolygon **papoPoly, int iX, int iY )
{
int nThisId = panThisLineId[iX];
int nRightId = panThisLineId[iX+1];
int nPreviousId = panLastLineId[iX];
int iXReal = iX - 1;
if( nThisId != -1 )
nThisId = panPolyIdMap[nThisId];
if( nRightId != -1 )
nRightId = panPolyIdMap[nRightId];
if( nPreviousId != -1 )
nPreviousId = panPolyIdMap[nPreviousId];
if( nThisId != nPreviousId )
{
if( nThisId != -1 )
{
if( papoPoly[nThisId] == NULL )
papoPoly[nThisId] = new RPolygon( panPolyValue[nThisId] );
papoPoly[nThisId]->AddSegment( iXReal, iY, iXReal+1, iY );
}
if( nPreviousId != -1 )
{
if( papoPoly[nPreviousId] == NULL )
papoPoly[nPreviousId] = new RPolygon(panPolyValue[nPreviousId]);
papoPoly[nPreviousId]->AddSegment( iXReal, iY, iXReal+1, iY );
}
}
if( nThisId != nRightId )
{
if( nThisId != -1 )
{
if( papoPoly[nThisId] == NULL )
papoPoly[nThisId] = new RPolygon(panPolyValue[nThisId]);
papoPoly[nThisId]->AddSegment( iXReal+1, iY, iXReal+1, iY+1 );
}
if( nRightId != -1 )
{
if( papoPoly[nRightId] == NULL )
papoPoly[nRightId] = new RPolygon(panPolyValue[nRightId]);
papoPoly[nRightId]->AddSegment( iXReal+1, iY, iXReal+1, iY+1 );
}
}
}
/************************************************************************/
/* EmitPolygonToLayer() */
/************************************************************************/
static CPLErr
EmitPolygonToLayer( OGRLayerH hOutLayer, int iPixValField,
RPolygon *poRPoly, double *padfGeoTransform )
{
OGRFeatureH hFeat;
OGRGeometryH hPolygon;
/* -------------------------------------------------------------------- */
/* Turn bits of lines into coherent rings. */
/* -------------------------------------------------------------------- */
poRPoly->Coalesce();
/* -------------------------------------------------------------------- */
/* Create the polygon geometry. */
/* -------------------------------------------------------------------- */
size_t iString;
hPolygon = OGR_G_CreateGeometry( wkbPolygon );
for( iString = 0; iString < poRPoly->aanXY.size(); iString++ )
{
std::vector<int> &anString = poRPoly->aanXY[iString];
OGRGeometryH hRing = OGR_G_CreateGeometry( wkbLinearRing );
int iVert;
// we go last to first to ensure the linestring is allocated to
// the proper size on the first try.
for( iVert = anString.size()/2 - 1; iVert >= 0; iVert-- )
{
double dfX, dfY;
int nPixelX, nPixelY;
nPixelX = anString[iVert*2];
nPixelY = anString[iVert*2+1];
dfX = padfGeoTransform[0]
+ nPixelX * padfGeoTransform[1]
+ nPixelY * padfGeoTransform[2];
dfY = padfGeoTransform[3]
+ nPixelX * padfGeoTransform[4]
+ nPixelY * padfGeoTransform[5];
OGR_G_SetPoint_2D( hRing, iVert, dfX, dfY );
}
OGR_G_AddGeometryDirectly( hPolygon, hRing );
}
/* -------------------------------------------------------------------- */
/* Create the feature object. */
/* -------------------------------------------------------------------- */
hFeat = OGR_F_Create( OGR_L_GetLayerDefn( hOutLayer ) );
OGR_F_SetGeometryDirectly( hFeat, hPolygon );
if( iPixValField >= 0 )
OGR_F_SetFieldInteger( hFeat, iPixValField, poRPoly->nPolyValue );
/* -------------------------------------------------------------------- */
/* Write the to the layer. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
if( OGR_L_CreateFeature( hOutLayer, hFeat ) != OGRERR_NONE )
eErr = CE_Failure;
OGR_F_Destroy( hFeat );
return eErr;
}
/************************************************************************/
/* GPMaskImageData() */
/* */
/* Mask out image pixels to a special nodata value if the mask */
/* band is zero. */
/************************************************************************/
static CPLErr
GPMaskImageData( GDALRasterBandH hMaskBand, GByte* pabyMaskLine, int iY, int nXSize,
GInt32 *panImageLine )
{
CPLErr eErr;
eErr = GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr == CE_None )
{
int i;
for( i = 0; i < nXSize; i++ )
{
if( pabyMaskLine[i] == 0 )
panImageLine[i] = GP_NODATA_MARKER;
}
}
return eErr;
}
#endif // OGR_ENABLED
/************************************************************************/
/* GDALPolygonize() */
/************************************************************************/
/**
* Create polygon coverage from raster data.
*
* This function creates vector polygons for all connected regions of pixels in
* the raster sharing a common pixel value. Optionally each polygon may be
* labelled with the pixel value in an attribute. Optionally a mask band
* can be provided to determine which pixels are eligible for processing.
*
* Note that currently the source pixel band values are read into a
* signed 32bit integer buffer (Int32), so floating point or complex
* bands will be implicitly truncated before processing. If you want to use a
* version using 32bit float buffers, see GDALFPolygonize() at fpolygonize.cpp.
*
* Polygon features will be created on the output layer, with polygon
* geometries representing the polygons. The polygon geometries will be
* in the georeferenced coordinate system of the image (based on the
* geotransform of the source dataset). It is acceptable for the output
* layer to already have features. Note that GDALPolygonize() does not
* set the coordinate system on the output layer. Application code should
* do this when the layer is created, presumably matching the raster
* coordinate system.
*
* The algorithm used attempts to minimize memory use so that very large
* rasters can be processed. However, if the raster has many polygons
* or very large/complex polygons, the memory use for holding polygon
* enumerations and active polygon geometries may grow to be quite large.
*
* The algorithm will generally produce very dense polygon geometries, with
* edges that follow exactly on pixel boundaries for all non-interior pixels.
* For non-thematic raster data (such as satellite images) the result will
* essentially be one small polygon per pixel, and memory and output layer
* sizes will be substantial. The algorithm is primarily intended for
* relatively simple thematic imagery, masks, and classification results.
*
* @param hSrcBand the source raster band to be processed.
* @param hMaskBand an optional mask band. All pixels in the mask band with a
* value other than zero will be considered suitable for collection as
* polygons.
* @param hOutLayer the vector feature layer to which the polygons should
* be written.
* @param iPixValField the attribute field index indicating the feature
* attribute into which the pixel value of the polygon should be written.
* @param papszOptions a name/value list of additional options
* <dl>
* <dt>"8CONNECTED":</dt> May be set to "8" to use 8 connectedness.
* Otherwise 4 connectedness will be applied to the algorithm
* </dl>
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
*
* @return CE_None on success or CE_Failure on a failure.
*/
CPLErr CPL_STDCALL
GDALPolygonize( GDALRasterBandH hSrcBand,
GDALRasterBandH hMaskBand,
OGRLayerH hOutLayer, int iPixValField,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
#ifndef OGR_ENABLED
CPLError(CE_Failure, CPLE_NotSupported, "GDALPolygonize() unimplemented in a non OGR build");
return CE_Failure;
#else
VALIDATE_POINTER1( hSrcBand, "GDALPolygonize", CE_Failure );
VALIDATE_POINTER1( hOutLayer, "GDALPolygonize", CE_Failure );
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
int nConnectedness = CSLFetchNameValue( papszOptions, "8CONNECTED" ) ? 8 : 4;
/* -------------------------------------------------------------------- */
/* Confirm our output layer will support feature creation. */
/* -------------------------------------------------------------------- */
if( !OGR_L_TestCapability( hOutLayer, OLCSequentialWrite ) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Output feature layer does not appear to support creation\n"
"of features in GDALPolygonize()." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Allocate working buffers. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
int nXSize = GDALGetRasterBandXSize( hSrcBand );
int nYSize = GDALGetRasterBandYSize( hSrcBand );
GInt32 *panLastLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2);
GInt32 *panThisLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2);
GInt32 *panLastLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2);
GInt32 *panThisLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2);
GByte *pabyMaskLine = (hMaskBand != NULL) ? (GByte *) VSIMalloc(nXSize) : NULL;
if (panLastLineVal == NULL || panThisLineVal == NULL ||
panLastLineId == NULL || panThisLineId == NULL ||
(hMaskBand != NULL && pabyMaskLine == NULL))
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate enough memory for temporary buffers");
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( panThisLineVal );
CPLFree( panLastLineVal );
CPLFree( pabyMaskLine );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Get the geotransform, if there is one, so we can convert the */
/* vectors into georeferenced coordinates. */
/* -------------------------------------------------------------------- */
GDALDatasetH hSrcDS = GDALGetBandDataset( hSrcBand );
double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
if( hSrcDS )
GDALGetGeoTransform( hSrcDS, adfGeoTransform );
/* -------------------------------------------------------------------- */
/* The first pass over the raster is only used to build up the */
/* polygon id map so we will know in advance what polygons are */
/* what on the second pass. */
/* -------------------------------------------------------------------- */
int iY;
GDALRasterPolygonEnumerator oFirstEnum(nConnectedness);
for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
eErr = GDALRasterIO(
hSrcBand,
GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
if( iY == 0 )
oFirstEnum.ProcessLine(
NULL, panThisLineVal, NULL, panThisLineId, nXSize );
else
oFirstEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
// swap lines
GInt32 *panTmp = panLastLineVal;
panLastLineVal = panThisLineVal;
panThisLineVal = panTmp;
panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.10 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/* -------------------------------------------------------------------- */
oFirstEnum.CompleteMerges();
/* -------------------------------------------------------------------- */
/* Initialize ids to -1 to serve as a nodata value for the */
/* previous line, and past the beginning and end of the */
/* scanlines. */
/* -------------------------------------------------------------------- */
int iX;
panThisLineId[0] = -1;
panThisLineId[nXSize+1] = -1;
for( iX = 0; iX < nXSize+2; iX++ )
panLastLineId[iX] = -1;
/* -------------------------------------------------------------------- */
/* We will use a new enumerator for the second pass primariliy */
/* so we can preserve the first pass map. */
/* -------------------------------------------------------------------- */
GDALRasterPolygonEnumerator oSecondEnum(nConnectedness);
RPolygon **papoPoly = (RPolygon **)
CPLCalloc(sizeof(RPolygon*),oFirstEnum.nNextPolygonId);
/* ==================================================================== */
/* Second pass during which we will actually collect polygon */
/* edges as geometries. */
/* ==================================================================== */
for( iY = 0; eErr == CE_None && iY < nYSize+1; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read the image data. */
/* -------------------------------------------------------------------- */
if( iY < nYSize )
{
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr == CE_None && hMaskBand != NULL )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
}
if( eErr != CE_None )
continue;
/* -------------------------------------------------------------------- */
/* Determine what polygon the various pixels belong to (redoing */
/* the same thing done in the first pass above). */
/* -------------------------------------------------------------------- */
if( iY == nYSize )
{
for( iX = 0; iX < nXSize+2; iX++ )
panThisLineId[iX] = -1;
}
else if( iY == 0 )
oSecondEnum.ProcessLine(
NULL, panThisLineVal, NULL, panThisLineId+1, nXSize );
else
oSecondEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId+1, panThisLineId+1,
nXSize );
/* -------------------------------------------------------------------- */
/* Add polygon edges to our polygon list for the pixel */
/* boundaries within and above this line. */
/* -------------------------------------------------------------------- */
for( iX = 0; iX < nXSize+1; iX++ )
{
AddEdges( panThisLineId, panLastLineId,
oFirstEnum.panPolyIdMap, oFirstEnum.panPolyValue,
papoPoly, iX, iY );
}
/* -------------------------------------------------------------------- */
/* Periodically we scan out polygons and write out those that */
/* haven't been added to on the last line as we can be sure */
/* they are complete. */
/* -------------------------------------------------------------------- */
if( iY % 8 == 7 )
{
for( iX = 0;
eErr == CE_None && iX < oSecondEnum.nNextPolygonId;
iX++ )
{
if( papoPoly[iX] && papoPoly[iX]->nLastLineUpdated < iY-1 )
{
eErr =
EmitPolygonToLayer( hOutLayer, iPixValField,
papoPoly[iX], adfGeoTransform );
delete papoPoly[iX];
papoPoly[iX] = NULL;
}
}
}
/* -------------------------------------------------------------------- */
/* Swap pixel value, and polygon id lines to be ready for the */
/* next line. */
/* -------------------------------------------------------------------- */
GInt32 *panTmp = panLastLineVal;
panLastLineVal = panThisLineVal;
panThisLineVal = panTmp;
panTmp = panThisLineId;
panThisLineId = panLastLineId;
panLastLineId = panTmp;
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.10 + 0.90 * ((iY+1) / (double) nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Make a cleanup pass for all unflushed polygons. */
/* -------------------------------------------------------------------- */
for( iX = 0; eErr == CE_None && iX < oSecondEnum.nNextPolygonId; iX++ )
{
if( papoPoly[iX] )
{
eErr =
EmitPolygonToLayer( hOutLayer, iPixValField,
papoPoly[iX], adfGeoTransform );
delete papoPoly[iX];
papoPoly[iX] = NULL;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( panThisLineVal );
CPLFree( panLastLineVal );
CPLFree( pabyMaskLine );
CPLFree( papoPoly );
return eErr;
#endif // OGR_ENABLED
}

View file

@ -0,0 +1,886 @@
/******************************************************************************
* $Id: rasterfill.cpp 28342 2015-01-22 12:31:07Z rouault $
*
* Project: GDAL
* Purpose: Interpolate in nodata areas.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2015, Sean Gillies <sean@mapbox.com>
*
* 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_alg.h"
#include "cpl_conv.h"
#include "cpl_string.h"
CPL_CVSID("$Id: rasterfill.cpp 28342 2015-01-22 12:31:07Z rouault $");
/************************************************************************/
/* GDALFilterLine() */
/* */
/* Apply 3x3 filtering one one scanline with masking for which */
/* pixels are to be interpolated (ThisFMask) and which window */
/* pixels are valid to include in the interpolation (TMask). */
/************************************************************************/
static void
GDALFilterLine( float *pafLastLine, float *pafThisLine, float *pafNextLine,
float *pafOutLine,
GByte *pabyLastTMask, GByte *pabyThisTMask, GByte*pabyNextTMask,
GByte *pabyThisFMask, int nXSize )
{
int iX;
for( iX = 0; iX < nXSize; iX++ )
{
if( !pabyThisFMask[iX] )
{
pafOutLine[iX] = pafThisLine[iX];
continue;
}
CPLAssert( pabyThisTMask[iX] );
double dfValSum = 0.0;
double dfWeightSum = 0.0;
// Previous line
if( pafLastLine != NULL )
{
if( iX > 0 && pabyLastTMask[iX-1] )
{
dfValSum += pafLastLine[iX-1];
dfWeightSum += 1.0;
}
if( pabyLastTMask[iX] )
{
dfValSum += pafLastLine[iX];
dfWeightSum += 1.0;
}
if( iX < nXSize-1 && pabyLastTMask[iX+1] )
{
dfValSum += pafLastLine[iX+1];
dfWeightSum += 1.0;
}
}
// Current Line
if( iX > 0 && pabyThisTMask[iX-1] )
{
dfValSum += pafThisLine[iX-1];
dfWeightSum += 1.0;
}
if( pabyThisTMask[iX] )
{
dfValSum += pafThisLine[iX];
dfWeightSum += 1.0;
}
if( iX < nXSize-1 && pabyThisTMask[iX+1] )
{
dfValSum += pafThisLine[iX+1];
dfWeightSum += 1.0;
}
// Next line
if( pafNextLine != NULL )
{
if( iX > 0 && pabyNextTMask[iX-1] )
{
dfValSum += pafNextLine[iX-1];
dfWeightSum += 1.0;
}
if( pabyNextTMask[iX] )
{
dfValSum += pafNextLine[iX];
dfWeightSum += 1.0;
}
if( iX < nXSize-1 && pabyNextTMask[iX+1] )
{
dfValSum += pafNextLine[iX+1];
dfWeightSum += 1.0;
}
}
pafOutLine[iX] = (float) (dfValSum / dfWeightSum);
}
}
/************************************************************************/
/* GDALMultiFilter() */
/* */
/* Apply multiple iterations of a 3x3 smoothing filter over a */
/* band with masking controlling what pixels should be */
/* filtered (FiltMaskBand non zero) and which pixels can be */
/* considered valid contributors to the filter */
/* (TargetMaskBand non zero). */
/* */
/* This implementation attempts to apply many iterations in */
/* one IO pass by managing the filtering over a rolling buffer */
/* of nIternations+2 scanlines. While possibly clever this */
/* makes the algorithm implementation largely */
/* incomprehensible. */
/************************************************************************/
static CPLErr
GDALMultiFilter( GDALRasterBandH hTargetBand,
GDALRasterBandH hTargetMaskBand,
GDALRasterBandH hFiltMaskBand,
int nIterations,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
float *paf3PassLineBuf;
GByte *pabyTMaskBuf;
GByte *pabyFMaskBuf;
float *pafThisPass, *pafLastPass, *pafSLastPass;
int nBufLines = nIterations + 2;
int iPassCounter = 0;
int nNewLine; // the line being loaded this time (zero based scanline)
int nXSize = GDALGetRasterBandXSize( hTargetBand );
int nYSize = GDALGetRasterBandYSize( hTargetBand );
CPLErr eErr = CE_None;
/* -------------------------------------------------------------------- */
/* Report starting progress value. */
/* -------------------------------------------------------------------- */
if( !pfnProgress( 0.0, "Smoothing Filter...", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Allocate rotating buffers. */
/* -------------------------------------------------------------------- */
pabyTMaskBuf = (GByte *) VSIMalloc2(nXSize, nBufLines);
pabyFMaskBuf = (GByte *) VSIMalloc2(nXSize, nBufLines);
paf3PassLineBuf = (float *) VSIMalloc3(nXSize, nBufLines, 3 * sizeof(float));
if (pabyTMaskBuf == NULL || pabyFMaskBuf == NULL || paf3PassLineBuf == NULL)
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate enough memory for temporary buffers");
eErr = CE_Failure;
goto end;
}
/* -------------------------------------------------------------------- */
/* Process rotating buffers. */
/* -------------------------------------------------------------------- */
for( nNewLine = 0;
eErr == CE_None && nNewLine < nYSize+nIterations;
nNewLine++ )
{
/* -------------------------------------------------------------------- */
/* Rotate pass buffers. */
/* -------------------------------------------------------------------- */
iPassCounter = (iPassCounter + 1) % 3;
pafSLastPass = paf3PassLineBuf
+ ((iPassCounter+0)%3) * nXSize*nBufLines;
pafLastPass = paf3PassLineBuf
+ ((iPassCounter+1)%3) * nXSize*nBufLines;
pafThisPass = paf3PassLineBuf
+ ((iPassCounter+2)%3) * nXSize*nBufLines;
/* -------------------------------------------------------------------- */
/* Where does the new line go in the rotating buffer? */
/* -------------------------------------------------------------------- */
int iBufOffset = nNewLine % nBufLines;
/* -------------------------------------------------------------------- */
/* Read the new data line if it is't off the bottom of the */
/* image. */
/* -------------------------------------------------------------------- */
if( nNewLine < nYSize )
{
eErr =
GDALRasterIO( hTargetMaskBand, GF_Read,
0, nNewLine, nXSize, 1,
pabyTMaskBuf + nXSize * iBufOffset, nXSize, 1,
GDT_Byte, 0, 0 );
if( eErr != CE_None )
break;
eErr =
GDALRasterIO( hFiltMaskBand, GF_Read,
0, nNewLine, nXSize, 1,
pabyFMaskBuf + nXSize * iBufOffset, nXSize, 1,
GDT_Byte, 0, 0 );
if( eErr != CE_None )
break;
eErr =
GDALRasterIO( hTargetBand, GF_Read,
0, nNewLine, nXSize, 1,
pafThisPass + nXSize * iBufOffset, nXSize, 1,
GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
}
/* -------------------------------------------------------------------- */
/* Loop over the loaded data, applying the filter to all loaded */
/* lines with neighbours. */
/* -------------------------------------------------------------------- */
int iFLine;
for( iFLine = nNewLine-1;
eErr == CE_None && iFLine >= nNewLine-nIterations;
iFLine-- )
{
int iLastOffset, iThisOffset, iNextOffset;
iLastOffset = (iFLine-1) % nBufLines;
iThisOffset = (iFLine ) % nBufLines;
iNextOffset = (iFLine+1) % nBufLines;
// default to preserving the old value.
if( iFLine >= 0 )
memcpy( pafThisPass + iThisOffset * nXSize,
pafLastPass + iThisOffset * nXSize,
sizeof(float) * nXSize );
// currently this skips the first and last line. Eventually
// we will enable these too. TODO
if( iFLine < 1 || iFLine >= nYSize-1 )
{
continue;
}
GDALFilterLine(
pafSLastPass + iLastOffset * nXSize,
pafLastPass + iThisOffset * nXSize,
pafThisPass + iNextOffset * nXSize,
pafThisPass + iThisOffset * nXSize,
pabyTMaskBuf + iLastOffset * nXSize,
pabyTMaskBuf + iThisOffset * nXSize,
pabyTMaskBuf + iNextOffset * nXSize,
pabyFMaskBuf + iThisOffset * nXSize,
nXSize );
}
/* -------------------------------------------------------------------- */
/* Write out the top data line that will be rolling out of our */
/* buffer. */
/* -------------------------------------------------------------------- */
int iLineToSave = nNewLine - nIterations;
if( iLineToSave >= 0 && eErr == CE_None )
{
iBufOffset = iLineToSave % nBufLines;
eErr =
GDALRasterIO( hTargetBand, GF_Write,
0, iLineToSave, nXSize, 1,
pafThisPass + nXSize * iBufOffset, nXSize, 1,
GDT_Float32, 0, 0 );
}
/* -------------------------------------------------------------------- */
/* Report progress. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( (nNewLine+1) / (double) (nYSize+nIterations),
"Smoothing Filter...", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
end:
CPLFree( pabyTMaskBuf );
CPLFree( pabyFMaskBuf );
CPLFree( paf3PassLineBuf );
return eErr;
}
/************************************************************************/
/* QUAD_CHECK() */
/* */
/* macro for checking whether a point is nearer than the */
/* existing closest point. */
/************************************************************************/
#define QUAD_CHECK(quad_dist, quad_value, \
target_x, target_y, origin_x, origin_y, target_value ) \
\
if( quad_value != nNoDataVal ) \
{ \
double dfDx = (double)target_x - (double)origin_x; \
double dfDy = (double)target_y - (double)origin_y; \
double dfDistSq = dfDx * dfDx + dfDy * dfDy; \
\
if( dfDistSq < quad_dist*quad_dist ) \
{ \
CPLAssert( dfDistSq > 0.0 ); \
quad_dist = sqrt(dfDistSq); \
quad_value = target_value; \
} \
}
/************************************************************************/
/* GDALFillNodata() */
/************************************************************************/
/**
* Fill selected raster regions by interpolation from the edges.
*
* This algorithm will interpolate values for all designated
* nodata pixels (marked by zeros in hMaskBand). For each pixel
* a four direction conic search is done to find values to interpolate
* from (using inverse distance weighting). Once all values are
* interpolated, zero or more smoothing iterations (3x3 average
* filters on interpolated pixels) are applied to smooth out
* artifacts.
*
* This algorithm is generally suitable for interpolating missing
* regions of fairly continuously varying rasters (such as elevation
* models for instance). It is also suitable for filling small holes
* and cracks in more irregularly varying images (like airphotos). It
* is generally not so great for interpolating a raster from sparse
* point data - see the algorithms defined in gdal_grid.h for that case.
*
* @param hTargetBand the raster band to be modified in place.
* @param hMaskBand a mask band indicating pixels to be interpolated (zero valued
* @param dfMaxSearchDist the maximum number of pixels to search in all
* directions to find values to interpolate from.
* @param bDeprecatedOption unused argument, should be zero.
* @param nSmoothingIterations the number of 3x3 smoothing filter passes to
* run (0 or more).
* @param papszOptions additional name=value options in a string list (the
* temporary file driver can be specified like TEMP_FILE_DRIVER=MEM).
* @param pfnProgress the progress function to report completion.
* @param pProgressArg callback data for progress function.
*
* @return CE_None on success or CE_Failure if something goes wrong.
*/
CPLErr CPL_STDCALL
GDALFillNodata( GDALRasterBandH hTargetBand,
GDALRasterBandH hMaskBand,
double dfMaxSearchDist,
int bDeprecatedOption,
int nSmoothingIterations,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
VALIDATE_POINTER1( hTargetBand, "GDALFillNodata", CE_Failure );
int nXSize = GDALGetRasterBandXSize( hTargetBand );
int nYSize = GDALGetRasterBandYSize( hTargetBand );
CPLErr eErr = CE_None;
// Special "x" pixel values identifying pixels as special.
GUInt32 nNoDataVal;
GDALDataType eType;
if( dfMaxSearchDist == 0.0 )
dfMaxSearchDist = MAX(nXSize,nYSize) + 1;
int nMaxSearchDist = (int) floor(dfMaxSearchDist);
if( nXSize > 65533 || nYSize > 65533 )
{
eType = GDT_UInt32;
nNoDataVal = 4000002;
}
else
{
eType = GDT_UInt16;
nNoDataVal = 65535;
}
if( hMaskBand == NULL )
hMaskBand = GDALGetMaskBand( hTargetBand );
/* If there are smoothing iterations, reserve 10% of the progress for them */
double dfProgressRatio = (nSmoothingIterations > 0) ? 0.9 : 1.0;
/* -------------------------------------------------------------------- */
/* Initialize progress counter. */
/* -------------------------------------------------------------------- */
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
if( !pfnProgress( 0.0, "Filling...", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Determine format driver for temp work files. */
/* -------------------------------------------------------------------- */
CPLString osTmpFileDriver = CSLFetchNameValueDef(
papszOptions, "TEMP_FILE_DRIVER", "GTiff");
GDALDriverH hDriver = GDALGetDriverByName((const char *) osTmpFileDriver);
if (hDriver == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Given driver is not registered");
return CE_Failure;
}
if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, NULL) == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Given driver is incapable of creating temp work files");
return CE_Failure;
}
char **papszWorkFileOptions = NULL;
if (osTmpFileDriver == "GTiff") {
papszWorkFileOptions = CSLSetNameValue(
papszWorkFileOptions, "COMPRESS", "LZW");
papszWorkFileOptions = CSLSetNameValue(
papszWorkFileOptions, "BIGTIFF", "IF_SAFER");
}
/* -------------------------------------------------------------------- */
/* Create a work file to hold the Y "last value" indices. */
/* -------------------------------------------------------------------- */
GDALDatasetH hYDS;
GDALRasterBandH hYBand;
CPLString osTmpFile = CPLGenerateTempFilename("");
CPLString osYTmpFile = osTmpFile + "fill_y_work.tif";
hYDS = GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1,
eType, (char **) papszWorkFileOptions );
if ( hYDS == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Could not create Y index work file. Check driver capabilities.");
return CE_Failure;
}
hYBand = GDALGetRasterBand( hYDS, 1 );
/* -------------------------------------------------------------------- */
/* Create a work file to hold the pixel value associated with */
/* the "last xy value" pixel. */
/* -------------------------------------------------------------------- */
GDALDatasetH hValDS;
GDALRasterBandH hValBand;
CPLString osValTmpFile = osTmpFile + "fill_val_work.tif";
hValDS = GDALCreate( hDriver, osValTmpFile, nXSize, nYSize, 1,
GDALGetRasterDataType( hTargetBand ),
(char **) papszWorkFileOptions );
if ( hValDS == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Could not create XY value work file. Check driver capabilities.");
return CE_Failure;
}
hValBand = GDALGetRasterBand( hValDS, 1 );
/* -------------------------------------------------------------------- */
/* Create a mask file to make it clear what pixels can be filtered */
/* on the filtering pass. */
/* -------------------------------------------------------------------- */
GDALDatasetH hFiltMaskDS;
GDALRasterBandH hFiltMaskBand;
CPLString osFiltMaskTmpFile = osTmpFile + "fill_filtmask_work.tif";
hFiltMaskDS =
GDALCreate( hDriver, osFiltMaskTmpFile, nXSize, nYSize, 1,
GDT_Byte, (char **) papszWorkFileOptions );
if ( hFiltMaskDS == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Could not create mask work file. Check driver capabilities.");
return CE_Failure;
}
hFiltMaskBand = GDALGetRasterBand( hFiltMaskDS, 1 );
/* -------------------------------------------------------------------- */
/* Allocate buffers for last scanline and this scanline. */
/* -------------------------------------------------------------------- */
GUInt32 *panLastY, *panThisY, *panTopDownY;
float *pafLastValue, *pafThisValue, *pafScanline, *pafTopDownValue;
GByte *pabyMask, *pabyFiltMask;
int iX;
int iY;
panLastY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
panThisY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
panTopDownY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
pafLastValue = (float *) VSICalloc(nXSize,sizeof(float));
pafThisValue = (float *) VSICalloc(nXSize,sizeof(float));
pafTopDownValue = (float *) VSICalloc(nXSize,sizeof(float));
pafScanline = (float *) VSICalloc(nXSize,sizeof(float));
pabyMask = (GByte *) VSICalloc(nXSize,1);
pabyFiltMask = (GByte *) VSICalloc(nXSize,1);
if (panLastY == NULL || panThisY == NULL || panTopDownY == NULL ||
pafLastValue == NULL || pafThisValue == NULL || pafTopDownValue == NULL ||
pafScanline == NULL || pabyMask == NULL || pabyFiltMask == NULL)
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"Could not allocate enough memory for temporary buffers");
eErr = CE_Failure;
goto end;
}
for( iX = 0; iX < nXSize; iX++ )
{
panLastY[iX] = nNoDataVal;
}
/* ==================================================================== */
/* Make first pass from top to bottom collecting the "last */
/* known value" for each column and writing it out to the work */
/* files. */
/* ==================================================================== */
for( iY = 0; iY < nYSize && eErr == CE_None; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read data and mask for this line. */
/* -------------------------------------------------------------------- */
eErr =
GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
pabyMask, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr != CE_None )
break;
eErr =
GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1,
pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
/* -------------------------------------------------------------------- */
/* Figure out the most recent pixel for each column. */
/* -------------------------------------------------------------------- */
for( iX = 0; iX < nXSize; iX++ )
{
if( pabyMask[iX] )
{
pafThisValue[iX] = pafScanline[iX];
panThisY[iX] = iY;
}
else if( iY <= dfMaxSearchDist + panLastY[iX] )
{
pafThisValue[iX] = pafLastValue[iX];
panThisY[iX] = panLastY[iX];
}
else
{
panThisY[iX] = nNoDataVal;
}
}
/* -------------------------------------------------------------------- */
/* Write out best index/value to working files. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hYBand, GF_Write, 0, iY, nXSize, 1,
panThisY, nXSize, 1, GDT_UInt32, 0, 0 );
if( eErr != CE_None )
break;
eErr = GDALRasterIO( hValBand, GF_Write, 0, iY, nXSize, 1,
pafThisValue, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
/* -------------------------------------------------------------------- */
/* Flip this/last buffers. */
/* -------------------------------------------------------------------- */
{
float *pafTmp = pafThisValue;
pafThisValue = pafLastValue;
pafLastValue = pafTmp;
GUInt32 *panTmp = panThisY;
panThisY = panLastY;
panLastY = panTmp;
}
/* -------------------------------------------------------------------- */
/* report progress. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( dfProgressRatio * (0.5*(iY+1) / (double)nYSize),
"Filling...", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* ==================================================================== */
/* Now we will do collect similar this/last information from */
/* bottom to top and use it in combination with the top to */
/* bottom search info to interpolate. */
/* ==================================================================== */
for( iY = nYSize-1; iY >= 0 && eErr == CE_None; iY-- )
{
eErr =
GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
pabyMask, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr != CE_None )
break;
eErr =
GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1,
pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
/* -------------------------------------------------------------------- */
/* Figure out the most recent pixel for each column. */
/* -------------------------------------------------------------------- */
for( iX = 0; iX < nXSize; iX++ )
{
if( pabyMask[iX] )
{
pafThisValue[iX] = pafScanline[iX];
panThisY[iX] = iY;
}
else if( panLastY[iX] - iY <= dfMaxSearchDist )
{
pafThisValue[iX] = pafLastValue[iX];
panThisY[iX] = panLastY[iX];
}
else
{
panThisY[iX] = nNoDataVal;
}
}
/* -------------------------------------------------------------------- */
/* Load the last y and corresponding value from the top down pass. */
/* -------------------------------------------------------------------- */
eErr =
GDALRasterIO( hYBand, GF_Read, 0, iY, nXSize, 1,
panTopDownY, nXSize, 1, GDT_UInt32, 0, 0 );
if( eErr != CE_None )
break;
eErr =
GDALRasterIO( hValBand, GF_Read, 0, iY, nXSize, 1,
pafTopDownValue, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
/* -------------------------------------------------------------------- */
/* Attempt to interpolate any pixels that are nodata. */
/* -------------------------------------------------------------------- */
memset( pabyFiltMask, 0, nXSize );
for( iX = 0; iX < nXSize; iX++ )
{
int iStep, iQuad;
int nThisMaxSearchDist = nMaxSearchDist;
// If this was a valid target - no change.
if( pabyMask[iX] )
continue;
// Quadrants 0:topleft, 1:bottomleft, 2:topright, 3:bottomright
double adfQuadDist[4];
double adfQuadValue[4];
for( iQuad = 0; iQuad < 4; iQuad++ )
{
adfQuadDist[iQuad] = dfMaxSearchDist + 1.0;
adfQuadValue[iQuad] = 0.0;
}
// Step left and right by one pixel searching for the closest
// target value for each quadrant.
for( iStep = 0; iStep < nThisMaxSearchDist; iStep++ )
{
int iLeftX = MAX(0,iX - iStep);
int iRightX = MIN(nXSize-1,iX + iStep);
// top left includes current line
QUAD_CHECK(adfQuadDist[0],adfQuadValue[0],
iLeftX, panTopDownY[iLeftX], iX, iY,
pafTopDownValue[iLeftX] );
// bottom left
QUAD_CHECK(adfQuadDist[1],adfQuadValue[1],
iLeftX, panLastY[iLeftX], iX, iY,
pafLastValue[iLeftX] );
// top right and bottom right do no include center pixel.
if( iStep == 0 )
continue;
// top right includes current line
QUAD_CHECK(adfQuadDist[2],adfQuadValue[2],
iRightX, panTopDownY[iRightX], iX, iY,
pafTopDownValue[iRightX] );
// bottom right
QUAD_CHECK(adfQuadDist[3],adfQuadValue[3],
iRightX, panLastY[iRightX], iX, iY,
pafLastValue[iRightX] );
// every four steps, recompute maximum distance.
if( (iStep & 0x3) == 0 )
nThisMaxSearchDist = (int) floor(
MAX(MAX(adfQuadDist[0],adfQuadDist[1]),
MAX(adfQuadDist[2],adfQuadDist[3])) );
}
double dfWeightSum = 0.0;
double dfValueSum = 0.0;
for( iQuad = 0; iQuad < 4; iQuad++ )
{
if( adfQuadDist[iQuad] <= dfMaxSearchDist )
{
double dfWeight = 1.0 / adfQuadDist[iQuad];
dfWeightSum += dfWeight;
dfValueSum += adfQuadValue[iQuad] * dfWeight;
}
}
if( dfWeightSum > 0.0 )
{
pabyMask[iX] = 255;
pabyFiltMask[iX] = 255;
pafScanline[iX] = (float) (dfValueSum / dfWeightSum);
}
}
/* -------------------------------------------------------------------- */
/* Write out the updated data and mask information. */
/* -------------------------------------------------------------------- */
eErr =
GDALRasterIO( hTargetBand, GF_Write, 0, iY, nXSize, 1,
pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
eErr =
GDALRasterIO( hFiltMaskBand, GF_Write, 0, iY, nXSize, 1,
pabyFiltMask, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr != CE_None )
break;
/* -------------------------------------------------------------------- */
/* Flip this/last buffers. */
/* -------------------------------------------------------------------- */
{
float *pafTmp = pafThisValue;
pafThisValue = pafLastValue;
pafLastValue = pafTmp;
GUInt32 *panTmp = panThisY;
panThisY = panLastY;
panLastY = panTmp;
}
/* -------------------------------------------------------------------- */
/* report progress. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( dfProgressRatio*(0.5+0.5*(nYSize-iY) / (double)nYSize),
"Filling...", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* ==================================================================== */
/* Now we will do iterative average filters over the */
/* interpolated values to smooth things out and make linear */
/* artifacts less obvious. */
/* ==================================================================== */
if( eErr == CE_None && nSmoothingIterations > 0 )
{
// force masks to be to flushed and recomputed.
GDALFlushRasterCache( hMaskBand );
void *pScaledProgress;
pScaledProgress =
GDALCreateScaledProgress( dfProgressRatio, 1.0, pfnProgress, NULL );
eErr = GDALMultiFilter( hTargetBand, hMaskBand, hFiltMaskBand,
nSmoothingIterations,
GDALScaledProgress, pScaledProgress );
GDALDestroyScaledProgress( pScaledProgress );
}
/* -------------------------------------------------------------------- */
/* Close and clean up temporary files. Free working buffers */
/* -------------------------------------------------------------------- */
end:
CPLFree(panLastY);
CPLFree(panThisY);
CPLFree(panTopDownY);
CPLFree(pafLastValue);
CPLFree(pafThisValue);
CPLFree(pafTopDownValue);
CPLFree(pafScanline);
CPLFree(pabyMask);
CPLFree(pabyFiltMask);
GDALClose( hYDS );
GDALClose( hValDS );
GDALClose( hFiltMaskDS );
CSLDestroy(papszWorkFileOptions);
GDALDeleteDataset( hDriver, osYTmpFile );
GDALDeleteDataset( hDriver, osValTmpFile );
GDALDeleteDataset( hDriver, osFiltMaskTmpFile );
return eErr;
}

View file

@ -0,0 +1,812 @@
/******************************************************************************
* $Id: thinplatespline.cpp 27546 2014-07-22 22:40:02Z rouault $
*
* Project: GDAL Warp API
* Purpose: Implemenentation of 2D Thin Plate Spline transformer.
* Author: VIZRT Development Team.
*
* This code was provided by Gilad Ronnen (gro at visrt dot com) with
* permission to reuse under the following license.
*
******************************************************************************
* Copyright (c) 2004, VIZRT Inc.
* Copyright (c) 2008-2014, 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.
****************************************************************************/
#ifdef HAVE_ARMADILLO
/* Include before #define A(r,c) because armadillo uses A in its include files */
#include "armadillo"
#endif
#include "thinplatespline.h"
/////////////////////////////////////////////////////////////////////////////////////
//// vizGeorefSpline2D
/////////////////////////////////////////////////////////////////////////////////////
#define A(r,c) _AA[ _nof_eqs * (r) + (c) ]
#define Ainv(r,c) _Ainv[ _nof_eqs * (r) + (c) ]
#define VIZ_GEOREF_SPLINE_DEBUG 0
#ifndef HAVE_ARMADILLO
static int matrixInvert( int N, double input[], double output[] );
#endif
void VizGeorefSpline2D::grow_points()
{
int new_max = _max_nof_points*2 + 2 + 3;
int i;
x = (double *) VSIRealloc( x, sizeof(double) * new_max );
y = (double *) VSIRealloc( y, sizeof(double) * new_max );
u = (double *) VSIRealloc( u, sizeof(double) * new_max );
unused = (int *) VSIRealloc( unused, sizeof(int) * new_max );
index = (int *) VSIRealloc( index, sizeof(int) * new_max );
for( i = 0; i < VIZGEOREF_MAX_VARS; i++ )
{
rhs[i] = (double *)
VSIRealloc( rhs[i], sizeof(double) * new_max );
coef[i] = (double *)
VSIRealloc( coef[i], sizeof(double) * new_max );
if( _max_nof_points == 0 )
{
memset(rhs[i], 0, 3 * sizeof(double));
memset(coef[i], 0, 3 * sizeof(double));
}
}
_max_nof_points = new_max - 3;
}
int VizGeorefSpline2D::add_point( const double Px, const double Py, const double *Pvars )
{
type = VIZ_GEOREF_SPLINE_POINT_WAS_ADDED;
int i;
if( _nof_points == _max_nof_points )
grow_points();
i = _nof_points;
//A new point is added
x[i] = Px;
y[i] = Py;
for ( int j = 0; j < _nof_vars; j++ )
rhs[j][i+3] = Pvars[j];
_nof_points++;
return 1;
}
#if 0
bool VizGeorefSpline2D::change_point(int index, double Px, double Py, double* Pvars)
{
if ( index < _nof_points )
{
int i = index;
x[i] = Px;
y[i] = Py;
for ( int j = 0; j < _nof_vars; j++ )
rhs[j][i+3] = Pvars[j];
}
return( true );
}
bool VizGeorefSpline2D::get_xy(int index, double& outX, double& outY)
{
bool ok;
if ( index < _nof_points )
{
ok = true;
outX = x[index];
outY = y[index];
}
else
{
ok = false;
outX = outY = 0.0f;
}
return(ok);
}
int VizGeorefSpline2D::delete_point(const double Px, const double Py )
{
for ( int i = 0; i < _nof_points; i++ )
{
if ( ( fabs(Px - x[i]) <= _tx ) && ( fabs(Py - y[i]) <= _ty ) )
{
for ( int j = i; j < _nof_points - 1; j++ )
{
x[j] = x[j+1];
y[j] = y[j+1];
for ( int k = 0; k < _nof_vars; k++ )
rhs[k][j+3] = rhs[k][j+3+1];
}
_nof_points--;
type = VIZ_GEOREF_SPLINE_POINT_WAS_DELETED;
return(1);
}
}
return(0);
}
#endif
#define SQ(x) ((x)*(x))
static CPL_INLINE double VizGeorefSpline2DBase_func( const double x1, const double y1,
const double x2, const double y2 )
{
double dist = SQ( x2 - x1 ) + SQ( y2 - y1 );
return dist ? dist * log( dist ) : 0.0;
}
#if defined(__GNUC__) && defined(__x86_64__)
/* Derived and adapted from code originating from: */
/* @(#)e_log.c 1.3 95/01/18 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* __ieee754_log(x)
* Return the logrithm of x
*
* Method :
* 1. Argument Reduction: find k and f such that
* x = 2^k * (1+f),
* where sqrt(2)/2 < 1+f < sqrt(2) .
*
* 2. Approximation of log(1+f).
* Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
* = 2s + 2/3 s**3 + 2/5 s**5 + .....,
* = 2s + s*R
* We use a special Reme algorithm on [0,0.1716] to generate
* a polynomial of degree 14 to approximate R The maximum error
* of this polynomial approximation is bounded by 2**-58.45. In
* other words,
* 2 4 6 8 10 12 14
* R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
* (the values of Lg1 to Lg7 are listed in the program)
* and
* | 2 14 | -58.45
* | Lg1*s +...+Lg7*s - R(z) | <= 2
* | |
* Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
* In order to guarantee error in log below 1ulp, we compute log
* by
* log(1+f) = f - s*(f - R) (if f is not too large)
* log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
*
* 3. Finally, log(x) = k*ln2 + log(1+f).
* = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
* Here ln2 is split into two floating point number:
* ln2_hi + ln2_lo,
* where n*ln2_hi is always exact for |n| < 2000.
*
* Special cases:
* log(x) is NaN with signal if x < 0 (including -INF) ;
* log(+INF) is +INF; log(0) is -INF with signal;
* log(NaN) is that NaN with no signal.
*
* Accuracy:
* according to an error analysis, the error is always less than
* 1 ulp (unit in the last place).
*
* Constants:
* The hexadecimal values are the intended ones for the following
* constants. The decimal values may be used, provided that the
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
typedef double V2DF __attribute__ ((__vector_size__ (16)));
typedef union
{
V2DF v2;
double d[2];
} v2dfunion;
typedef union
{
int i[2];
long long li;
} i64union;
static const V2DF
v2_ln2_div_2pow20 = {6.93147180559945286e-01 / 1048576, 6.93147180559945286e-01 / 1048576},
v2_Lg1 = {6.666666666666735130e-01, 6.666666666666735130e-01},
v2_Lg2 = {3.999999999940941908e-01, 3.999999999940941908e-01},
v2_Lg3 = {2.857142874366239149e-01, 2.857142874366239149e-01},
v2_Lg4 = {2.222219843214978396e-01, 2.222219843214978396e-01},
v2_Lg5 = {1.818357216161805012e-01, 1.818357216161805012e-01},
v2_Lg6 = {1.531383769920937332e-01, 1.531383769920937332e-01},
/*v2_Lg7 = {1.479819860511658591e-01, 1.479819860511658591e-01}, */
v2_one = { 1.0, 1.0 },
v2_const1023_mul_2pow20 = { 1023.0 * 1048576, 1023.0 * 1048576};
#define GET_HIGH_WORD(hx,x) memcpy(&hx,((char*)&x+4),4)
#define SET_HIGH_WORD(x,hx) memcpy(((char*)&x+4),&hx,4)
#define MAKE_WIDE_CST(x) ((((long long)(x)) << 32) | (x))
static const long long cst_expmask = MAKE_WIDE_CST(0xfff00000);
static const long long cst_0x95f64 = MAKE_WIDE_CST(0x00095f64);
static const long long cst_0x100000 = MAKE_WIDE_CST(0x00100000);
static const long long cst_0x3ff00000 = MAKE_WIDE_CST(0x3ff00000);
/* Modified version of __ieee754_log(), less precise than log() but a bit */
/* faste, and computing 4 log() at a time. Assumes that the values are > 0 */
static void FastApproxLog4Val(v2dfunion* x)
{
V2DF f[2],s[2],z[2],R[2],w[2],t1[2],t2[2];
v2dfunion dk[2];
i64union k[2], hx[2], i[2];
GET_HIGH_WORD(hx[0].i[0],x[0].d[0]);
GET_HIGH_WORD(hx[0].i[1],x[0].d[1]);
k[0].li = hx[0].li & cst_expmask;
hx[0].li &= ~cst_expmask;
i[0].li = (hx[0].li + cst_0x95f64) & cst_0x100000;
hx[0].li |= i[0].li ^ cst_0x3ff00000;
SET_HIGH_WORD(x[0].d[0],hx[0].i[0]); /* normalize x or x/2 */
SET_HIGH_WORD(x[0].d[1],hx[0].i[1]); /* normalize x or x/2 */
k[0].li += i[0].li;
dk[0].d[0] = (double)k[0].i[0];
dk[0].d[1] = (double)k[0].i[1];
GET_HIGH_WORD(hx[1].i[0],x[1].d[0]);
GET_HIGH_WORD(hx[1].i[1],x[1].d[1]);
k[1].li = hx[1].li & cst_expmask;
hx[1].li &= ~cst_expmask;
i[1].li = (hx[1].li + cst_0x95f64) & cst_0x100000;
hx[1].li |= i[1].li ^ cst_0x3ff00000;
SET_HIGH_WORD(x[1].d[0],hx[1].i[0]); /* normalize x or x/2 */
SET_HIGH_WORD(x[1].d[1],hx[1].i[1]); /* normalize x or x/2 */
k[1].li += i[1].li;
dk[1].d[0] = (double)k[1].i[0];
dk[1].d[1] = (double)k[1].i[1];
f[0] = x[0].v2-v2_one;
s[0] = f[0]/(x[0].v2+v2_one);
z[0] = s[0]*s[0];
w[0] = z[0]*z[0];
t1[0]= w[0]*(v2_Lg2+w[0]*(v2_Lg4+w[0]*v2_Lg6));
t2[0]= z[0]*(v2_Lg1+w[0]*(v2_Lg3+w[0]*(v2_Lg5/*+w[0]*v2_Lg7*/)));
R[0] = t2[0]+t1[0];
x[0].v2 = ((dk[0].v2 - v2_const1023_mul_2pow20)*v2_ln2_div_2pow20-(s[0]*(f[0]-R[0])-f[0]));
f[1] = x[1].v2-v2_one;
s[1] = f[1]/(x[1].v2+v2_one);
z[1] = s[1]*s[1];
w[1] = z[1]*z[1];
t1[1]= w[1]*(v2_Lg2+w[1]*(v2_Lg4+w[1]*v2_Lg6));
t2[1]= z[1]*(v2_Lg1+w[1]*(v2_Lg3+w[1]*(v2_Lg5/*+w[1]*v2_Lg7*/)));
R[1] = t2[1]+t1[1];
x[1].v2 = ((dk[1].v2- v2_const1023_mul_2pow20)*v2_ln2_div_2pow20-(s[1]*(f[1]-R[1])-f[1]));
}
static CPL_INLINE void VizGeorefSpline2DBase_func4( double* res,
const double* pxy,
const double* xr, const double* yr )
{
v2dfunion x1v, y1v, xv[2], yv[2], dist[2], resv[2];
xv[0].d[0] = xr[0];
xv[0].d[1] = xr[1];
xv[1].d[0] = xr[2];
xv[1].d[1] = xr[3];
yv[0].d[0] = yr[0];
yv[0].d[1] = yr[1];
yv[1].d[0] = yr[2];
yv[1].d[1] = yr[3];
x1v.d[0] = pxy[0];
x1v.d[1] = pxy[0];
y1v.d[0] = pxy[1];
y1v.d[1] = pxy[1];
dist[0].v2 = SQ( xv[0].v2 - x1v.v2 ) + SQ( yv[0].v2 - y1v.v2 );
dist[1].v2 = SQ( xv[1].v2 - x1v.v2 ) + SQ( yv[1].v2 - y1v.v2 );
resv[0] = dist[0];
resv[1] = dist[1];
FastApproxLog4Val(dist);
resv[0].v2 *= dist[0].v2;
resv[1].v2 *= dist[1].v2;
res[0] = resv[0].d[0];
res[1] = resv[0].d[1];
res[2] = resv[1].d[0];
res[3] = resv[1].d[1];
}
#else
static void VizGeorefSpline2DBase_func4( double* res,
const double* pxy,
const double* xr, const double* yr )
{
double dist0 = SQ( xr[0] - pxy[0] ) + SQ( yr[0] - pxy[1] );
res[0] = dist0 ? dist0 * log(dist0) : 0.0;
double dist1 = SQ( xr[1] - pxy[0] ) + SQ( yr[1] - pxy[1] );
res[1] = dist1 ? dist1 * log(dist1) : 0.0;
double dist2 = SQ( xr[2] - pxy[0] ) + SQ( yr[2] - pxy[1] );
res[2] = dist2 ? dist2 * log(dist2) : 0.0;
double dist3 = SQ( xr[3] - pxy[0] ) + SQ( yr[3] - pxy[1] );
res[3] = dist3 ? dist3 * log(dist3) : 0.0;
}
#endif
int VizGeorefSpline2D::solve(void)
{
int r, c;
int p;
// No points at all
if ( _nof_points < 1 )
{
type = VIZ_GEOREF_SPLINE_ZERO_POINTS;
return(0);
}
// Only one point
if ( _nof_points == 1 )
{
type = VIZ_GEOREF_SPLINE_ONE_POINT;
return(1);
}
// Just 2 points - it is necessarily 1D case
if ( _nof_points == 2 )
{
_dx = x[1] - x[0];
_dy = y[1] - y[0];
double fact = 1.0 / ( _dx * _dx + _dy * _dy );
_dx *= fact;
_dy *= fact;
type = VIZ_GEOREF_SPLINE_TWO_POINTS;
return(2);
}
// More than 2 points - first we have to check if it is 1D or 2D case
double xmax = x[0], xmin = x[0], ymax = y[0], ymin = y[0];
double delx, dely;
double xx, yy;
double sumx = 0.0f, sumy= 0.0f, sumx2 = 0.0f, sumy2 = 0.0f, sumxy = 0.0f;
double SSxx, SSyy, SSxy;
for ( p = 0; p < _nof_points; p++ )
{
xx = x[p];
yy = y[p];
xmax = MAX( xmax, xx );
xmin = MIN( xmin, xx );
ymax = MAX( ymax, yy );
ymin = MIN( ymin, yy );
sumx += xx;
sumx2 += xx * xx;
sumy += yy;
sumy2 += yy * yy;
sumxy += xx * yy;
}
delx = xmax - xmin;
dely = ymax - ymin;
SSxx = sumx2 - sumx * sumx / _nof_points;
SSyy = sumy2 - sumy * sumy / _nof_points;
SSxy = sumxy - sumx * sumy / _nof_points;
if ( delx < 0.001 * dely || dely < 0.001 * delx ||
fabs ( SSxy * SSxy / ( SSxx * SSyy ) ) > 0.99 )
{
int p1;
type = VIZ_GEOREF_SPLINE_ONE_DIMENSIONAL;
_dx = _nof_points * sumx2 - sumx * sumx;
_dy = _nof_points * sumy2 - sumy * sumy;
double fact = 1.0 / sqrt( _dx * _dx + _dy * _dy );
_dx *= fact;
_dy *= fact;
for ( p = 0; p < _nof_points; p++ )
{
double dxp = x[p] - x[0];
double dyp = y[p] - y[0];
u[p] = _dx * dxp + _dy * dyp;
unused[p] = 1;
}
for ( p = 0; p < _nof_points; p++ )
{
int min_index = -1;
double min_u = 0;
for ( p1 = 0; p1 < _nof_points; p1++ )
{
if ( unused[p1] )
{
if ( min_index < 0 || u[p1] < min_u )
{
min_index = p1;
min_u = u[p1];
}
}
}
index[p] = min_index;
unused[min_index] = 0;
}
return(3);
}
type = VIZ_GEOREF_SPLINE_FULL;
// Make the necessary memory allocations
_nof_eqs = _nof_points + 3;
if( _nof_eqs > INT_MAX / _nof_eqs )
{
CPLError(CE_Failure, CPLE_AppDefined, "Too many coefficients. Computation aborted.");
return 0;
}
double* _AA = ( double * )VSICalloc( _nof_eqs * _nof_eqs, sizeof( double ) );
double* _Ainv = ( double * )VSICalloc( _nof_eqs * _nof_eqs, sizeof( double ) );
if( _AA == NULL || _Ainv == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined, "Out-of-memory while allocating temporary arrays. Computation aborted.");
VSIFree(_AA);
VSIFree(_Ainv);
return 0;
}
// Calc the values of the matrix A
for ( r = 0; r < 3; r++ )
for ( c = 0; c < 3; c++ )
A(r,c) = 0.0;
for ( c = 0; c < _nof_points; c++ )
{
A(0,c+3) = 1.0;
A(1,c+3) = x[c];
A(2,c+3) = y[c];
A(c+3,0) = 1.0;
A(c+3,1) = x[c];
A(c+3,2) = y[c];
}
for ( r = 0; r < _nof_points; r++ )
for ( c = r; c < _nof_points; c++ )
{
A(r+3,c+3) = VizGeorefSpline2DBase_func( x[r], y[r], x[c], y[c] );
if ( r != c )
A(c+3,r+3 ) = A(r+3,c+3);
}
#if VIZ_GEOREF_SPLINE_DEBUG
for ( r = 0; r < _nof_eqs; r++ )
{
for ( c = 0; c < _nof_eqs; c++ )
fprintf(stderr, "%f", A(r,c));
fprintf(stderr, "\n");
}
#endif
int ret = 4;
#ifdef HAVE_ARMADILLO
try
{
arma::mat matA(_AA,_nof_eqs,_nof_eqs,false);
arma::mat matRHS(_nof_eqs, _nof_vars);
int row, col;
for(row = 0; row < _nof_eqs; row++)
for(col = 0; col < _nof_vars; col++)
matRHS.at(row, col) = rhs[col][row];
arma::mat matCoefs(_nof_vars, _nof_eqs);
if( !arma::solve(matCoefs, matA, matRHS) )
{
CPLError(CE_Failure, CPLE_AppDefined, "There is a problem to invert the interpolation matrix.");
ret = 0;
}
else
{
for(row = 0; row < _nof_eqs; row++)
for(col = 0; col < _nof_vars; col++)
coef[col][row] = matCoefs.at(row, col);
}
}
catch(...)
{
CPLError(CE_Failure, CPLE_AppDefined, "There is a problem to invert the interpolation matrix.");
ret = 0;
}
#else
// Invert the matrix
int status = matrixInvert( _nof_eqs, _AA, _Ainv );
if ( !status )
{
CPLError(CE_Failure, CPLE_AppDefined, "There is a problem to invert the interpolation matrix.");
ret = 0;
}
else
{
// calc the coefs
for ( int v = 0; v < _nof_vars; v++ )
for ( r = 0; r < _nof_eqs; r++ )
{
coef[v][r] = 0.0;
for ( c = 0; c < _nof_eqs; c++ )
coef[v][r] += Ainv(r,c) * rhs[v][c];
}
}
#endif
VSIFree(_AA);
VSIFree(_Ainv);
return(ret);
}
int VizGeorefSpline2D::get_point( const double Px, const double Py, double *vars )
{
int v, r;
double tmp, Pu;
double fact;
int leftP=0, rightP=0, found = 0;
switch ( type )
{
case VIZ_GEOREF_SPLINE_ZERO_POINTS :
for ( v = 0; v < _nof_vars; v++ )
vars[v] = 0.0;
break;
case VIZ_GEOREF_SPLINE_ONE_POINT :
for ( v = 0; v < _nof_vars; v++ )
vars[v] = rhs[v][3];
break;
case VIZ_GEOREF_SPLINE_TWO_POINTS :
fact = _dx * ( Px - x[0] ) + _dy * ( Py - y[0] );
for ( v = 0; v < _nof_vars; v++ )
vars[v] = ( 1 - fact ) * rhs[v][3] + fact * rhs[v][4];
break;
case VIZ_GEOREF_SPLINE_ONE_DIMENSIONAL :
Pu = _dx * ( Px - x[0] ) + _dy * ( Py - y[0] );
if ( Pu <= u[index[0]] )
{
leftP = index[0];
rightP = index[1];
}
else if ( Pu >= u[index[_nof_points-1]] )
{
leftP = index[_nof_points-2];
rightP = index[_nof_points-1];
}
else
{
for ( r = 1; !found && r < _nof_points; r++ )
{
leftP = index[r-1];
rightP = index[r];
if ( Pu >= u[leftP] && Pu <= u[rightP] )
found = 1;
}
}
fact = ( Pu - u[leftP] ) / ( u[rightP] - u[leftP] );
for ( v = 0; v < _nof_vars; v++ )
vars[v] = ( 1.0 - fact ) * rhs[v][leftP+3] +
fact * rhs[v][rightP+3];
break;
case VIZ_GEOREF_SPLINE_FULL :
{
double Pxy[2] = { Px, Py };
for ( v = 0; v < _nof_vars; v++ )
vars[v] = coef[v][0] + coef[v][1] * Px + coef[v][2] * Py;
for ( r = 0; r < (_nof_points & (~3)); r+=4 )
{
double tmp[4];
VizGeorefSpline2DBase_func4( tmp, Pxy, &x[r], &y[r] );
for ( v= 0; v < _nof_vars; v++ )
vars[v] += coef[v][r+3] * tmp[0] +
coef[v][r+3+1] * tmp[1] +
coef[v][r+3+2] * tmp[2] +
coef[v][r+3+3] * tmp[3];
}
for ( ; r < _nof_points; r++ )
{
tmp = VizGeorefSpline2DBase_func( Px, Py, x[r], y[r] );
for ( v= 0; v < _nof_vars; v++ )
vars[v] += coef[v][r+3] * tmp;
}
break;
}
case VIZ_GEOREF_SPLINE_POINT_WAS_ADDED :
fprintf(stderr, " A point was added after the last solve\n");
fprintf(stderr, " NO interpolation - return values are zero\n");
for ( v = 0; v < _nof_vars; v++ )
vars[v] = 0.0;
return(0);
break;
case VIZ_GEOREF_SPLINE_POINT_WAS_DELETED :
fprintf(stderr, " A point was deleted after the last solve\n");
fprintf(stderr, " NO interpolation - return values are zero\n");
for ( v = 0; v < _nof_vars; v++ )
vars[v] = 0.0;
return(0);
break;
default :
return(0);
break;
}
return(1);
}
#ifndef HAVE_ARMADILLO
static int matrixInvert( int N, double input[], double output[] )
{
// Receives an array of dimension NxN as input. This is passed as a one-
// dimensional array of N-squared size. It produces the inverse of the
// input matrix, returned as output, also of size N-squared. The Gauss-
// Jordan Elimination method is used. (Adapted from a BASIC routine in
// "Basic Scientific Subroutines Vol. 1", courtesy of Scott Edwards.)
// Array elements 0...N-1 are for the first row, N...2N-1 are for the
// second row, etc.
// We need to have a temporary array of size N x 2N. We'll refer to the
// "left" and "right" halves of this array.
int row, col;
#if 0
fprintf(stderr, "Matrix Inversion input matrix (N=%d)\n", N);
for ( row=0; row<N; row++ )
{
for ( col=0; col<N; col++ )
{
fprintf(stderr, "%5.2f ", input[row*N + col ] );
}
fprintf(stderr, "\n");
}
#endif
int tempSize = 2 * N * N;
double* temp = (double*) new double[ tempSize ];
double ftemp;
if (temp == 0) {
CPLError(CE_Failure, CPLE_AppDefined, "matrixInvert(): ERROR - memory allocation failed.");
return false;
}
// First create a double-width matrix with the input array on the left
// and the identity matrix on the right.
for ( row=0; row<N; row++ )
{
for ( col=0; col<N; col++ )
{
// Our index into the temp array is X2 because it's twice as wide
// as the input matrix.
temp[ 2*row*N + col ] = input[ row*N+col ]; // left = input matrix
temp[ 2*row*N + col + N ] = 0.0f; // right = 0
}
temp[ 2*row*N + row + N ] = 1.0f; // 1 on the diagonal of RHS
}
// Now perform row-oriented operations to convert the left hand side
// of temp to the identity matrix. The inverse of input will then be
// on the right.
int max;
int k=0;
for (k = 0; k < N; k++)
{
if (k+1 < N) // if not on the last row
{
max = k;
for (row = k+1; row < N; row++) // find the maximum element
{
if (fabs( temp[row*2*N + k] ) > fabs( temp[max*2*N + k] ))
{
max = row;
}
}
if (max != k) // swap all the elements in the two rows
{
for (col=k; col<2*N; col++)
{
ftemp = temp[k*2*N + col];
temp[k*2*N + col] = temp[max*2*N + col];
temp[max*2*N + col] = ftemp;
}
}
}
ftemp = temp[ k*2*N + k ];
if ( ftemp == 0.0f ) // matrix cannot be inverted
{
delete[] temp;
return false;
}
for ( col=k; col<2*N; col++ )
{
temp[ k*2*N + col ] /= ftemp;
}
int i2 = k*2*N ;
for ( row=0; row<N; row++ )
{
if ( row != k )
{
int i1 = row*2*N;
ftemp = temp[ i1 + k ];
for ( col=k; col<2*N; col++ )
{
temp[ i1 + col ] -= ftemp * temp[ i2 + col ];
}
}
}
}
// Retrieve inverse from the right side of temp
for (row = 0; row < N; row++)
{
for (col = 0; col < N; col++)
{
output[row*N + col] = temp[row*2*N + col + N ];
}
}
#if 0
fprintf(stderr, "Matrix Inversion result matrix:\n");
for ( row=0; row<N; row++ )
{
for ( col=0; col<N; col++ )
{
fprintf(stderr, "%5.2f ", output[row*N + col ] );
}
fprintf(stderr, "\n");
}
#endif
delete [] temp; // free memory
return true;
}
#endif

View file

@ -0,0 +1,170 @@
/******************************************************************************
* $Id: thinplatespline.h 26650 2013-11-24 14:05:58Z rouault $
*
* Project: GDAL Warp API
* Purpose: Declarations for 2D Thin Plate Spline transformer.
* Author: VIZRT Development Team.
*
* This code was provided by Gilad Ronnen (gro at visrt dot com) with
* permission to reuse under the following license.
*
******************************************************************************
* Copyright (c) 2004, VIZRT Inc.
*
* 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_alg.h"
#include "cpl_conv.h"
typedef enum
{
VIZ_GEOREF_SPLINE_ZERO_POINTS,
VIZ_GEOREF_SPLINE_ONE_POINT,
VIZ_GEOREF_SPLINE_TWO_POINTS,
VIZ_GEOREF_SPLINE_ONE_DIMENSIONAL,
VIZ_GEOREF_SPLINE_FULL,
VIZ_GEOREF_SPLINE_POINT_WAS_ADDED,
VIZ_GEOREF_SPLINE_POINT_WAS_DELETED
} vizGeorefInterType;
//#define VIZ_GEOREF_SPLINE_MAX_POINTS 40
#define VIZGEOREF_MAX_VARS 2
class VizGeorefSpline2D
{
public:
VizGeorefSpline2D(int nof_vars = 1){
x = y = u = NULL;
unused = index = NULL;
for( int i = 0; i < nof_vars; i++ )
{
rhs[i] = NULL;
coef[i] = NULL;
}
_tx = _ty = 0.0;
_ta = 10.0;
_nof_points = 0;
_nof_vars = nof_vars;
_max_nof_points = 0;
grow_points();
type = VIZ_GEOREF_SPLINE_ZERO_POINTS;
}
~VizGeorefSpline2D(){
CPLFree( x );
CPLFree( y );
CPLFree( u );
CPLFree( unused );
CPLFree( index );
for( int i = 0; i < _nof_vars; i++ )
{
CPLFree( rhs[i] );
CPLFree( coef[i] );
}
}
#if 0
int get_nof_points(){
return _nof_points;
}
void set_toler( double tx, double ty ){
_tx = tx;
_ty = ty;
}
void get_toler( double& tx, double& ty) {
tx = _tx;
ty = _ty;
}
vizGeorefInterType get_interpolation_type ( ){
return type;
}
void dump_data_points()
{
for ( int i = 0; i < _nof_points; i++ )
{
fprintf(stderr, "X = %f Y = %f Vars = ", x[i], y[i]);
for ( int v = 0; v < _nof_vars; v++ )
fprintf(stderr, "%f ", rhs[v][i+3]);
fprintf(stderr, "\n");
}
}
int delete_list()
{
_nof_points = 0;
type = VIZ_GEOREF_SPLINE_ZERO_POINTS;
if ( _AA )
{
CPLFree(_AA);
_AA = NULL;
}
if ( _Ainv )
{
CPLFree(_Ainv);
_Ainv = NULL;
}
return _nof_points;
}
#endif
void grow_points();
int add_point( const double Px, const double Py, const double *Pvars );
int get_point( const double Px, const double Py, double *Pvars );
#if 0
int delete_point(const double Px, const double Py );
bool get_xy(int index, double& x, double& y);
bool change_point(int index, double x, double y, double* Pvars);
void reset(void) { _nof_points = 0; }
#endif
int solve(void);
private:
vizGeorefInterType type;
int _nof_vars;
int _nof_points;
int _max_nof_points;
int _nof_eqs;
double _tx, _ty;
double _ta;
double _dx, _dy;
double *x; // [VIZ_GEOREF_SPLINE_MAX_POINTS+3];
double *y; // [VIZ_GEOREF_SPLINE_MAX_POINTS+3];
// double rhs[VIZ_GEOREF_SPLINE_MAX_POINTS+3][VIZGEOREF_MAX_VARS];
// double coef[VIZ_GEOREF_SPLINE_MAX_POINTS+3][VIZGEOREF_MAX_VARS];
double *rhs[VIZGEOREF_MAX_VARS];
double *coef[VIZGEOREF_MAX_VARS];
double *u; // [VIZ_GEOREF_SPLINE_MAX_POINTS];
int *unused; // [VIZ_GEOREF_SPLINE_MAX_POINTS];
int *index; // [VIZ_GEOREF_SPLINE_MAX_POINTS];
};

View file

@ -0,0 +1,149 @@
#define CPL_DISABLE_DLL
#define DISABLE_CPLID // ALLOW BLITZ
#define GDAL_COMPILATION
#ifndef _gdal_cpl_config_h_
#define _gdal_cpl_config_h_
#define RENAME_INTERNAL_LIBTIFF_SYMBOLS
#define RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS
// added to embed in U++ to fix plugin/tif interoperability
#define TIFFSwabArrayOfDouble gdal_TIFFSwabArrayOfDouble
#define TIFFSwabArrayOfLong gdal_TIFFSwabArrayOfLong
#define TIFFSwabArrayOfShort gdal_TIFFSwabArrayOfShort
#define TIFFSwabArrayOfTriples gdal_TIFFSwabArrayOfTriples
#define TIFFSwabDouble gdal_TIFFSwabDouble
#define TIFFSwabLong gdal_TIFFSwabLong
#define TIFFSwabShort gdal_TIFFSwabShort
#define _TIFFSwab16BitData gdal__TIFFSwab16BitData
#define _TIFFSwab24BitData gdal__TIFFSwab24BitData
#define _TIFFSwab32BitData gdal__TIFFSwab32BitData
#define _TIFFSwab64BitData gdal__TIFFSwab64BitData
/* We define this here in general so that a VC++ build will publically
declare STDCALL interfaces even if an application is built against it
using MinGW */
#ifndef CPL_DISABLE_STDCALL
# define CPL_STDCALL __stdcall
#endif
#define HAVE_LIBZ 1
/* Define if you don't have vprintf but do have _doprnt. */
#undef HAVE_DOPRNT
/* Define if you have the vprintf function. */
#define HAVE_VPRINTF 1
#define HAVE_VSNPRINTF 1
#define HAVE_SNPRINTF 1
#if defined(_MSC_VER) && (_MSC_VER < 1500)
# define vsnprintf _vsnprintf
#endif
#if defined(_MSC_VER) && (_MSC_VER < 1900)
# define snprintf _snprintf
#endif
#define HAVE_GETCWD 1
/* gmt_notunix.h from GMT project also redefines getcwd. See #3138 */
#ifndef getcwd
#define getcwd _getcwd
#endif
/* Define if you have the ANSI C header files. */
#ifndef STDC_HEADERS
# define STDC_HEADERS 1
#endif
/* Define to 1 if you have the <assert.h> header file. */
#define HAVE_ASSERT_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
#undef HAVE_LIBDL
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
#define HAVE_FLOAT_H 1
#define HAVE_ERRNO_H 1
#define HAVE_SEARCH_H 1
/* Define to 1 if you have the <direct.h> header file. */
#define HAVE_DIRECT_H
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
#undef HAVE_DLFCN_H
#undef HAVE_DBMALLOC_H
#undef HAVE_LIBDBMALLOC
#undef WORDS_BIGENDIAN
/* The size of a `int', as computed by sizeof. */
#define SIZEOF_INT 4
/* The size of a `long', as computed by sizeof. */
#define SIZEOF_LONG 4
/* The size of a `unsigned long', as computed by sizeof. */
#define SIZEOF_UNSIGNED_LONG 4
/* The size of `void*', as computed by sizeof. */
#ifdef _WIN64
# define SIZEOF_VOIDP 8
#else
# define SIZEOF_VOIDP 4
#endif
/* Set the native cpu bit order */
#define HOST_FILLORDER FILLORDER_LSB2MSB
/* Define as 0 or 1 according to the floating point format suported by the
machine */
#define HAVE_IEEEFP 1
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
# ifndef inline
# define inline __inline
# endif
#endif
#define lfind _lfind
#if defined(_MSC_VER) && (_MSC_VER < 1310)
# define VSI_STAT64 _stat
# define VSI_STAT64_T _stat
#else
# define VSI_STAT64 _stat64
# define VSI_STAT64_T __stat64
#endif
/* VC6 doesn't known intptr_t */
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
typedef int intptr_t;
#endif
#pragma warning(disable: 4786)
/* #define CPL_DISABLE_DLL */
#endif

View file

@ -0,0 +1,27 @@
include ../GDALmake.opt
OBJ = o/gdalallregister.o
FRMT_FLAGS = $(foreach FRMT, $(GDAL_FORMATS), -DFRMT_$(FRMT))
%-install-obj:
$(MAKE) -C $* install-obj
default: $(OBJ:.o=.$(OBJ_EXT)) $(foreach d,$(GDAL_FORMATS),$(d)-install-obj)
clean: $(foreach d,$(GDAL_FORMATS),$(d)-clean)
rm -f *.o o/*.o o/*.a
$(RM) o/*.lo
o/gdalallregister.$(OBJ_EXT): gdalallregister.cpp ../GDALmake.opt
$(CXX) -c $(GDAL_INCLUDE) $(CXXFLAGS) $(FRMT_FLAGS) \
-DGDAL_FORMATS="$(GDAL_FORMATS)" \
gdalallregister.cpp -o o/gdalallregister.$(OBJ_EXT)
# We might want to add dynamically generated drivers here eventually.
install:
$(MAKE) -C vrt install
$(MAKE) -C mem install
$(MAKE) -C raw install

View file

@ -0,0 +1,15 @@
include ../../GDALmake.opt
OBJ = aaigriddataset.o
CPPFLAGS := $(CPPFLAGS) $(XTRA_OPT)
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o
all: $(OBJ:.o=.$(OBJ_EXT))
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
OBJ = aaigriddataset.obj
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,14 @@
include ../../GDALmake.opt
OBJ = adrgdataset.o srpdataset.o
CPPFLAGS := $(CPPFLAGS) -I../iso8211
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
OBJ = adrgdataset.obj srpdataset.obj
EXTRAFLAGS = -I..\iso8211
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
include ../../GDALmake.opt
AIGOBJ = gridlib.o aigopen.o aigccitt.o
OBJ = aigdataset.o $(AIGOBJ)
CPPFLAGS := $(CPPFLAGS) -I../../ogr/ogrsf_frmts/avc
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o aitest$(EXE) $(OBJ) $(O_OBJ)
aitest$(EXE): aitest.$(OBJ_EXT)
$(LD) $(LDFLAGS) aitest.$(OBJ_EXT) $(CONFIG_LIBS) -o aitest$(EXE)
aigrid2tif$(EXE): aigrid2tif.$(OBJ_EXT)
$(LD) $(LDFLAGS) aigrid2tif.$(OBJ_EXT) $(CONFIG_LIBS) -o aigrid2tif$(EXE)
$(OBJ) $(O_OBJ): aigrid.h
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))
aitest-dist:
rm -rf aitest_dist
mkdir aitest_dist
cp gridlib.c aitest.c aigrid.h aigopen.c aigccitt.c aitest_dist
cp ../../port/cpl_{vsisimple,conv,error}.cpp aitest_dist
cp ../../port/cpl_{port,conv,vsi,config,error}.h aitest_dist
cp Makefile.dist aitest_dist/Makefile

View file

@ -0,0 +1,19 @@
OBJ = aigopen.o gridlib.o aigccitt.o \
cpl_vsisimple.o cpl_conv.o cpl_error.o
default: aitest
aitest: $(OBJ)
$(CXX) aitest.c $(OBJ) -o aitest
cpl_vsisimple.o: cpl_vsisimple.cpp
$(CXX) -c cpl_vsisimple.cpp
cpl_conv.o: cpl_conv.cpp
$(CXX) -c cpl_conv.cpp
cpl_error.o: cpl_error.cpp
$(CXX) -c cpl_error.cpp

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,479 @@
/******************************************************************************
* $Id: aigopen.c 27044 2014-03-16 23:41:27Z rouault $
*
* Project: Arc/Info Binary Grid Translator
* Purpose: Grid file access cover API for non-GDAL use.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
* Copyright (c) 2009-2010, 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 "aigrid.h"
CPL_CVSID("$Id: aigopen.c 27044 2014-03-16 23:41:27Z rouault $");
/************************************************************************/
/* AIGOpen() */
/************************************************************************/
AIGInfo_t *AIGOpen( const char * pszInputName, const char * pszAccess )
{
AIGInfo_t *psInfo;
char *pszCoverName;
(void) pszAccess;
/* -------------------------------------------------------------------- */
/* If the pass name ends in .adf assume a file within the */
/* coverage has been selected, and strip that off the coverage */
/* name. */
/* -------------------------------------------------------------------- */
pszCoverName = CPLStrdup( pszInputName );
if( EQUAL(pszCoverName+strlen(pszCoverName)-4, ".adf") )
{
int i;
for( i = strlen(pszCoverName)-1; i > 0; i-- )
{
if( pszCoverName[i] == '\\' || pszCoverName[i] == '/' )
{
pszCoverName[i] = '\0';
break;
}
}
if( i == 0 )
strcpy(pszCoverName,".");
}
/* -------------------------------------------------------------------- */
/* Allocate info structure. */
/* -------------------------------------------------------------------- */
psInfo = (AIGInfo_t *) CPLCalloc(sizeof(AIGInfo_t),1);
psInfo->bHasWarned = FALSE;
psInfo->pszCoverName = pszCoverName;
/* -------------------------------------------------------------------- */
/* Read the header file. */
/* -------------------------------------------------------------------- */
if( AIGReadHeader( pszCoverName, psInfo ) != CE_None )
{
CPLFree( pszCoverName );
CPLFree( psInfo );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Read the extents. */
/* -------------------------------------------------------------------- */
if( AIGReadBounds( pszCoverName, psInfo ) != CE_None )
{
AIGClose( psInfo );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Compute the number of pixels and lines, and the number of */
/* tile files. */
/* -------------------------------------------------------------------- */
if (psInfo->dfCellSizeX <= 0 || psInfo->dfCellSizeY <= 0)
{
CPLError( CE_Failure, CPLE_AppDefined,
"Illegal cell size : %f x %f",
psInfo->dfCellSizeX, psInfo->dfCellSizeY );
AIGClose( psInfo );
return NULL;
}
psInfo->nPixels = (int)
((psInfo->dfURX - psInfo->dfLLX + 0.5 * psInfo->dfCellSizeX)
/ psInfo->dfCellSizeX);
psInfo->nLines = (int)
((psInfo->dfURY - psInfo->dfLLY + 0.5 * psInfo->dfCellSizeY)
/ psInfo->dfCellSizeY);
if (psInfo->nPixels <= 0 || psInfo->nLines <= 0)
{
CPLError( CE_Failure, CPLE_AppDefined,
"Invalid raster dimensions : %d x %d",
psInfo->nPixels, psInfo->nLines );
AIGClose( psInfo );
return NULL;
}
if (psInfo->nBlockXSize <= 0 || psInfo->nBlockYSize <= 0 ||
psInfo->nBlocksPerRow <= 0 || psInfo->nBlocksPerColumn <= 0 ||
psInfo->nBlockXSize > INT_MAX / psInfo->nBlocksPerRow ||
psInfo->nBlockYSize > INT_MAX / psInfo->nBlocksPerColumn)
{
CPLError( CE_Failure, CPLE_AppDefined,
"Invalid block characteristics: nBlockXSize=%d, "
"nBlockYSize=%d, nBlocksPerRow=%d, nBlocksPerColumn=%d",
psInfo->nBlockXSize, psInfo->nBlockYSize,
psInfo->nBlocksPerRow, psInfo->nBlocksPerColumn);
AIGClose( psInfo );
return NULL;
}
psInfo->nTileXSize = psInfo->nBlockXSize * psInfo->nBlocksPerRow;
psInfo->nTileYSize = psInfo->nBlockYSize * psInfo->nBlocksPerColumn;
psInfo->nTilesPerRow = (psInfo->nPixels-1) / psInfo->nTileXSize + 1;
psInfo->nTilesPerColumn = (psInfo->nLines-1) / psInfo->nTileYSize + 1;
if (psInfo->nTilesPerRow > INT_MAX / psInfo->nTilesPerColumn)
{
CPLError(CE_Failure, CPLE_OutOfMemory, "Too many tiles");
AIGClose( psInfo );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Setup tile infos, but defer reading of tile data. */
/* -------------------------------------------------------------------- */
psInfo->pasTileInfo = (AIGTileInfo *)
VSICalloc(sizeof(AIGTileInfo),
psInfo->nTilesPerRow * psInfo->nTilesPerColumn);
if (psInfo->pasTileInfo == NULL)
{
CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate tile info array");
AIGClose( psInfo );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Read the statistics. */
/* -------------------------------------------------------------------- */
if( AIGReadStatistics( pszCoverName, psInfo ) != CE_None )
{
AIGClose( psInfo );
return NULL;
}
return( psInfo );
}
/************************************************************************/
/* AIGAccessTile() */
/************************************************************************/
CPLErr AIGAccessTile( AIGInfo_t *psInfo, int iTileX, int iTileY )
{
char szBasename[20];
char *pszFilename;
AIGTileInfo *psTInfo;
/* -------------------------------------------------------------------- */
/* Identify our tile. */
/* -------------------------------------------------------------------- */
if( iTileX < 0 || iTileX >= psInfo->nTilesPerRow
|| iTileY < 0 || iTileY >= psInfo->nTilesPerColumn )
{
CPLAssert( FALSE );
return CE_Failure;
}
psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
if( psTInfo->fpGrid != NULL || psTInfo->bTriedToLoad )
return CE_None;
/* -------------------------------------------------------------------- */
/* Compute the basename. */
/* -------------------------------------------------------------------- */
if( iTileY == 0 )
sprintf( szBasename, "w%03d001", iTileX + 1 );
else if( iTileY == 1 )
sprintf( szBasename, "w%03d000", iTileX + 1 );
else
sprintf( szBasename, "z%03d%03d", iTileX + 1, iTileY - 1 );
/* -------------------------------------------------------------------- */
/* Open the file w001001.adf file itself. */
/* -------------------------------------------------------------------- */
pszFilename = (char *) CPLMalloc(strlen(psInfo->pszCoverName)+40);
sprintf( pszFilename, "%s/%s.adf", psInfo->pszCoverName, szBasename );
psTInfo->fpGrid = AIGLLOpen( pszFilename, "rb" );
psTInfo->bTriedToLoad = TRUE;
if( psTInfo->fpGrid == NULL )
{
CPLError( CE_Warning, CPLE_OpenFailed,
"Failed to open grid file, assuming region is nodata:\n%s\n",
pszFilename );
CPLFree( pszFilename );
return CE_Warning;
}
CPLFree( pszFilename );
pszFilename = NULL;
/* -------------------------------------------------------------------- */
/* Read the block index file. */
/* -------------------------------------------------------------------- */
return AIGReadBlockIndex( psInfo, psTInfo, szBasename );
}
/************************************************************************/
/* AIGReadTile() */
/************************************************************************/
CPLErr AIGReadTile( AIGInfo_t * psInfo, int nBlockXOff, int nBlockYOff,
GInt32 *panData )
{
int nBlockID;
CPLErr eErr;
int iTileX, iTileY;
AIGTileInfo *psTInfo;
/* -------------------------------------------------------------------- */
/* Compute our tile, and ensure it is accessable (open). Then */
/* reduce block x/y values to be the block within that tile. */
/* -------------------------------------------------------------------- */
iTileX = nBlockXOff / psInfo->nBlocksPerRow;
iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
eErr = AIGAccessTile( psInfo, iTileX, iTileY );
if( eErr == CE_Failure )
return eErr;
psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
/* -------------------------------------------------------------------- */
/* Request for tile from a file which does not exist - treat as */
/* all nodata. */
/* -------------------------------------------------------------------- */
if( psTInfo->fpGrid == NULL )
{
int i;
for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
panData[i] = ESRI_GRID_NO_DATA;
return CE_None;
}
/* -------------------------------------------------------------------- */
/* validate block id. */
/* -------------------------------------------------------------------- */
nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
if( nBlockID < 0
|| nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Illegal block requested." );
return CE_Failure;
}
if( nBlockID >= psTInfo->nBlocks )
{
int i;
CPLDebug( "AIG",
"Request legal block, but from beyond end of block map.\n"
"Assuming all nodata." );
for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
panData[i] = ESRI_GRID_NO_DATA;
return CE_None;
}
/* -------------------------------------------------------------------- */
/* Read block. */
/* -------------------------------------------------------------------- */
eErr = AIGReadBlock( psTInfo->fpGrid,
psTInfo->panBlockOffset[nBlockID],
psTInfo->panBlockSize[nBlockID],
psInfo->nBlockXSize, psInfo->nBlockYSize,
panData, psInfo->nCellType, psInfo->bCompressed );
/* -------------------------------------------------------------------- */
/* Apply floating point post-processing. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_FLOAT )
{
float *pafData = (float *) panData;
int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
for( i = 0; i < nPixels; i++ )
{
panData[i] = (int) pafData[i];
}
}
return( eErr );
}
/************************************************************************/
/* AIGReadFloatTile() */
/************************************************************************/
CPLErr AIGReadFloatTile( AIGInfo_t * psInfo, int nBlockXOff, int nBlockYOff,
float *pafData )
{
int nBlockID;
CPLErr eErr;
int iTileX, iTileY;
AIGTileInfo *psTInfo;
/* -------------------------------------------------------------------- */
/* Compute our tile, and ensure it is accessable (open). Then */
/* reduce block x/y values to be the block within that tile. */
/* -------------------------------------------------------------------- */
iTileX = nBlockXOff / psInfo->nBlocksPerRow;
iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
eErr = AIGAccessTile( psInfo, iTileX, iTileY );
if( eErr == CE_Failure )
return eErr;
psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
/* -------------------------------------------------------------------- */
/* Request for tile from a file which does not exist - treat as */
/* all nodata. */
/* -------------------------------------------------------------------- */
if( psTInfo->fpGrid == NULL )
{
int i;
for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
return CE_None;
}
/* -------------------------------------------------------------------- */
/* validate block id. */
/* -------------------------------------------------------------------- */
nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
if( nBlockID < 0
|| nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Illegal block requested." );
return CE_Failure;
}
if( nBlockID >= psTInfo->nBlocks )
{
int i;
CPLDebug( "AIG",
"Request legal block, but from beyond end of block map.\n"
"Assuming all nodata." );
for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
return CE_None;
}
/* -------------------------------------------------------------------- */
/* Read block. */
/* -------------------------------------------------------------------- */
eErr = AIGReadBlock( psTInfo->fpGrid,
psTInfo->panBlockOffset[nBlockID],
psTInfo->panBlockSize[nBlockID],
psInfo->nBlockXSize, psInfo->nBlockYSize,
(GInt32 *) pafData, psInfo->nCellType,
psInfo->bCompressed );
/* -------------------------------------------------------------------- */
/* Perform integer post processing. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_INT )
{
GUInt32 *panData = (GUInt32 *) pafData;
int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
for( i = 0; i < nPixels; i++ )
{
pafData[i] = (float) panData[i];
}
}
return( eErr );
}
/************************************************************************/
/* AIGClose() */
/************************************************************************/
void AIGClose( AIGInfo_t * psInfo )
{
int nTileCount = psInfo->nTilesPerRow * psInfo->nTilesPerColumn;
int iTile;
for( iTile = 0; iTile < nTileCount; iTile++ )
{
if( psInfo->pasTileInfo[iTile].fpGrid )
{
VSIFCloseL( psInfo->pasTileInfo[iTile].fpGrid );
CPLFree( psInfo->pasTileInfo[iTile].panBlockOffset );
CPLFree( psInfo->pasTileInfo[iTile].panBlockSize );
}
}
CPLFree( psInfo->pasTileInfo );
CPLFree( psInfo->pszCoverName );
CPLFree( psInfo );
}
/************************************************************************/
/* AIGLLOpen() */
/* */
/* Low level fopen() replacement that will try provided, and */
/* upper cased versions of file names. */
/************************************************************************/
VSILFILE *AIGLLOpen( const char *pszFilename, const char *pszAccess )
{
VSILFILE *fp;
fp = VSIFOpenL( pszFilename, pszAccess );
if( fp == NULL )
{
char *pszUCFilename = CPLStrdup(pszFilename);
int i;
for( i = strlen(pszUCFilename)-1;
pszUCFilename[i] != '/' && pszUCFilename[i] != '\\';
i-- )
{
pszUCFilename[i] = (char) toupper(pszUCFilename[i]);
}
fp = VSIFOpenL( pszUCFilename, pszAccess );
CPLFree( pszUCFilename );
}
return fp;
}

View file

@ -0,0 +1,135 @@
/******************************************************************************
* $Id: aigrid.h 22159 2011-04-14 18:18:54Z warmerdam $
*
* Project: Arc/Info Binary Grid Translator
* Purpose: Grid file access include file.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* 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.
****************************************************************************/
#ifndef _AIGRID_H_INCLUDED
#define _AIGRID_H_INCLUDED
#include "cpl_conv.h"
CPL_C_START
#define ESRI_GRID_NO_DATA -2147483647
/*#define ESRI_GRID_FLOAT_NO_DATA -340282306073709652508363335590014353408.0 */
#define ESRI_GRID_FLOAT_NO_DATA -340282346638528859811704183484516925440.0
/* ==================================================================== */
/* Grid Instance */
/* ==================================================================== */
typedef struct {
int nBlocks;
GUInt32 *panBlockOffset;
int *panBlockSize;
VSILFILE *fpGrid; /* the w001001.adf file */
int bTriedToLoad;
} AIGTileInfo;
typedef struct {
/* Private information */
AIGTileInfo *pasTileInfo;
int bHasWarned;
/* public information */
char *pszCoverName; /* path of coverage directory */
GInt32 nCellType;
GInt32 bCompressed;
#define AIG_CELLTYPE_INT 1
#define AIG_CELLTYPE_FLOAT 2
GInt32 nBlockXSize;
GInt32 nBlockYSize;
GInt32 nBlocksPerRow;
GInt32 nBlocksPerColumn;
int nTileXSize;
int nTileYSize;
int nTilesPerRow;
int nTilesPerColumn;
double dfLLX;
double dfLLY;
double dfURX;
double dfURY;
double dfCellSizeX;
double dfCellSizeY;
int nPixels;
int nLines;
double dfMin;
double dfMax;
double dfMean;
double dfStdDev;
} AIGInfo_t;
/* ==================================================================== */
/* Private APIs */
/* ==================================================================== */
CPLErr AIGAccessTile( AIGInfo_t *psInfo, int iTileX, int iTileY );
CPLErr AIGReadBlock( VSILFILE * fp, GUInt32 nBlockOffset, int nBlockSize,
int nBlockXSize, int nBlockYSize, GInt32 * panData,
int nCellType, int bCompressed );
CPLErr AIGReadHeader( const char *, AIGInfo_t * );
CPLErr AIGReadBlockIndex( AIGInfo_t *, AIGTileInfo *,
const char *pszBasename );
CPLErr AIGReadBounds( const char *, AIGInfo_t * );
CPLErr AIGReadStatistics( const char *, AIGInfo_t * );
CPLErr DecompressCCITTRLETile( unsigned char *pabySrcData, int nSrcBytes,
unsigned char *pabyDstData, int nDstBytes,
int nBlockXSize, int nBlockYSize );
/* ==================================================================== */
/* Public APIs */
/* ==================================================================== */
AIGInfo_t *AIGOpen( const char *, const char * );
CPLErr AIGReadTile( AIGInfo_t *, int, int, GInt32 * );
CPLErr AIGReadFloatTile( AIGInfo_t *, int, int, float * );
void AIGClose( AIGInfo_t * );
VSILFILE *AIGLLOpen( const char *, const char * );
CPL_C_END
#endif /* ndef _AIGRID_H_INCLUDED */

View file

@ -0,0 +1,790 @@
<html>
<head>
<title>Arc/Info Binary Grid Format</title>
</head>
<body bgcolor="#ffffff">
<h1>Arc/Info Binary Grid Format</h1>
<i>by <a href="http://pobox.com/~warmerdam">Frank Warmerdam</a></i>
(<a href="mailto:warmerdam@pobox.com">warmerdam@pobox.com</a>)<p>
The Arc/Info Binary Grid format is the internal working format of the
Arc/Info Grid product. It is also usable and creatable within the
spatial analyst component of ArcView. It is a tiled (blocked) format with run
length compression capable of holding raster data of up to 4 byte integers
or 4 byte floating data. <p>
This format should not be confused with the Arc/Info ASCII Grid format
which is the interchange format for grids. Files can be converted between
binary and ASCII format with the GRIDASCII and ASCIIGRID commands in
Arc/Info. This format is also different than the flat binary raster
output of the GRIDFLOAT command. The Arc/Info binary float, and ASCII
formats are also accessable from within ArcView.<p>
This format should also not be confused with what I know as ESRI BIL format.
This is really a standard ESRI way of creating a header file (.HDR)
describing the data layout a binary raster file containing raster data.<p>
<!--------------------------------------------------------------------------->
<h2>Version</h2>
I am not sure yet how the versions work for grid files. I have been
working primarily with grid files generated by ArcView 3.x, and it's associated
gridio API. The hdr.adf files I have examined start with the string
<b>GRID1.2</b> for what that's worth. Certainly the file naming conventions
seem to follow the Arc/Info 7.x conventions rather than that of earlier
versions.<p>
<!--------------------------------------------------------------------------->
<h2>File Set</h2>
A grid coverage actually consists of a number of files. A grid normally
lives in it's own directory named after the grid. For instance, the
grid <b>nwgrd1</b> lives in the directory <b>nwgrd1</b>, and has the following
component files:<p>
<pre>
-rwxr--r-- 1 warmerda users 32 Jan 22 16:07 nwgrd1/dblbnd.adf
-rwxr--r-- 1 warmerda users 308 Jan 22 16:07 nwgrd1/hdr.adf
-rwxr--r-- 1 warmerda users 32 Jan 22 16:07 nwgrd1/sta.adf
-rwxr--r-- 1 warmerda users 2048 Jan 22 16:07 nwgrd1/vat.adf
-rwxr--r-- 1 warmerda users 187228 Jan 22 16:07 nwgrd1/w001001.adf
-rwxr--r-- 1 warmerda users 6132 Jan 22 16:07 nwgrd1/w001001x.adf
</pre>
Sometimes datasets will also include a prj.adf files containing the projection
definition in the usual ESRI format. Grids also normally have associated
tables in the info directory. This is beyond the scope of my discussion
for now.<p>
The files have the following roles:
<ul>
<li> <a href="#dblbnd">dblbnd.adf</a>: Contains the bounds
(LLX, LLY, URX, URY) of the portion of utilized portion of the grid.<p>
<li> <a href="#hdr.adf">hdr.adf</a>: This is the header, and contains
information on the tile sizes, and number of tiles in the dataset. It also
contains assorted other information I have yet to identify.<p>
<li> <a href="#sta">sta.adf</a>: This contains raster statistics. In
particular, the raster min, max, mean and standard deviation.<p>
<li> <b>vat.adf</b>: This relates to the value attribute table. This is
the table corresponding integer raster values with a set of attributes. I
presume it is really just a pointer into info in a manner similar to the
pat.adf file in a vector coverage, but I haven't investigated yet. <p>
<li> <a href="#w001001">w001001.adf</a>:
This is the file containing the actual raster data.
<p>
<li> <a href="#w001001x">w001001x.adf</a>:
This is an index file containing pointers to
each of the tiles in the w001001.adf raster file.<p>
</ul>
<!--------------------------------------------------------------------------->
<hr>
<h2><a name="dblbnd">dblbnd.adf - Georef Bounds</a></h2>
Fields:<p>
<table border>
<th>Start Byte
<th># of Bytes
<th>Format
<th>Name
<th>Description
<tr>
<td> 0
</td><td> 8
</td><td> MSB double
</td><td> D_LLX
</td><td> Lower left X (easting) of the grid. Generally -0.5 for an
ungeoreferenced grid.
</td>
</tr>
<tr>
<td> 8
</td><td> 8
</td><td> MSB double
</td><td> D_LLY
</td><td> Lower left Y (northing) of the grid. Generally -0.5 for an
ungeoreferenced grid.
</td>
</tr>
<tr>
<td> 16
</td><td> 8
</td><td> MSB double
</td><td> D_URX
</td><td> Upper right X (easting) of the grid. Generally #Pixels-0.5 for an
ungeoreferenced grid.
</td>
</tr>
<tr>
<td> 24
</td><td> 8
</td><td> MSB double
</td><td> D_URY
</td><td> Upper right Y (northing) of the grid. Generally #Lines-0.5 for an
ungeoreferenced grid.
</td>
</tr>
</table>
This file is always 32 bytes long. The bounds apply to the portion of the
grid that is in use, not the whole thing.<p>
<!--------------------------------------------------------------------------->
<hr>
<h2><a name="w001001x">w001001x.adf - Tile Index</a></h2>
This is a binary dump of the first 320 bytes of a w001001x.adf
file. <p>
<pre>
0: 0000270A FFFFFC14 00000000 00000000 ~~'~~~~~~~~~~~~~
16: 00000000 00000000 00000BFA 00000000 ~~~~~~~~~~~~~~~~
32: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
48: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
64: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
80: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
96: 00000000 00000032 00000202 00000235 ~~~~~~~2~~~~~~~5
112: 000001D4 0000040A 00000000 0000040B ~~~~~~~~~~~~~~~~
128: 00000000 0000040C 00000000 0000040D ~~~~~~~~~~~~~~~~
144: 00000000 0000040E 00000000 0000040F ~~~~~~~~~~~~~~~~
160: 00000000 00000410 00000202 00000613 ~~~~~~~~~~~~~~~~
176: 000001D4 000007E8 00000000 000007E9 ~~~~~~~~~~~~~~~~
192: 00000000 000007EA 00000000 000007EB ~~~~~~~~~~~~~~~~
208: 00000000 000007EC 00000000 000007ED ~~~~~~~~~~~~~~~~
224: 00000000 000007EE 00000202 000009F1 ~~~~~~~~~~~~~~~~
240: 000001D4 00000BC6 00000000 00000BC7 ~~~~~~~~~~~~~~~~
256: 00000000 00000BC8 00000000 00000BC9 ~~~~~~~~~~~~~~~~
272: 00000000 00000BCA 00000000 00000BCB ~~~~~~~~~~~~~~~~
288: 00000000 00000BCC 00000202 00000DCF ~~~~~~~~~~~~~~~~
304: 000001D4 00000FA4 00000000 00000FA5 ~~~~~~~~~~~~~~~~
</pre>
Fields:<p>
<table border>
<th>Start Byte
<th># of Bytes
<th>Format
<th>Description
<tr>
<td> 0
</td><td> 8
</td><td>
</td><td> Magic Number (always hex 00 00 27 0A FF FF ** **, usually ending in FC 14, FB F8 or FC 08).
</td>
</tr>
<tr>
<td> 8
</td><td> 16
</td><td>
</td><td> zero fill
</td>
</tr>
<tr>
<td> 24
</td><td> 4
</td><td> MSB Int32
</td><td> Size of whole file in shorts (multiply by two
to get file size in bytes).
</td>
</tr>
<tr>
<td> 28
</td><td> 72
</td><td>
</td><td> zero fill
</td>
</tr>
<tr>
<td> 100 + <b>t</b>*8
</td><td> 4
</td><td> MSB Int32
</td><td> Offset to tile <b>t</b> in w001001.adf measured in two byte
shorts.
</td>
</tr>
<tr>
<td> 104 + <b>t</b>*8
</td><td> 4
</td><td> MSB Int32
</td><td> Size of tile <b>t</b> in 2 byte shorts.
</td>
</tr>
</table>
<!--------------------------------------------------------------------------->
<hr>
<h2><a name="sta">sta.adf - Raster Statistics</a></h2>
Fields:<p>
<table border>
<th>Start Byte
<th># of Bytes
<th>Format
<th>Name
<th>Description
<tr>
<td> 0
</td><td> 8
</td><td> MSB double
</td><td> SMin
</td><td> Minimum value of a raster cell in this grid.
</td>
</tr>
<tr>
<td> 8
</td><td> 8
</td><td> MSB double
</td><td> SMax
</td><td> Maximum value of a raster cell in this grid.
</td>
</tr>
<tr>
<td> 16
</td><td> 8
</td><td> MSB double
</td><td> SMean
</td><td> Mean value of a raster cells in this grid.
</td>
</tr>
<tr>
<td> 24
</td><td> 8
</td><td> MSB double
</td><td> SStdDev
</td><td> Standard deviation of raster cells in this grid.
</td>
</tr>
</table>
This file is always 32 bytes long. <p>
<!--------------------------------------------------------------------------->
<hr>
<h2><a name="w001001">w001001.adf - Raster Data</a></h2>
This is a binary dump of the first 320 bytes of a w001001.adf
file.<p>
<pre>
0: 0000270A FFFFFC14 00000000 00000000 ~~'~~~~~~~~~~~~~
16: 00000000 00000000 00016DAE 00000000 ~~~~~~~~~~m~~~~~
32: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
48: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
64: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
80: 00000000 00000000 00000000 00000000 ~~~~~~~~~~~~~~~~
96: 00000000 02020800 00373D42 5C5A4D31 ~~~~~~~~~7=B\ZM1
112: 200A0108 0E1D4F89 9C9A9392 8C7E6653 ~~~~~O~~~~~~~fS
128: 5151596D 83919290 868A8B87 807A7A7B QQYm~~~~~~~~~zz{
144: 7C7A766F 64481D00 0406305F 6B6C6A5B |zvodH~~~~0_klj[
160: 5D53513C 2D2D2732 24293F54 40354C55 ]SQ<--'2$)?T@5LU
176: 67686258 514E4943 5859534A 41394D70 ghbXQNICXYSJA9Mp
192: 75665659 66625A63 737A848E 9090979F ufVYfbZcsz~~~~~~
208: 9F908C8F 8F96998E 8778685B 53536274 ~~~~~~~~~xh[SSbt
224: 747B838A 8A8C8F92 8D979B94 8C8D9294 t{~~~~~~~~~~~~~~
240: 8D8D8D8D 8C8B8989 8B8E908F 8E8E9092 ~~~~~~~~~~~~~~~~
256: 90929394 989C9891 92939698 9B9B9C9C ~~~~~~~~~~~~~~~~
272: 8E8E8F8F 8E8E8F90 898E918F 8B8A8E93 ~~~~~~~~~~~~~~~~
288: 8B8D9093 94918C86 838DA1BC B7CEC9B0 ~~~~~~~~~~~~~~~~
304: D4B0BB96 A0929E99 9797999B 9D9C9C9B ~~~~~~~~~~~~~~~~
</pre>
Fields:<p>
<table border>
<th>Start Byte
<th># of Bytes
<th>Format
<th>Name
<th>Description
<tr>
<td> 0
</td><td> 8
</td><td>
</td><td> RMagic
</td><td> Magic Number (always hex 00 00 27 0A FF FF ** **, usually ending in FC 14, FB F8 or FC 08).
</td>
</tr>
<tr>
<td> 8
</td><td> 16
</td><td>
</td><td>
</td><td> zero fill
</td>
</tr>
<tr>
<td> 24
</td><td> 4
</td><td> MSB Int32
</td><td> RFileSize
</td><td> Size of whole file in shorts (multiply by two
to get file size in bytes).
</td>
</tr>
<tr>
<td> 28
</td><td> 72
</td><td>
</td><td>
</td><td> zero fill
</td>
</tr>
<tr>
<td> 100, ...
</td><td> 2
</td><td> MSB Int16
</td><td> RTileSize
</td><td> Size of this tiles data measured in shorts. This matches the size
in the index file, and does not include the tile size itself. The next
tile starts <b>2*n+2</b> bytes after the start of this tile, where <b>n</b>
is the value of this field.
</td>
</tr>
<tr>
<td> 102, ...
</td><td> 1
</td><td> byte
</td><td> RTileType
</td><td> Tile type code indicating the organization of the following
data (integer coverages only).
</td>
</tr>
<tr>
<td> 103, ...
</td><td> 1
</td><td> byte
</td><td> RMinSize
</td><td> Number of bytes following to form the minimum value for the tile
(integer coverages only).
</td>
</tr>
<tr>
<td> 104, ...
</td><td> (RMinSize bytes)
</td><td> MSB Int (var size)
</td><td> RMin
</td><td> The minimum value pixels for this tile. This number is added
to the pixel values for each pixel in this tile (integer coverages only).
I must stress that if RMinSize is less than 4 this is still a signed quantity.
For instance, if RMinSize is 2, the value is 65536 - byte0*256 - byte1 if
byte0 is &gt; 127.
</td>
</tr>
<tr>
<td> 104+RMinSize, ...
</td><td> RTileSize*2 - 3 - RMinSize
</td><td> variable
</td><td> RTileData
</td><td> The data for this tile. Format varies according to RTileType
for integer coverages.
</td>
</tr>
</table>
<p>
The fields RTileSize, RTileType, RMinSize, RMin, and RTileData occur in the
file for each tile of data present. They are usually packed one after the
other, but this isn't necessarily guaranteed. The index file (w001001x.adf)
should be used to establish the tile locations. Note that tiles that
appear in the index file with a size of zero will appear as just two
bytes (zeros) for the RTileSize for that tile.<p>
<!------------------------------------------>
<h3>Raster Size</h3>
The size of a the grid isn't as easy to deduce as one might expect.
The hdr.adf file contains the HTilesPerRow, HTilesPerColumn,
HTileXSize, and HTileYSize fields which imply a particular raster
space. However, it seems that this is created much larger than
necessary to hold the users raster data. I have created 3x1 rasters
which resulted in the standard 8x512 tiles of 256x4 pixels each.<p>
It seems that the user portion of the raster has to be computed
based on the georeferenced bounds in the dblbnd.adf file (assumed
to be anchored at the top left of the total raster space), and
the HPixelSizeX, and HPixelSizeY fields from hdr.adf.<p>
<b> #Pixels = (D_URX - D_LRX) / HPixelSizeX</b><p>
<b> #Lines = (D_URY - D_LRY) / HPixelSizeY</b><p>
Based on this number of pixels and lines, it is possible to establish
what portion out of the top left of the raster is really <i>of
interest</i>. All regions outside this appear to empty tiles,
or filled with no data markers.<p>
<!------------------------------------------>
<h3>RTileType/RTileData</h3>
Each tile contains HBlockXSize * HBlockYSize pixels of data. For floating
point and uncompressed integer files the data is just the tile size (in two
bytes) followed by the pixel data as 4 byte MSB order IEEE floating point
words. For compressed integer
tiles it is necessary to interpret the RTileType to establish the details
of the tile organization:
<h4>RTileType = 0x00 (constant block)</h4>
All pixels take the value of the RMin. Data is ignored. It appears there is
sometimes a bit of meaningless data (up to four bytes) in the block.<p>
<h4>RTileType = 0x01 (raw 1bit data)</h4>
One full tile worth of data pixel values follows the RMin field, with
1bit per pixel.<p>
<h4>RTileType = 0x04 (raw 4bit data)</h4>
One full tiles worth of data pixel values follows the RMin field, with
4 bits per pixel. The high order four bits of a byte comes before the low
order four bits.<p>
<h4>RTileType = 0x08 (raw byte data)</h4>
One full tiles worth of data pixel values (one byte per pixel) follows the
RMin field.<p>
<h4>RTileType = 0x10 (raw 16bit data)</h4>
One full tiles worth of data pixel values follows the RMin field, with
16 bits per pixel (MSB).<p>
<h4>RTileType = 0x20 (raw 32bit data)</h4>
One full tiles worth of data pixel values follows the RMin field, with
32 bits per pixel (MSB).<p>
<h4>RTileType = 0xCF (16 bit literal runs/nodata runs)</h4>
The data is organized in a series of runs. Each run starts with a marker
which should be interpreted as:
<ul>
<li> <b>Marker < 128</b>: The marker is followed by <b>Marker</b> pixels of
literal data with two MSB bytes per pixel. <p>
<li> <b>Marker > 127</b>: The marker indicates that <b>256-Marker</b> pixels
of <i>no data</i> pixels should be put into the output stream. No data
(other than the next marker) follows this marker.
</ul>
<h4>RTileType = 0xD7 (literal runs/nodata runs)</h4>
The data is organized in a series of runs. Each run starts with a marker
which should be interpreted as:
<ul>
<li> <b>Marker < 128</b>: The marker is followed by <b>Marker</b> pixels of
literal data with one byte per pixel. <p>
<li> <b>Marker > 127</b>: The marker indicates that <b>256-Marker</b> pixels
of <i>no data</i> pixels should be put into the output stream. No data
(other than the next marker) follows this marker.
</ul>
<h4>RTileType = 0xDF (RMin runs/nodata runs)</h4>
The data is organized in a series of runs. Each run starts with a marker
which should be interpreted as:
<ul>
<li> <b>Marker < 128</b>: The marker is followed by <b>Marker</b> pixels of
literal data with one byte per pixel. <p>
<li> <b>Marker > 127</b>: The marker indicates that <b>256-Marker</b> pixels
of <i>no data</i> pixels should be put into the output stream. No data
(other than the next marker) follows this marker.
</ul>
This is similar to 0xD7, except that the data size is zero bytes instead of
1, so only RMin values are inserted into the output stream.<p>
<h4>RTileType = 0xE0 (run length encoded 32bit)</h4>
The data is organized in a series of runs. Each run starts with a marker
which should be interpreted as a <b>count</b>. The four bytes following the
count should be interpreted as an MSB Int32 <b>value</b>. They indicate
that <b>count</b> pixels of <b>value</b> should be inserted into the output
stream.<p>
<h4>RTileType = 0xF0 (run length encoded 16bit)</h4>
The data is organized in a series of runs. Each run starts with a marker
which should be interpreted as a <b>count</b>. The two bytes following the
count should be interpreted as an MSB Int16 <b>value</b>. They indicate
that <b>count</b> pixels of <b>value</b> should be inserted into the output
stream.<p>
<h4>RTileType = 0xFC/0xF8 (run length encoded 8bit)</h4>
The data is organized in a series of runs. Each run starts with a marker
which should be interpreted as a <b>count</b>. The following byte is the
<b>value</b>. They indicate
that <b>count</b> pixels of <b>value</b> should be inserted into the output
stream.<p>
The intepretation is the same for 0xFC, and 0xF8. I believe that 0xFC has
a lower dynamic (2 bit) range than 0xF8 (4 or 8 bit).<p>
<h4>RTileType = 0xFF (RMin CCITT RLE 1Bit)</h4>
The data stream for this file is CCITT RLE (G1 fax) compressed. The
format is complex but source is provided with the sample program (derived
from libtiff) for reading it. The result of uncompressing is 1bit data so
which the RMin value should be added.<p>
<!--------------------------------------------------------------------------->
<hr>
<h2><a name="hdr.adf">hdr.adf - Header</a></h2>
This is a binary dump of the first 308 bytes of a hdr.adf
file.<p>
<pre>
0: 47524944 312E3200 00000000 FFFFFFFF GRID1.2~~~~~~~~~
16: 00000001 00000000 0000164E 3F800000 ~~~~~~~~~~~N?~~~
32: 00000F00 F6180000 90060000 3603D601 ~~~~~~~~~~~~6~~~
48: 6403E301 01000000 7620F808 43012B03 d~~~~~~~v ~~C~+~
64: D6019903 E3012B03 D6019903 E301F7BF ~~~~~~+~~~~~~~~~
80: 00007406 6E1FC2A4 7A370D00 0B004200 ~~t~n~~~z7~~~~B~
96: 4E1654A4 00000000 00000000 00000000 N~T~~~~~~~~~~~~~
112: 34A5A89D FF0414A5 A70F0002 00000000 4~~~~~~~~~~~~~~~
128: 00000000 3C0B5F06 A8C05F06 08005AC0 ~~~~<~_~~~_~~~Z~
144: 0A00E101 36035AC0 72085F06 FAA42F3C ~~~~6~Z~r~_~~~/<
160: 0A001667 02000E00 A80B0200 08370200 ~~~g~~~~~~~~~7~~
176: 0CA00200 9C0B0200 04370200 36A0E436 ~~~~~~~~~7~~6~~6
192: 84000000 36A00200 5F063EA5 0883FF04 ~~~~6~~~_~>~~~~~
208: 00008400 00000010 BD810200 5F010000 ~~~~~~~~~~~~_~~~
224: 670E0000 5F01560E 4C4F0001 84008CA5 g~~~_~V~LO~~~~~~
240: 28008F01 1000E00A 6628F7BF 4076FF04 (~~~~~~~f(~~@v~~
256: 3FF00000 00000000 3FF00000 00000000 ?~~~~~~~?~~~~~~~
272: C08FFC00 00000000 C0A1BF00 00000000 ~~~~~~~~~~~~~~~~
288: 00000008 00000200 00000100 00000001 ~~~~~~~~~~~~~~~~
304: 00000004 ~~~~
</pre>
Fields:<p>
<table border>
<th>Start Byte
<th># of Bytes
<th>Format
<th>Name
<th>Description
<tr>
<td> 0
</td><td> 8
</td><td> Char
</td><td> HMagic
</td><td> Magic Number - always "GRID1.2\0"
</td>
</tr>
<tr>
<td> 8
</td><td> 8
</td><td> &nbsp;
</td><td> &nbsp;
</td><td> assorted data, I don't know the purpose.
</td>
</tr>
<tr>
<td> 16
</td><td> 4
</td><td> MSB Int32
</td><td> HCellType
</td><td> 1 = int cover, 2 = float cover.
</td>
</tr>
<tr>
<td> 20
</td><td> 4
</td><td> MSB Int32
</td><td> CompFlag
</td><td> 0 = compressed, 1 = uncompressed
</td>
</tr>
<tr>
<td> 24
</td><td> 232
</td><td> &nbsp;
</td><td> &nbsp;
</td><td> assorted data, I don't know the purpose.
</td>
</tr>
<tr>
<td> 256
</td><td> 8
</td><td> MSB Double
</td><td> HPixelSizeX
</td><td> Width of a pixel in georeferenced coordinates. Generally 1.0
for ungeoreferenced rasters.
</td>
</tr>
<tr>
<td> 264
</td><td> 8
</td><td> MSB Double
</td><td> HPixelSizeY
</td><td> Height of a pixel in georeferenced coordinates. Generally 1.0
for ungeoreferenced rasters.
</td>
</tr>
<tr>
<td> 272
</td><td> 8
</td><td> MSB Double
</td><td> XRef
</td><td> dfLLX-(nBlocksPerRow*nBlockXSize*dfCellSizeX)/2.0
</td>
</tr>
<tr>
<td> 280
</td><td> 8
</td><td> MSB Double
</td><td> YRef
</td><td> dfURY-(3*nBlocksPerColumn*nBlockYSize*dfCellSizeY)/2.0
</td>
</tr>
<tr>
<td> 288
</td><td> 4
</td><td> MSB Int32
</td><td> HTilesPerRow
</td><td> The width of the file in tiles (often 8 for files of
less than 2K in width).
</td>
</tr>
<tr>
<td> 292
</td><td> 4
</td><td> MSB Int32
</td><td> HTilesPerColumn
</td><td> The height of the file in tiles. Note this may be much more than
the number of tiles actually represented in the index file.<p>
</td>
</tr>
<tr>
<td> 296
</td><td> 4
</td><td> MSB Int32
</td><td> HTileXSize
</td><td> The width of a file in pixels. Normally 256. </td>
</tr>
<tr>
<td> 300
</td><td> 4
</td><td> MSB Int32
</td><td>
</td><td> Unknown, usually 1.
</tr>
<tr>
<td> 304
</td><td> 4
</td><td> MSB Int32
</td><td> HTileYSize
</td><td> Height of a tile in pixels, usually 4.
</tr>
</table>
<!--------------------------------------------------------------------------->
<hr>
<h2>Acknowledgements</h2>
I would like to thank <a href="http://www.geosoft.com/">Geosoft Inc.</a>
for partial funding of my research into this
format. I would also like to thank:<p>
<ul>
<li> Kenneth R. McVay for providing the statistics file format.
<li> Noureddine Farah of ThinkSpace who dug up lots of datasets that caused
problems.
<li> Luciano Fonseca who worked out RTileType 0x01.
<li> Martin Manningham of Global Geomatics for additional problem sample files.
<li> Harry Anderson of EDX Engineering, for showing me that floating point
tiles don't have RTileType.
<li> Ian Turton for supplying a sample files demonstrating the need to be
careful with the sign of "short" RMin values.
<li> Duncan Chaundy at PCI for poking hard till I finally deduced 0xFF tiles.
<li> Stephen Cheeseman of GeoSoft for yet more problem files.
<li> Geoffrey Williams for a files demonstrating tile type 0x20.
</ul>
</body>
</html>

View file

@ -0,0 +1,246 @@
/******************************************************************************
* $Id: aitest.c 28039 2014-11-30 18:24:59Z rouault $
*
* Project: Arc/Info Binary Grid Translator
* Purpose: Test mainline for examining AIGrid files.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* 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 "aigrid.h"
CPL_CVSID("$Id: aitest.c 28039 2014-11-30 18:24:59Z rouault $");
/************************************************************************/
/* DumpMagic() */
/* */
/* Dump the magic ``block type byte'' for each existing block. */
/************************************************************************/
static void DumpMagic( AIGInfo_t * psInfo, int bVerbose )
{
int i;
AIGTileInfo *psTInfo = psInfo->pasTileInfo + 0;
for( i = 0; i < psTInfo->nBlocks; i++ )
{
GByte byMagic;
int bReport = bVerbose;
unsigned char abyBlockSize[2];
const char *pszMessage = "";
if( psTInfo->panBlockSize[i] == 0 )
continue;
VSIFSeekL( psTInfo->fpGrid, psTInfo->panBlockOffset[i], SEEK_SET );
VSIFReadL( abyBlockSize, 2, 1, psTInfo->fpGrid );
if( psInfo->nCellType == AIG_CELLTYPE_INT && psInfo->bCompressed )
{
VSIFReadL( &byMagic, 1, 1, psTInfo->fpGrid );
if( byMagic != 0 && byMagic != 0x43 && byMagic != 0x04
&& byMagic != 0x08 && byMagic != 0x10 && byMagic != 0xd7
&& byMagic != 0xdf && byMagic != 0xe0 && byMagic != 0xfc
&& byMagic != 0xf8 && byMagic != 0xff && byMagic != 0x41
&& byMagic != 0x40 && byMagic != 0x42 && byMagic != 0xf0
&& byMagic != 0xcf && byMagic != 0x01 )
{
pszMessage = "(unhandled magic number)";
bReport = TRUE;
}
if( byMagic == 0 && psTInfo->panBlockSize[i] > 8 )
{
pszMessage = "(wrong size for 0x00 block, should be 8 bytes)";
bReport = TRUE;
}
if( (abyBlockSize[0] * 256 + abyBlockSize[1])*2 !=
psTInfo->panBlockSize[i] )
{
pszMessage = "(block size in data doesn't match index)";
bReport = TRUE;
}
}
else
{
if( psTInfo->panBlockSize[i] !=
psInfo->nBlockXSize*psInfo->nBlockYSize*sizeof(float) )
{
pszMessage = "(floating point block size is wrong)";
bReport = TRUE;
}
}
if( bReport )
{
printf( " %02x %5d %5d @ %d %s\n", byMagic, i,
psTInfo->panBlockSize[i],
psTInfo->panBlockOffset[i],
pszMessage );
}
}
}
/************************************************************************/
/* main() */
/************************************************************************/
int main( int argc, char ** argv )
{
AIGInfo_t *psInfo;
GInt32 *panRaster;
int i, j;
int bMagic = FALSE, bSuppressMagic = FALSE;
int iTestTileX = 0, iTestTileY = 0;
/* -------------------------------------------------------------------- */
/* Process arguments. */
/* -------------------------------------------------------------------- */
while( argc > 1 && argv[1][0] == '-' )
{
if( EQUAL(argv[1],"-magic") )
bMagic = TRUE;
else if( EQUAL(argv[1],"-nomagic") )
bSuppressMagic = TRUE;
else if( EQUAL(argv[1],"-t") && argc > 2 )
{
iTestTileX = atoi(argv[2]);
iTestTileY = atoi(argv[3]);
argc -= 2;
argv += 2;
}
argc--;
argv++;
}
if( argc < 2 ) {
printf( "Usage: aitest [-magic] coverage [block numbers...]\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Open dataset. */
/* -------------------------------------------------------------------- */
psInfo = AIGOpen( argv[1], "r" );
if( psInfo == NULL )
exit( 1 );
AIGAccessTile( psInfo, iTestTileX, iTestTileY );
/* -------------------------------------------------------------------- */
/* Dump general information */
/* -------------------------------------------------------------------- */
printf( "%d pixels x %d lines.\n", psInfo->nPixels, psInfo->nLines );
printf( "Lower Left = (%f,%f) Upper Right = (%f,%f)\n",
psInfo->dfLLX,
psInfo->dfLLY,
psInfo->dfURX,
psInfo->dfURY );
if( psInfo->nCellType == AIG_CELLTYPE_INT )
printf( "%s Integer coverage, %dx%d blocks.\n",
psInfo->bCompressed ? "Compressed" : "Uncompressed",
psInfo->nBlockXSize, psInfo->nBlockYSize );
else
printf( "%s Floating point coverage, %dx%d blocks.\n",
psInfo->bCompressed ? "Compressed" : "Uncompressed",
psInfo->nBlockXSize, psInfo->nBlockYSize );
printf( "Stats - Min=%f, Max=%f, Mean=%f, StdDev=%f\n",
psInfo->dfMin,
psInfo->dfMax,
psInfo->dfMean,
psInfo->dfStdDev );
/* -------------------------------------------------------------------- */
/* Do we want a dump of all the ``magic'' numbers for */
/* instantated blocks? */
/* -------------------------------------------------------------------- */
if( !bSuppressMagic )
DumpMagic( psInfo, bMagic );
/* -------------------------------------------------------------------- */
/* Read a block, and report it's contents. */
/* -------------------------------------------------------------------- */
panRaster = (GInt32 *)
CPLMalloc(psInfo->nBlockXSize * psInfo->nBlockYSize * 4);
while( argc > 2 && (atoi(argv[2]) > 0 || argv[2][0] == '0') )
{
int nBlock = atoi(argv[2]);
CPLErr eErr;
AIGTileInfo *psTInfo = psInfo->pasTileInfo + 0;
argv++;
argc--;
eErr = AIGReadBlock( psTInfo->fpGrid,
psTInfo->panBlockOffset[nBlock],
psTInfo->panBlockSize[nBlock],
psInfo->nBlockXSize, psInfo->nBlockYSize,
panRaster, psInfo->nCellType, psInfo->bCompressed);
printf( "\nBlock %d:\n", nBlock );
if( eErr != CE_None )
{
printf( " Error! Skipping block.\n" );
continue;
}
for( j = 0; j < psInfo->nBlockYSize; j++ )
{
for( i = 0; i < psInfo->nBlockXSize; i++ )
{
if( i > 18 )
{
printf( "..." );
break;
}
if( panRaster[i+j*psInfo->nBlockXSize] == ESRI_GRID_NO_DATA )
printf( "-*- " );
else if( psInfo->nCellType == AIG_CELLTYPE_FLOAT )
printf( "%f ",
((float *) panRaster)[i+j*psInfo->nBlockXSize] );
else
printf( "%3d ", panRaster[i+j*psInfo->nBlockXSize] );
}
printf( "\n" );
}
}
CPLFree( panRaster );
AIGClose( psInfo );
exit( 0 );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
OBJ = aigdataset.obj aigopen.obj gridlib.obj aigccitt.obj
EXTRAFLAGS = -I../../ogr/ogrsf_frmts/avc
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
all: $(OBJ) aitest.exe
aitest.exe: $(OBJ) aitest.c
$(CC) $(CFLAGS) aitest.c aigopen.obj gridlib.obj \
$(GDAL_ROOT)/port/cpl.lib
clean:
-del *.obj

View file

@ -0,0 +1,13 @@
include ../../GDALmake.opt
OBJ = airsardataset.o
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o $(O_OBJ)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

View file

@ -0,0 +1,673 @@
/******************************************************************************
* $Id: airsardataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: AirSAR Reader
* Purpose: Implements read support for AirSAR Polarimetric data.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2007-2009, 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 "cpl_string.h"
#include "cpl_conv.h"
#include "cpl_vsi.h"
CPL_CVSID("$Id: airsardataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
CPL_C_START
void GDALRegister_AirSAR(void);
CPL_C_END
/************************************************************************/
/* ==================================================================== */
/* AirSARDataset */
/* ==================================================================== */
/************************************************************************/
class AirSARRasterBand;
class AirSARDataset : public GDALPamDataset
{
friend class AirSARRasterBand;
VSILFILE *fp;
int nLoadedLine;
GByte *pabyCompressedLine;
double *padfMatrix;
int nDataStart;
int nRecordLength;
CPLErr LoadLine(int iLine);
static char **ReadHeader( VSILFILE * fp, int nFileOffset,
const char *pszPrefix, int nMaxLines );
public:
AirSARDataset();
~AirSARDataset();
static GDALDataset *Open( GDALOpenInfo * );
};
/************************************************************************/
/* ==================================================================== */
/* AirSARRasterBand */
/* ==================================================================== */
/************************************************************************/
class AirSARRasterBand : public GDALPamRasterBand
{
public:
AirSARRasterBand( AirSARDataset *, int );
virtual ~AirSARRasterBand();
virtual CPLErr IReadBlock( int, int, void * );
};
/* locations of stokes matrix values within padfMatrix ... same order as they
are computed in the document. */
#define M11 0
#define M12 1
#define M13 2
#define M14 3
#define M23 4
#define M24 5
#define M33 6
#define M34 7
#define M44 8
#define M22 9
/************************************************************************/
/* AirSARRasterBand() */
/************************************************************************/
AirSARRasterBand::AirSARRasterBand( AirSARDataset *poDS,
int nBand )
{
this->poDS = poDS;
this->nBand = nBand;
nBlockXSize = poDS->GetRasterXSize();
nBlockYSize = 1;
if( this->nBand == 2 || this->nBand == 3 || this->nBand == 5 )
eDataType = GDT_CFloat32;
else
eDataType = GDT_Float32;
switch( nBand )
{
case 1:
SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_11" );
SetDescription( "Covariance_11" );
eDataType = GDT_CFloat32;
break;
case 2:
SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_12" );
SetDescription( "Covariance_12" );
eDataType = GDT_CFloat32;
break;
case 3:
SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_13" );
SetDescription( "Covariance_13" );
eDataType = GDT_CFloat32;
break;
case 4:
SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_22" );
SetDescription( "Covariance_22" );
eDataType = GDT_CFloat32;
break;
case 5:
SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_23" );
SetDescription( "Covariance_23" );
eDataType = GDT_CFloat32;
break;
case 6:
SetMetadataItem( "POLARIMETRIC_INTERP", "Covariance_33" );
SetDescription( "Covariance_33" );
eDataType = GDT_CFloat32;
break;
}
}
/************************************************************************/
/* ~AirSARRasterBand() */
/************************************************************************/
AirSARRasterBand::~AirSARRasterBand()
{
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr AirSARRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
int nBlockYOff,
void * pImage )
{
CPLErr eErr;
float *pafLine = (float *) pImage;
int iPixel;
double *padfMatrix;
eErr = ((AirSARDataset *)poDS)->LoadLine( nBlockYOff );
if( eErr != CE_None )
return eErr;
padfMatrix = ((AirSARDataset *) poDS)->padfMatrix;
#define SQRT_2 1.4142135623730951
if( nBand == 1 ) /* C11 */
{
for( iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *m = padfMatrix + 10 * iPixel;
pafLine[iPixel*2+0] = (float)(m[M11] + m[M22] + 2 * m[M12]);
pafLine[iPixel*2+1] = 0.0;
}
}
else if( nBand == 2 ) /* C12 */
{
for( iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *m = padfMatrix + 10 * iPixel;
// real
pafLine[iPixel*2 + 0] = (float)(SQRT_2 * (m[M13] + m[M23]));
// imaginary
pafLine[iPixel*2 + 1] = (float)(- SQRT_2 * (m[M24] + m[M14]));
}
}
else if( nBand == 3 ) /* C13 */
{
for( iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *m = padfMatrix + 10 * iPixel;
// real
pafLine[iPixel*2 + 0] = (float)(2*m[M33] + m[M22] - m[M11]);
// imaginary
pafLine[iPixel*2 + 1] = (float)(-2 * m[M34]);
}
}
else if( nBand == 4 ) /* C22 */
{
for( iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *m = padfMatrix + 10 * iPixel;
pafLine[iPixel*2+0] = (float)(2 * (m[M11] - m[M22]));
pafLine[iPixel*2+1] = 0.0;
}
}
else if( nBand == 5 ) /* C23 */
{
for( iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *m = padfMatrix + 10 * iPixel;
// real
pafLine[iPixel*2 + 0] = (float)(SQRT_2 * (m[M13] - m[M23]));
// imaginary
pafLine[iPixel*2 + 1] = (float)(SQRT_2 * (m[M23] - m[M14]));
}
}
else if( nBand == 6 ) /* C33 */
{
for( iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *m = padfMatrix + 10 * iPixel;
pafLine[iPixel*2+0] = (float)(m[M11] + m[M22] - 2 * m[M12]);
pafLine[iPixel*2+1] = 0.0;
}
}
return CE_None;
}
/************************************************************************/
/* ==================================================================== */
/* AirSARDataset */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* AirSARDataset() */
/************************************************************************/
AirSARDataset::AirSARDataset()
{
fp = NULL;
nLoadedLine = -1;
pabyCompressedLine = NULL;
padfMatrix = NULL;
}
/************************************************************************/
/* ~AirSARDataset() */
/************************************************************************/
AirSARDataset::~AirSARDataset()
{
FlushCache();
if( pabyCompressedLine != NULL )
{
CPLFree( pabyCompressedLine );
CPLFree( padfMatrix );
}
if( fp != NULL )
{
VSIFCloseL( fp );
fp = NULL;
}
}
/************************************************************************/
/* LoadLine() */
/************************************************************************/
CPLErr AirSARDataset::LoadLine( int iLine )
{
if( iLine == nLoadedLine )
return CE_None;
/* -------------------------------------------------------------------- */
/* allocate working buffers if we don't have them already. */
/* -------------------------------------------------------------------- */
if( pabyCompressedLine == NULL )
{
pabyCompressedLine = (GByte *) VSIMalloc2(nRasterXSize, 10);
padfMatrix = (double *) VSIMalloc2(10* sizeof(double), nRasterXSize);
if (pabyCompressedLine == NULL ||
padfMatrix == NULL)
{
CPLError(CE_Failure, CPLE_OutOfMemory,
"AirSARDataset::LoadLine : Out of memory. "
"Probably due to corrupted dataset (nRasterXSize = %d)",
nRasterXSize);
CPLFree (pabyCompressedLine);
CPLFree (padfMatrix);
return CE_Failure;
}
}
CPLAssert( nRecordLength == nRasterXSize * 10 );
/* -------------------------------------------------------------------- */
/* Load raw compressed data. */
/* -------------------------------------------------------------------- */
if( VSIFSeekL( fp, nDataStart + iLine * nRecordLength, SEEK_SET ) != 0
|| ((int) VSIFReadL( pabyCompressedLine, 10, nRasterXSize, fp ))
!= nRasterXSize )
{
CPLError( CE_Failure, CPLE_FileIO,
"Error reading %d bytes for line %d at offset %d.\n%s",
nRasterXSize * 10, iLine, nDataStart + iLine * nRecordLength,
VSIStrerror( errno ) );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Build stokes matrix */
/* -------------------------------------------------------------------- */
for( int iPixel = 0; iPixel < nRasterXSize; iPixel++ )
{
double *M = padfMatrix + 10 * iPixel;
signed char *byte = (signed char *) pabyCompressedLine + 10*iPixel - 1;
double gen_fac = 1.0; // should we have a general scale factor?
M[M11] = (byte[2] / 254.0 + 1.5) * pow(2.0,byte[1]) * gen_fac;
M[M12] = byte[3] * M[M11] / 127.0;
M[M13] = byte[4] * fabs((double) byte[4]) * M[M11] / (127*127);
M[M14] = byte[5] * fabs((double) byte[5]) * M[M11] / (127*127);
M[M23] = byte[6] * fabs((double) byte[6]) * M[M11] / (127*127);
M[M24] = byte[7] * fabs((double) byte[7]) * M[M11] / (127*127);
M[M33] = byte[8] * M[M11] / 127;
M[M34] = byte[9] * M[M11] / 127;
M[M44] = byte[10] * M[M11] / 127;
M[M22] = M[M11] - M[M33] - M[M44];
}
return CE_None;
}
/************************************************************************/
/* ReadHeader() */
/* */
/* Read the AirSAR header. We assume an equal sign seperates */
/* the keyword name from the value. If not, assume the last */
/* "blank delimited" word is the value and everything else is a */
/* keyword. */
/* */
/* The records are 50 characters each. Read till we get an all */
/* blank record or some zero bytes. */
/************************************************************************/
char ** AirSARDataset::ReadHeader( VSILFILE * fp, int nFileOffset,
const char *pszPrefix, int nMaxLines )
{
char **papszHeadInfo = NULL;
char szLine[51];
int iLine;
VSIFSeekL( fp, nFileOffset, SEEK_SET );
/* ==================================================================== */
/* Loop collecting one line at a time. */
/* ==================================================================== */
for( iLine = 0; iLine < nMaxLines; iLine++ )
{
/* -------------------------------------------------------------------- */
/* Read a 50 byte header record. */
/* -------------------------------------------------------------------- */
if( VSIFReadL( szLine, 1, 50, fp ) != 50 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Read error collecting AirSAR header." );
return NULL;
}
szLine[50] = '\0';
/* -------------------------------------------------------------------- */
/* Is it all spaces, or does it have a zero byte? */
/* -------------------------------------------------------------------- */
int bAllSpaces = TRUE;
int bHasIllegalChars = FALSE;
int i;
for( i = 0; i < 50; i++ )
{
if( szLine[i] == '\0' )
break;
if( szLine[i] != ' ' )
bAllSpaces = FALSE;
if( ((unsigned char *) szLine)[i] > 127
|| ((unsigned char *) szLine)[i] < 10 )
bHasIllegalChars = TRUE;
}
if( bAllSpaces || bHasIllegalChars )
break;
/* -------------------------------------------------------------------- */
/* Find the pivot between the keyword name and value. */
/* -------------------------------------------------------------------- */
int iPivot = -1;
for( i = 0; i < 50; i++ )
{
if( szLine[i] == '=' )
{
iPivot = i;
break;
}
}
// If no "=" found, split on first double white space
if( iPivot == -1 )
{
for( i = 48; i >= 0; i-- )
{
if( szLine[i] == ' ' && szLine[i+1] == ' ' )
{
iPivot = i;
break;
}
}
}
if( iPivot == -1 ) // Yikes!
{
CPLDebug( "AIRSAR", "No pivot in line `%s'.",
szLine );
CPLAssert( iPivot != -1 );
break;
}
/* -------------------------------------------------------------------- */
/* Trace ahead to the first non-white space value character. */
/* -------------------------------------------------------------------- */
int iValue = iPivot + 1;
while( iValue < 50 && szLine[iValue] == ' ' )
iValue++;
/* -------------------------------------------------------------------- */
/* Strip any white space off the keyword. */
/* -------------------------------------------------------------------- */
int iKeyEnd = iPivot - 1;
while( iKeyEnd > 0 && szLine[iKeyEnd] == ' ' )
iKeyEnd--;
szLine[iKeyEnd+1] = '\0';
/* -------------------------------------------------------------------- */
/* Convert spaces or colons into underscores in the key name. */
/* -------------------------------------------------------------------- */
for( i = 0; szLine[i] != '\0'; i++ )
{
if( szLine[i] == ' ' || szLine[i] == ':' || szLine[i] == ',' )
szLine[i] = '_';
}
/* -------------------------------------------------------------------- */
/* Prefix key name with provided prefix string. */
/* -------------------------------------------------------------------- */
char szPrefixedKeyName[55];
sprintf( szPrefixedKeyName, "%s_%s", pszPrefix, szLine );
papszHeadInfo =
CSLSetNameValue( papszHeadInfo, szPrefixedKeyName, szLine+iValue );
}
return papszHeadInfo;
}
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *AirSARDataset::Open( GDALOpenInfo * poOpenInfo )
{
if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 800 )
return NULL;
/* -------------------------------------------------------------------- */
/* Check for AirSAR/ keyword. */
/* -------------------------------------------------------------------- */
if( !EQUALN((char *) poOpenInfo->pabyHeader, "RECORD LENGTH IN BYTES",22) )
return NULL;
if( strstr((char *) poOpenInfo->pabyHeader, "COMPRESSED") == NULL
|| strstr((char *) poOpenInfo->pabyHeader, "JPL AIRCRAFT") == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Parse the header fields. We turn all the transform the */
/* keywords by converting spaces to underscores so they will be */
/* "well behaved" as metadata keywords. */
/* -------------------------------------------------------------------- */
char **papszMD = ReadHeader( poOpenInfo->fpL, 0, "MH", 20 );
if( papszMD == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Confirm the requested access is supported. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->eAccess == GA_Update )
{
CPLError( CE_Failure, CPLE_NotSupported,
"The AIRSAR driver does not support update access to existing"
" datasets.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
AirSARDataset *poDS;
poDS = new AirSARDataset();
/* -------------------------------------------------------------------- */
/* Extract some key information. */
/* -------------------------------------------------------------------- */
poDS->nRasterXSize =
atoi(CSLFetchNameValue(papszMD,"MH_NUMBER_OF_SAMPLES_PER_RECORD"));
poDS->nRasterYSize =
atoi(CSLFetchNameValue(papszMD,"MH_NUMBER_OF_LINES_IN_IMAGE"));
poDS->nRecordLength = atoi(
CSLFetchNameValue( papszMD, "MH_RECORD_LENGTH_IN_BYTES" ) );
poDS->nDataStart = atoi(
CSLFetchNameValue( papszMD, "MH_BYTE_OFFSET_OF_FIRST_DATA_RECORD" ));
/* -------------------------------------------------------------------- */
/* Adopt the openinfo file pointer. */
/* -------------------------------------------------------------------- */
poDS->fp = poOpenInfo->fpL;
poOpenInfo->fpL = NULL;
/* -------------------------------------------------------------------- */
/* Read and merge parameter header into metadata. Prefix */
/* parameter header values with PH_. */
/* -------------------------------------------------------------------- */
int nPHOffset = 0;
if( CSLFetchNameValue( papszMD,
"MH_BYTE_OFFSET_OF_PARAMETER_HEADER" ) != NULL )
{
nPHOffset = atoi(CSLFetchNameValue(
papszMD, "MH_BYTE_OFFSET_OF_PARAMETER_HEADER"));
char **papszPHInfo = ReadHeader( poDS->fp, nPHOffset, "PH", 100 );
papszMD = CSLInsertStrings( papszMD, CSLCount(papszMD), papszPHInfo );
CSLDestroy( papszPHInfo );
}
/* -------------------------------------------------------------------- */
/* Read and merge calibration header into metadata. Prefix */
/* parameter header values with CH_. */
/* -------------------------------------------------------------------- */
if( nPHOffset != 0 )
{
char **papszCHInfo = ReadHeader( poDS->fp,
nPHOffset+poDS->nRecordLength,
"CH", 18 );
papszMD = CSLInsertStrings( papszMD, CSLCount(papszMD), papszCHInfo );
CSLDestroy( papszCHInfo );
}
/* -------------------------------------------------------------------- */
/* Assign metadata to dataset. */
/* -------------------------------------------------------------------- */
poDS->SetMetadata( papszMD );
CSLDestroy( papszMD );
/* -------------------------------------------------------------------- */
/* Create band information objects. */
/* -------------------------------------------------------------------- */
poDS->SetBand( 1, new AirSARRasterBand( poDS, 1 ));
poDS->SetBand( 2, new AirSARRasterBand( poDS, 2 ));
poDS->SetBand( 3, new AirSARRasterBand( poDS, 3 ));
poDS->SetBand( 4, new AirSARRasterBand( poDS, 4 ));
poDS->SetBand( 5, new AirSARRasterBand( poDS, 5 ));
poDS->SetBand( 6, new AirSARRasterBand( poDS, 6 ));
poDS->SetMetadataItem( "MATRIX_REPRESENTATION", "SYMMETRIZED_COVARIANCE" );
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
return( poDS );
}
/************************************************************************/
/* GDALRegister_AirSAR() */
/************************************************************************/
void GDALRegister_AirSAR()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "AirSAR" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "AirSAR" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"AirSAR Polarimetric Image" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_airsar.html" );
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->pfnOpen = AirSARDataset::Open;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}

View file

@ -0,0 +1,57 @@
<html>
<head>
<title>AIRSAR -- AIRSAR Polarimetric Format</title>
</head>
<body bgcolor="#ffffff">
<h1>AIRSAR -- AIRSAR Polarimetric Format</h1>
Most variants of the AIRSAR Polarimetric Format produced by the AIRSAR
Integrated Processor are supported for reading by GDAL. AIRSAR products
normally include various associated data files, but only the imagery
data themselves is supported. Normally these are named <i>mission</i>_l.dat
(L-Band) or <i>mission</i>_c.dat (C-Band).<p>
AIRSAR format contains a polarimetric image in compressed stokes matrix form.
Internally GDAL decompresses the data into a stokes matrix, and then converts
that form into a covariance matrix. The returned six bands are the six values
needed to define the 3x3 Hermitian covariance matrix. The convention used
to represent the covariance matrix in terms of the scattering matrix
elements HH, HV (=VH), and VV is indicated below. Note that the
non-diagonal elements of the matrix are complex values, while the diagonal
values are real (though represented as complex bands).<p>
<ul>
<li> Band 1: Covariance_11 (Float32) = HH*conj(HH)
<li> Band 2: Covariance_12 (CFloat32) = sqrt(2)*HH*conj(HV)
<li> Band 3: Covariance_13 (CFloat32) = HH*conj(VV)
<li> Band 4: Covariance_22 (Float32) = 2*HV*conj(HV)
<li> Band 5: Covariance_23 (CFloat32) = sqrt(2)*HV*conj(VV)
<li> Band 6: Covariance_33 (Float32) = VV*conj(VV)
</ul>
The identities of the bands are also reflected in metadata and in the band
descriptions. <p>
The AIRSAR product format includes (potentially) several headers of
information. This information is captured and represented as metadata on the
file as a whole. Information items from the main header are prefixed with
"MH_", items from the parameter header are prefixed with "PH_" and
information from the calibration header are prefixed with "CH_".
The metadata item names are derived automatically from the names of the
fields within the header itself. <p>
No effort is made to read files associated with the AIRSAR product such as
<i>mission</i>_l.mocomp, <i>mission</i>_meta.airsar or
<i>mission</i>_meta.podaac.<p>
See Also:<p>
<ul>
<li> <a href="http://airsar.jpl.nasa.gov/documents/dataformat.htm">AIRSAR Data Format</a>
</ul>
</body>
</html>

View file

@ -0,0 +1,13 @@
OBJ = airsardataset.obj
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,14 @@
include ../../GDALmake.opt
OBJ = argdataset.o
CPPFLAGS := $(JSON_INCLUDE) -I../raw $(CPPFLAGS)
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o $(O_OBJ)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

View file

@ -0,0 +1,850 @@
/******************************************************************************
* $Id: argdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
*
* Project: Azavea Raster Grid format driver.
* Purpose: Implements support for reading and writing Azavea Raster Grid
* format.
* Author: David Zwarg <dzwarg@azavea.com>
*
******************************************************************************
* Copyright (c) 2012, David Zwarg <dzwarg@azavea.com>
* Copyright (c) 2012-2013, 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 "rawdataset.h"
#include "cpl_string.h"
#include <json.h>
#include <ogr_spatialref.h>
CPL_CVSID("$Id: argdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
#define MAX_FILENAME_LEN 4096
#ifndef NAN
# ifdef HUGE_VAL
# define NAN (HUGE_VAL * 0.0)
# else
static float CPLNaN(void)
{
float fNan;
int nNan = 0x7FC00000;
memcpy(&fNan, &nNan, 4);
return fNan;
}
# define NAN CPLNaN()
# endif
#endif
/************************************************************************/
/* ==================================================================== */
/* ARGDataset */
/* ==================================================================== */
/************************************************************************/
class ARGDataset : public RawDataset
{
VSILFILE *fpImage; // image data file.
double adfGeoTransform[6];
char * pszFilename;
public:
ARGDataset();
~ARGDataset();
CPLErr GetGeoTransform( double * padfTransform );
static int Identify( GDALOpenInfo * );
static GDALDataset *Open( GDALOpenInfo * );
static GDALDataset *CreateCopy( const char *, GDALDataset *, int,
char **, GDALProgressFunc, void *);
virtual char ** GetFileList(void);
};
/************************************************************************/
/* ARGDataset() */
/************************************************************************/
ARGDataset::ARGDataset()
{
adfGeoTransform[0] = 0.0;
adfGeoTransform[1] = 1.0;
adfGeoTransform[2] = 0.0;
adfGeoTransform[3] = 0.0;
adfGeoTransform[4] = 0.0;
adfGeoTransform[5] = 1.0;
fpImage = NULL;
}
/************************************************************************/
/* ~ARGDataset() */
/************************************************************************/
ARGDataset::~ARGDataset()
{
CPLFree(pszFilename);
FlushCache();
if( fpImage != NULL )
VSIFCloseL( fpImage );
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr ARGDataset::GetGeoTransform( double * padfTransform )
{
memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
return CE_None;
}
/************************************************************************/
/* GetJsonFilename() */
/************************************************************************/
CPLString GetJsonFilename(CPLString pszFilename)
{
return CPLSPrintf( "%s/%s.json", CPLGetDirname(pszFilename), CPLGetBasename(pszFilename) );
}
/************************************************************************/
/* GetJsonObject() */
/************************************************************************/
json_object * GetJsonObject(CPLString pszFilename)
{
json_object * pJSONObject = NULL;
CPLString osJSONFilename = GetJsonFilename(pszFilename);
pJSONObject = json_object_from_file((char *)osJSONFilename.c_str());
if (pJSONObject == NULL) {
CPLDebug("ARGDataset", "GetJsonObject(): "
"Could not parse JSON file.");
return NULL;
}
return pJSONObject;
}
/************************************************************************/
/* GetJsonValueStr() */
/************************************************************************/
const char * GetJsonValueStr(json_object * pJSONObject, CPLString pszKey)
{
json_object * pJSONItem = json_object_object_get(pJSONObject, pszKey.c_str());
if (pJSONItem == NULL) {
CPLDebug("ARGDataset", "GetJsonValueStr(): "
"Could not find '%s' in JSON.", pszKey.c_str());
return NULL;
}
return json_object_get_string(pJSONItem);
}
/************************************************************************/
/* GetJsonValueDbl() */
/************************************************************************/
double GetJsonValueDbl(json_object * pJSONObject, CPLString pszKey)
{
const char *pszJSONStr = GetJsonValueStr(pJSONObject, pszKey.c_str());
char *pszTmp;
double fTmp;
if (pszJSONStr == NULL) {
return NAN;
}
pszTmp = (char *)pszJSONStr;
fTmp = CPLStrtod(pszJSONStr, &pszTmp);
if (pszTmp == pszJSONStr) {
CPLDebug("ARGDataset", "GetJsonValueDbl(): "
"Key value is not a numeric value: %s:%s", pszKey.c_str(), pszTmp);
return NAN;
}
return fTmp;
}
/************************************************************************/
/* GetJsonValueInt() */
/************************************************************************/
int GetJsonValueInt(json_object * pJSONObject, CPLString pszKey)
{
double fTmp = GetJsonValueDbl(pJSONObject, pszKey.c_str());
if (CPLIsNan(fTmp)) {
return -1;
}
return (int)fTmp;
}
/************************************************************************/
/* GetFileList() */
/************************************************************************/
char ** ARGDataset::GetFileList()
{
char **papszFileList = GDALPamDataset::GetFileList();
CPLString osJSONFilename = GetJsonFilename(pszFilename);
papszFileList = CSLAddString( papszFileList, osJSONFilename );
return papszFileList;
}
/************************************************************************/
/* Identify() */
/************************************************************************/
int ARGDataset::Identify( GDALOpenInfo *poOpenInfo )
{
json_object * pJSONObject;
if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "arg")) {
return FALSE;
}
pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
if (pJSONObject == NULL) {
return FALSE;
}
json_object_put(pJSONObject);
pJSONObject = NULL;
return TRUE;
}
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *ARGDataset::Open( GDALOpenInfo * poOpenInfo )
{
json_object * pJSONObject;
const char * pszJSONStr;
char * pszLayer;
/***** items from the json metadata *****/
GDALDataType eType = GDT_Unknown;
double fXmin = 0.0;
double fYmin = 0.0;
double fXmax = 0.0;
double fYmax = 0.0;
double fCellwidth = 1.0;
double fCellheight = 1.0;
double fXSkew = 0.0;
double fYSkew = 0.0;
int nRows = 0;
int nCols = 0;
int nSrs = 3857;
/***** items from the json metadata *****/
int nPixelOffset = 0;
double fNoDataValue = NAN;
char * pszWKT = NULL;
OGRSpatialReference oSRS;
OGRErr nErr = OGRERR_NONE;
if ( !Identify( poOpenInfo ) )
return NULL;
/* -------------------------------------------------------------------- */
/* Check metadata settings in JSON. */
/* -------------------------------------------------------------------- */
pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
if (pJSONObject == NULL) {
CPLError(CE_Failure, CPLE_AppDefined, "Error parsing JSON.");
return NULL;
}
// get the type (always 'arg')
pszJSONStr = GetJsonValueStr(pJSONObject, "type");
if (pszJSONStr == NULL ) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'type' is missing from the JSON file.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
else if (!EQUAL(pszJSONStr, "arg")) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'type' is not recognized: '%s'.", pszJSONStr);
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the datatype
pszJSONStr = GetJsonValueStr(pJSONObject, "datatype");
if (pszJSONStr == NULL) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'datatype' is missing from the JSON file.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
else if (EQUAL(pszJSONStr, "int8")) {
CPLDebug("ARGDataset", "Open(): "
"int8 data is not supported in GDAL -- mapped to uint8");
eType = GDT_Byte;
nPixelOffset = 1;
fNoDataValue = 128;
}
else if (EQUAL(pszJSONStr, "int16")) {
eType = GDT_Int16;
nPixelOffset = 2;
fNoDataValue = -32767;
}
else if (EQUAL(pszJSONStr, "int32")) {
eType = GDT_Int32;
nPixelOffset = 4;
fNoDataValue = -2e31;
}
else if (EQUAL(pszJSONStr, "uint8")) {
eType = GDT_Byte;
nPixelOffset = 1;
fNoDataValue = 255;
}
else if (EQUAL(pszJSONStr, "uint16")) {
eType = GDT_UInt16;
nPixelOffset = 2;
fNoDataValue = 65535;
}
else if (EQUAL(pszJSONStr, "uint32")) {
eType = GDT_UInt32;
nPixelOffset = 4;
fNoDataValue = -2e31;
}
else if (EQUAL(pszJSONStr, "float32")) {
eType = GDT_Float32;
nPixelOffset = 4;
fNoDataValue = NAN;
}
else if (EQUAL(pszJSONStr, "float64")) {
eType = GDT_Float64;
nPixelOffset = 8;
fNoDataValue = NAN;
}
else {
if (EQUAL(pszJSONStr, "int64") ||
EQUAL(pszJSONStr, "uint64")) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'datatype' is unsupported in GDAL: '%s'.", pszJSONStr);
}
else {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'datatype' is unknown: '%s'.", pszJSONStr);
}
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the xmin of the bounding box
fXmin = GetJsonValueDbl(pJSONObject, "xmin");
if (CPLIsNan(fXmin)) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'xmin' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the ymin of the bounding box
fYmin = GetJsonValueDbl(pJSONObject, "ymin");
if (CPLIsNan(fYmin)) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'ymin' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the xmax of the bounding box
fXmax = GetJsonValueDbl(pJSONObject, "xmax");
if (CPLIsNan(fXmax)) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'xmax' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the ymax of the bounding box
fYmax = GetJsonValueDbl(pJSONObject, "ymax");
if (CPLIsNan(fYmax)) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'ymax' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the cell width
fCellwidth = GetJsonValueDbl(pJSONObject, "cellwidth");
if (CPLIsNan(fCellwidth)) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'cellwidth' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the cell height
fCellheight = GetJsonValueDbl(pJSONObject, "cellheight");
if (CPLIsNan(fCellheight)) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'cellheight' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
fXSkew = GetJsonValueDbl(pJSONObject, "xskew");
if (CPLIsNan(fXSkew)) {
// not an error -- default to 0.0
fXSkew = 0.0f;
}
fYSkew = GetJsonValueDbl(pJSONObject, "yskew");
if (CPLIsNan(fYSkew)) {
// not an error -- default to 0.0
fYSkew = 0.0f;
}
// get the rows
nRows = GetJsonValueInt(pJSONObject, "rows");
if (nRows < 0) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'rows' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the columns
nCols = GetJsonValueInt(pJSONObject, "cols");
if (nCols < 0) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'cols' is missing or invalid.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
nSrs = GetJsonValueInt(pJSONObject, "epsg");
if (nSrs < 0) {
// not an error -- default to web mercator
nSrs = 3857;
}
nErr = oSRS.importFromEPSG(nSrs);
if (nErr != OGRERR_NONE) {
nErr = oSRS.importFromEPSG(3857);
if (nErr == OGRERR_NONE) {
CPLDebug("ARGDataset", "Open(): "
"The EPSG provided did not import cleanly. Defaulting to EPSG:3857");
}
else {
CPLError(CE_Failure, CPLE_AppDefined,
"The 'epsg' value did not transate to a known spatial reference."
" Please check the 'epsg' value and try again.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
}
nErr = oSRS.exportToWkt(&pszWKT);
if (nErr != OGRERR_NONE) {
CPLError(CE_Failure, CPLE_AppDefined,
"The spatial reference is known, but could not be set on the "
"dataset. Please check the 'epsg' value and try again.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
// get the layer (always the file basename)
pszJSONStr = GetJsonValueStr(pJSONObject, "layer");
if (pszJSONStr == NULL) {
CPLError(CE_Failure, CPLE_AppDefined,
"The ARG 'layer' is missing from the JSON file.");
json_object_put(pJSONObject);
pJSONObject = NULL;
return NULL;
}
pszLayer = CPLStrdup(pszJSONStr);
// done with the json object now
json_object_put(pJSONObject);
pJSONObject = NULL;
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
ARGDataset *poDS;
poDS = new ARGDataset();
poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
poDS->SetMetadataItem("LAYER",pszLayer,NULL);
poDS->nRasterXSize = nCols;
poDS->nRasterYSize = nRows;
poDS->SetProjection( pszWKT );
// done with the projection string
CPLFree(pszWKT);
CPLFree(pszLayer);
/* -------------------------------------------------------------------- */
/* Assume ownership of the file handled from the GDALOpenInfo. */
/* -------------------------------------------------------------------- */
poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb");
if (poDS->fpImage == NULL)
{
delete poDS;
CPLError(CE_Failure, CPLE_AppDefined,
"Could not open dataset '%s'", poOpenInfo->pszFilename);
return NULL;
}
poDS->adfGeoTransform[0] = fXmin;
poDS->adfGeoTransform[1] = fCellwidth;
poDS->adfGeoTransform[2] = fXSkew;
poDS->adfGeoTransform[3] = fYmax;
poDS->adfGeoTransform[4] = fYSkew;
poDS->adfGeoTransform[5] = -fCellheight;
/* -------------------------------------------------------------------- */
/* Create band information objects. */
/* -------------------------------------------------------------------- */
RawRasterBand *poBand;
#ifdef CPL_LSB
int bNative = FALSE;
#else
int bNative = TRUE;
#endif
poBand = new RawRasterBand( poDS, 1, poDS->fpImage,
0, nPixelOffset, nPixelOffset * nCols,
eType, bNative, TRUE );
poDS->SetBand( 1, poBand );
poBand->SetNoDataValue( fNoDataValue );
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
/* -------------------------------------------------------------------- */
/* Check for overviews. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
return( poDS );
}
/************************************************************************/
/* CreateCopy() */
/************************************************************************/
GDALDataset * ARGDataset::CreateCopy( const char * pszFilename,
GDALDataset * poSrcDS,
CPL_UNUSED int bStrict,
CPL_UNUSED char ** papszOptions,
CPL_UNUSED GDALProgressFunc pfnProgress,
CPL_UNUSED void * pProgressData )
{
int nBands = poSrcDS->GetRasterCount();
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
int nXBlockSize, nYBlockSize, nPixelOffset = 0;
GDALDataType eType;
CPLString osJSONFilename;
CPLString pszDataType;
json_object * poJSONObject = NULL;
double adfTransform[6];
GDALRasterBand * poSrcBand = NULL;
RawRasterBand * poDstBand = NULL;
VSILFILE * fpImage = NULL;
void * pabyData;
OGRSpatialReference oSRS;
char * pszWKT = NULL;
char ** pszTokens = NULL;
const char * pszLayer = NULL;
int nSrs = 0;
OGRErr nErr = OGRERR_NONE;
CPLErr eErr;
if( nBands != 1 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"ARG driver doesn't support %d bands. Must be 1 band.", nBands );
return NULL;
}
eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
if( eType == GDT_Unknown ||
eType == GDT_CInt16 ||
eType == GDT_CInt32 ||
eType == GDT_CFloat32 ||
eType == GDT_CFloat64 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"ARG driver doesn't support data type %s.",
GDALGetDataTypeName(eType) );
return NULL;
}
else if (eType == GDT_Int16) {
pszDataType = "int16";
nPixelOffset = 2;
}
else if (eType == GDT_Int32) {
pszDataType = "int32";
nPixelOffset = 4;
}
else if (eType == GDT_Byte) {
pszDataType = "uint8";
nPixelOffset = 1;
}
else if (eType == GDT_UInt16) {
pszDataType = "uint16";
nPixelOffset = 2;
}
else if (eType == GDT_UInt32) {
pszDataType = "uint32";
nPixelOffset = 4;
}
else if (eType == GDT_Float32) {
pszDataType = "float32";
nPixelOffset = 4;
}
else if (eType == GDT_Float64) {
pszDataType = "float64";
nPixelOffset = 8;
}
poSrcDS->GetGeoTransform( adfTransform );
pszWKT = (char *)poSrcDS->GetProjectionRef();
nErr = oSRS.importFromWkt(&pszWKT);
if (nErr != OGRERR_NONE) {
CPLError( CE_Failure, CPLE_NotSupported,
"Cannot import spatial reference WKT from source dataset.");
return NULL;
}
if (oSRS.GetAuthorityCode("PROJCS") != NULL) {
nSrs = atoi(oSRS.GetAuthorityCode("PROJCS"));
}
else if (oSRS.GetAuthorityCode("GEOGCS") != NULL) {
nSrs = atoi(oSRS.GetAuthorityCode("GEOGCS"));
}
else {
// could not determine projected or geographic code
// default to EPSG:3857 if no code could be found
nSrs = 3857;
}
/********************************************************************/
/* Create JSON companion file. */
/********************************************************************/
osJSONFilename = GetJsonFilename(pszFilename);
poJSONObject = json_object_new_object();
pszTokens = poSrcDS->GetMetadata();
pszLayer = CSLFetchNameValue(pszTokens, "LAYER");
if ( pszLayer == NULL) {
// Set the layer
json_object_object_add(poJSONObject, "layer", json_object_new_string(
CPLGetBasename(osJSONFilename)
));
}
else {
// Set the layer
json_object_object_add(poJSONObject, "layer", json_object_new_string(
pszLayer
));
}
// Set the type
json_object_object_add(poJSONObject, "type", json_object_new_string("arg"));
// Set the datatype
json_object_object_add(poJSONObject, "datatype", json_object_new_string(pszDataType));
// Set the number of rows
json_object_object_add(poJSONObject, "rows", json_object_new_int(nYSize));
// Set the number of columns
json_object_object_add(poJSONObject, "cols", json_object_new_int(nXSize));
// Set the xmin
json_object_object_add(poJSONObject, "xmin", json_object_new_double(adfTransform[0]));
// Set the ymax
json_object_object_add(poJSONObject, "ymax", json_object_new_double(adfTransform[3]));
// Set the cellwidth
json_object_object_add(poJSONObject, "cellwidth", json_object_new_double(adfTransform[1]));
// Set the cellheight
json_object_object_add(poJSONObject, "cellheight", json_object_new_double(-adfTransform[5]));
// Set the xmax
json_object_object_add(poJSONObject, "xmax", json_object_new_double(adfTransform[0] + nXSize * adfTransform[1]));
// Set the ymin
json_object_object_add(poJSONObject, "ymin", json_object_new_double(adfTransform[3] + nYSize * adfTransform[5]));
// Set the xskew
json_object_object_add(poJSONObject, "xskew", json_object_new_double(adfTransform[2]));
// Set the yskew
json_object_object_add(poJSONObject, "yskew", json_object_new_double(adfTransform[4]));
if (nSrs > 0) {
// Set the epsg
json_object_object_add(poJSONObject, "epsg", json_object_new_int(nSrs));
}
if (json_object_to_file((char *)osJSONFilename.c_str(), poJSONObject) < 0) {
CPLError( CE_Failure, CPLE_NotSupported,
"ARG driver can't write companion file.");
json_object_put(poJSONObject);
poJSONObject = NULL;
return NULL;
}
json_object_put(poJSONObject);
poJSONObject = NULL;
fpImage = VSIFOpenL(pszFilename, "wb");
if (fpImage == NULL)
{
CPLError( CE_Failure, CPLE_NotSupported,
"ARG driver can't create data file %s.", pszFilename);
// remove JSON file
VSIUnlink( osJSONFilename.c_str() );
return NULL;
}
// only 1 raster band
poSrcBand = poSrcDS->GetRasterBand( 1 );
#ifdef CPL_LSB
int bNative = FALSE;
#else
int bNative = TRUE;
#endif
poDstBand = new RawRasterBand( fpImage, 0, nPixelOffset,
nPixelOffset * nXSize, eType, bNative,
nXSize, nYSize, TRUE, FALSE);
poSrcBand->GetBlockSize(&nXBlockSize, &nYBlockSize);
pabyData = CPLMalloc(nXBlockSize * nPixelOffset);
// convert any blocks into scanlines
for (int nYBlock = 0; nYBlock * nYBlockSize < nYSize; nYBlock++) {
for (int nYScanline = 0; nYScanline < nYBlockSize; nYScanline++) {
if ((nYScanline+1) + nYBlock * nYBlockSize > poSrcBand->GetYSize() ) {
continue;
}
for (int nXBlock = 0; nXBlock * nXBlockSize < nXSize; nXBlock++) {
int nXValid;
if( (nXBlock+1) * nXBlockSize > poSrcBand->GetXSize() )
nXValid = poSrcBand->GetXSize() - nXBlock * nXBlockSize;
else
nXValid = nXBlockSize;
eErr = poSrcBand->RasterIO(GF_Read, nXBlock * nXBlockSize,
nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
1, eType, 0, 0, NULL);
if (eErr != CE_None) {
CPLError(CE_Failure, CPLE_AppDefined, "Error reading.");
CPLFree( pabyData );
delete poDstBand;
VSIFCloseL( fpImage );
return NULL;
}
eErr = poDstBand->RasterIO(GF_Write, nXBlock * nXBlockSize,
nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
1, eType, 0, 0, NULL);
if (eErr != CE_None) {
CPLError(CE_Failure, CPLE_AppDefined, "Error writing.");
CPLFree( pabyData );
delete poDstBand;
VSIFCloseL( fpImage );
return NULL;
}
}
}
}
CPLFree( pabyData );
delete poDstBand;
VSIFCloseL( fpImage );
return (GDALDataset *)GDALOpen( pszFilename, GA_ReadOnly );
}
/************************************************************************/
/* GDALRegister_ARG() */
/************************************************************************/
void GDALRegister_ARG()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "ARG" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "ARG" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"Azavea Raster Grid format" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_various.html#ARG" );
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->pfnIdentify = ARGDataset::Identify;
poDriver->pfnOpen = ARGDataset::Open;
poDriver->pfnCreateCopy = ARGDataset::CreateCopy;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}

View file

@ -0,0 +1,15 @@
OBJ = argdataset.obj
EXTRAFLAGS = -I..\..\ogr\ogrsf_frmts\geojson -I../../ogr/ogrsf_frmts/geojson/libjson -I..\raw
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,15 @@
include ../../GDALmake.opt
XTRA_OPT = -I. -DGDALDRIVER
OBJ = blxdataset.o blx.o
CPPFLAGS := $(XTRA_OPT) $(CPPFLAGS)
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o $(O_OBJ)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,147 @@
/* libblx - Magellan BLX topo reader/writer library
*
* Copyright (c) 2008, Henrik Johansson <henrik@johome.net>
*
* 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.
*/
#ifndef _BLX_H_INCLUDED
#define _BLX_H_INCLUDED
#include <stdio.h>
/* Constants */
#define BLX_UNDEF -32768
#define BLX_OVERVIEWLEVELS 4
/* Possible values of ctx.endian */
#define BIGENDIAN 1
#define LITTLEENDIAN 0
/* Data types */
typedef short int blxdata;
struct cellindex_s {
int offset;
unsigned int datasize; /* Uncompressed size */
unsigned int compdatasize; /* Compressed data size */
};
struct blxcontext_s {
int xsize, ysize;
int cell_xsize, cell_ysize;
int cell_cols, cell_rows;
double lon,lat;
double pixelsize_lon, pixelsize_lat;
int zscale;
int maxchunksize;
int minval, maxval;
int endian;
struct cellindex_s *cellindex;
int debug;
int fillundef; /* If non-zero, fillundefval will be used instead of -32768 for undefined values in non-empty cells when
a cell is written */
int fillundefval;
FILE *fh;
int write;
int open;
};
typedef struct blxcontext_s blxcontext_t;
struct component_s {
int n;
blxdata *lut;
int dlen;
blxdata *data;
};
/* Included all functions in the global name space when testing */
#ifdef TEST
#define STATIC
#else
#define STATIC static
#endif
/* Define memory allocation and I/O function macros */
#ifdef GDALDRIVER
#include "cpl_conv.h"
#define BLXfopen VSIFOpen
#define BLXfclose VSIFClose
#define BLXfread VSIFRead
#define BLXfwrite VSIFWrite
#define BLXfseek VSIFSeek
#define BLXftell VSIFTell
#define BLXmalloc VSIMalloc
#define BLXfree CPLFree
#define BLXdebug0(text) CPLDebug("BLX", text)
#define BLXdebug1(text, arg1) CPLDebug("BLX", text, arg1)
#define BLXdebug2(text, arg1, arg2) CPLDebug("BLX", text, arg1, arg2)
#define BLXerror0(text) CPLError(CE_Failure, CPLE_AppDefined, text)
#define BLXnotice1(text, arg1) CPLDebug("BLX", text, arg1)
#define BLXnotice2(text, arg1, arg2) CPLDebug("BLX", text, arg1, arg2)
#else
#define BLXfopen fopen
#define BLXfclose fclose
#define BLXfread fread
#define BLXfwrite fwrite
#define BLXfseek fseek
#define BLXftell ftell
#define BLXmalloc malloc
#define BLXfree free
#define BLXdebug0 printf
#define BLXdebug1 printf
#define BLXdebug2 printf
#define BLXerror0 printf
#define BLXnotice1 printf
#define BLXnotice2 printf
#endif
/* Function prototypes */
#ifdef TEST
STATIC int compress_chunk(unsigned char *inbuf, int inlen, unsigned char *outbuf, int outbuflen);
STATIC int uncompress_chunk(unsigned char *inbuf, int inlen, unsigned char *outbuf, int outbuflen);
STATIC blxdata *reconstruct_horiz(blxdata *base, blxdata *diff, unsigned rows, unsigned cols, blxdata *out);
STATIC blxdata *reconstruct_vert(blxdata *base, blxdata *diff, unsigned rows, unsigned cols, blxdata *out);
STATIC void decimate_horiz(blxdata *in, unsigned rows, unsigned cols, blxdata *base, blxdata *diff);
STATIC void decimate_vert(blxdata *in, unsigned int rows, unsigned int cols, blxdata *base, blxdata *diff);
STATIC blxdata *decode_celldata(blxcontext_t *blxcontext, unsigned char *inbuf, int len, int *side, blxdata *outbuf, int outbufsize, int overviewlevel);
#endif
blxcontext_t *blx_create_context(void);
void blx_free_context(blxcontext_t *ctx);
int blxopen(blxcontext_t *ctx, const char *filename, const char *rw);
int blxclose(blxcontext_t *ctx);
void blxprintinfo(blxcontext_t *ctx);
short *blx_readcell(blxcontext_t *ctx, int row, int col, short *buffer, int bufsize, int overviewlevel);
int blx_encode_celldata(blxcontext_t *ctx, blxdata *indata, int side, unsigned char *outbuf, int outbufsize);
int blx_checkheader(char *header);
int blx_writecell(blxcontext_t *ctx, blxdata *cell, int cellrow, int cellcol);
#endif

View file

@ -0,0 +1,453 @@
/******************************************************************************
* $Id: blxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
*
* Project: BLX Driver
* Purpose: GDAL BLX support.
* Author: Henrik Johansson, henrik@johome.net
*
******************************************************************************
* Copyright (c) 2006, Henrik Johansson <henrik@johome.net>
* Copyright (c) 2008-2011, 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 "cpl_string.h"
CPL_CVSID("$Id: blxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
CPL_C_START
#include <blx.h>
CPL_C_END
CPL_C_START
void GDALRegister_BLX(void);
CPL_C_END
class BLXDataset : public GDALPamDataset
{
friend class BLXRasterBand;
CPLErr GetGeoTransform( double * padfTransform );
const char *GetProjectionRef();
blxcontext_t *blxcontext;
int nOverviewCount;
int bIsOverview;
BLXDataset *papoOverviewDS[BLX_OVERVIEWLEVELS];
public:
BLXDataset();
~BLXDataset();
static GDALDataset *Open( GDALOpenInfo * );
};
class BLXRasterBand : public GDALPamRasterBand
{
int overviewLevel;
public:
BLXRasterBand( BLXDataset *, int, int overviewLevel=0 );
virtual double GetNoDataValue( int *pbSuccess = NULL );
virtual GDALColorInterp GetColorInterpretation(void);
virtual int GetOverviewCount();
virtual GDALRasterBand *GetOverview( int );
virtual CPLErr IReadBlock( int, int, void * );
};
GDALDataset *BLXDataset::Open( GDALOpenInfo * poOpenInfo )
{
// --------------------------------------------------------------------
// First that the header looks like a BLX header
// --------------------------------------------------------------------
if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 102 )
return NULL;
if(!blx_checkheader((char *)poOpenInfo->pabyHeader))
return NULL;
// --------------------------------------------------------------------
// Create a corresponding GDALDataset.
// --------------------------------------------------------------------
BLXDataset *poDS;
poDS = new BLXDataset();
// --------------------------------------------------------------------
// Open BLX file
// --------------------------------------------------------------------
poDS->blxcontext = blx_create_context();
if(poDS->blxcontext==NULL)
{
delete poDS;
return NULL;
}
if (blxopen(poDS->blxcontext, poOpenInfo->pszFilename, "rb") != 0)
{
delete poDS;
return NULL;
}
if ((poDS->blxcontext->cell_xsize % (1 << (1+BLX_OVERVIEWLEVELS))) != 0 ||
(poDS->blxcontext->cell_ysize % (1 << (1+BLX_OVERVIEWLEVELS))) != 0)
{
delete poDS;
return NULL;
}
// Update dataset header from BLX context
poDS->nRasterXSize = poDS->blxcontext->xsize;
poDS->nRasterYSize = poDS->blxcontext->ysize;
// --------------------------------------------------------------------
// Create band information objects.
// --------------------------------------------------------------------
poDS->nBands = 1;
poDS->SetBand( 1, new BLXRasterBand( poDS, 1 ));
// Create overview bands
poDS->nOverviewCount = BLX_OVERVIEWLEVELS;
for(int i=0; i < poDS->nOverviewCount; i++) {
poDS->papoOverviewDS[i] = new BLXDataset();
poDS->papoOverviewDS[i]->blxcontext = poDS->blxcontext;
poDS->papoOverviewDS[i]->bIsOverview = TRUE;
poDS->papoOverviewDS[i]->nRasterXSize = poDS->nRasterXSize >> (i+1);
poDS->papoOverviewDS[i]->nRasterYSize = poDS->nRasterYSize >> (i+1);
poDS->nBands = 1;
poDS->papoOverviewDS[i]->SetBand(1, new BLXRasterBand( poDS->papoOverviewDS[i], 1, i+1));
}
/* -------------------------------------------------------------------- */
/* Confirm the requested access is supported. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->eAccess == GA_Update )
{
delete poDS;
CPLError( CE_Failure, CPLE_NotSupported,
"The BLX driver does not support update access to existing"
" datasets.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
return( poDS );
}
BLXDataset::BLXDataset() {
blxcontext = NULL;
bIsOverview = FALSE;
nOverviewCount = 0;
for(int i=0; i < nOverviewCount; i++)
papoOverviewDS[i]=NULL;
}
BLXDataset::~BLXDataset() {
if(!bIsOverview) {
if(blxcontext) {
blxclose(blxcontext);
blx_free_context(blxcontext);
}
for(int i=0; i < nOverviewCount; i++)
if(papoOverviewDS[i])
delete papoOverviewDS[i];
}
}
CPLErr BLXDataset::GetGeoTransform( double * padfTransform )
{
padfTransform[0] = blxcontext->lon;
padfTransform[1] = blxcontext->pixelsize_lon;
padfTransform[2] = 0.0;
padfTransform[3] = blxcontext->lat;
padfTransform[4] = 0.0;
padfTransform[5] = blxcontext->pixelsize_lat;
return CE_None;
}
const char *BLXDataset::GetProjectionRef()
{
return( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4326\"]]" );
}
BLXRasterBand::BLXRasterBand( BLXDataset *poDS, int nBand, int overviewLevel )
{
BLXDataset *poGDS = (BLXDataset *) poDS;
this->poDS = poDS;
this->nBand = nBand;
this->overviewLevel = overviewLevel;
eDataType = GDT_Int16;
nBlockXSize = poGDS->blxcontext->cell_xsize >> overviewLevel;
nBlockYSize = poGDS->blxcontext->cell_ysize >> overviewLevel;
}
int BLXRasterBand::GetOverviewCount()
{
BLXDataset *poGDS = (BLXDataset *) poDS;
return poGDS->nOverviewCount;
}
GDALRasterBand *BLXRasterBand::GetOverview( int i )
{
BLXDataset *poGDS = (BLXDataset *) poDS;
if( i < 0 || i >= poGDS->nOverviewCount )
return NULL;
else
return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
}
CPLErr BLXRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
void * pImage )
{
BLXDataset *poGDS = (BLXDataset *) poDS;
if(blx_readcell(poGDS->blxcontext, nBlockYOff, nBlockXOff, (short *)pImage, nBlockXSize*nBlockYSize*2, overviewLevel) == NULL) {
CPLError(CE_Failure, CPLE_AppDefined,
"Failed to read BLX cell");
return CE_Failure;
}
return CE_None;
}
double BLXRasterBand::GetNoDataValue( int * pbSuccess )
{
if (pbSuccess)
*pbSuccess = TRUE;
return BLX_UNDEF;
}
GDALColorInterp BLXRasterBand::GetColorInterpretation(void) {
return GCI_GrayIndex;
}
/* TODO: check if georeference is the same as for BLX files, WGS84
*/
static GDALDataset *
BLXCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress, void * pProgressData )
{
int nBands = poSrcDS->GetRasterCount();
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
int zscale = 1;
int fillundef = 1, fillundefval = 0;
int endian = LITTLEENDIAN;
// --------------------------------------------------------------------
// Some rudimentary checks
// --------------------------------------------------------------------
if( nBands != 1 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"BLX driver doesn't support %d bands. Must be 1 (grey) ",
nBands );
return NULL;
}
if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Int16 && bStrict )
{
CPLError( CE_Failure, CPLE_NotSupported,
"BLX driver doesn't support data type %s. "
"Only 16 bit byte bands supported.\n",
GDALGetDataTypeName(
poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
return NULL;
}
if( (nXSize % 128 != 0) || (nYSize % 128 != 0) ) {
CPLError( CE_Failure, CPLE_NotSupported,
"BLX driver doesn't support dimensions that are not a multiple of 128.\n");
return NULL;
}
// --------------------------------------------------------------------
// What options has the user selected?
// --------------------------------------------------------------------
if( CSLFetchNameValue(papszOptions,"ZSCALE") != NULL ) {
zscale = atoi(CSLFetchNameValue(papszOptions,"ZSCALE"));
if( zscale < 1 ) {
CPLError( CE_Failure, CPLE_IllegalArg,
"ZSCALE=%s is not a legal value in the range >= 1.",
CSLFetchNameValue(papszOptions,"ZSCALE") );
return NULL;
}
}
if( CSLFetchNameValue(papszOptions,"FILLUNDEF") != NULL
&& EQUAL(CSLFetchNameValue(papszOptions,"FILLUNDEF"),"NO") )
fillundef = 0;
else
fillundef = 1;
if( CSLFetchNameValue(papszOptions,"FILLUNDEFVAL") != NULL ) {
fillundefval = atoi(CSLFetchNameValue(papszOptions,"FILLUNDEFVAL"));
if( (fillundefval < -32768) || (fillundefval > 32767) ) {
CPLError( CE_Failure, CPLE_IllegalArg,
"FILLUNDEFVAL=%s is not a legal value in the range -32768, 32767.",
CSLFetchNameValue(papszOptions,"FILLUNDEFVAL") );
return NULL;
}
}
if( CSLFetchNameValue(papszOptions,"BIGENDIAN") != NULL
&& !EQUAL(CSLFetchNameValue(papszOptions,"BIGENDIAN"),"NO") )
endian = BIGENDIAN;
// --------------------------------------------------------------------
// Create the dataset.
// --------------------------------------------------------------------
blxcontext_t *ctx;
// Create a BLX context
ctx = blx_create_context();
// Setup BLX parameters
ctx->cell_rows = nYSize / ctx->cell_ysize;
ctx->cell_cols = nXSize / ctx->cell_xsize;
ctx->zscale = zscale;
ctx->fillundef = fillundef;
ctx->fillundefval = fillundefval;
ctx->endian = endian;
if(blxopen(ctx, pszFilename, "wb")) {
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to create blx file %s.\n",
pszFilename );
blx_free_context(ctx);
return NULL;
}
// --------------------------------------------------------------------
// Loop over image, copying image data.
// --------------------------------------------------------------------
GInt16 *pabyTile;
CPLErr eErr=CE_None;
pabyTile = (GInt16 *) VSIMalloc( sizeof(GInt16)*ctx->cell_xsize*ctx->cell_ysize );
if (pabyTile == NULL)
{
CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
blxclose(ctx);
blx_free_context(ctx);
return NULL;
}
if( !pfnProgress( 0.0, NULL, pProgressData ) )
eErr = CE_Failure;
for(int i=0; (i < ctx->cell_rows) && (eErr == CE_None); i++)
for(int j=0; j < ctx->cell_cols; j++) {
blxdata *celldata;
GDALRasterBand * poBand = poSrcDS->GetRasterBand( 1 );
eErr = poBand->RasterIO( GF_Read, j*ctx->cell_xsize, i*ctx->cell_ysize,
ctx->cell_xsize, ctx->cell_ysize,
pabyTile, ctx->cell_xsize, ctx->cell_ysize, GDT_Int16,
0, 0, NULL );
if(eErr >= CE_Failure)
break;
celldata = pabyTile;
if (blx_writecell(ctx, celldata, i, j) != 0)
{
eErr = CE_Failure;
break;
}
if ( ! pfnProgress( 1.0 * (i * ctx->cell_cols + j) / (ctx->cell_rows * ctx->cell_cols), NULL, pProgressData ))
{
eErr = CE_Failure;
break;
}
}
pfnProgress( 1.0, NULL, pProgressData );
CPLFree( pabyTile );
double adfGeoTransform[6];
if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
{
ctx->lon = adfGeoTransform[0];
ctx->lat = adfGeoTransform[3];
ctx->pixelsize_lon = adfGeoTransform[1];
ctx->pixelsize_lat = adfGeoTransform[5];
}
blxclose(ctx);
blx_free_context(ctx);
if (eErr == CE_None)
return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
else
return NULL;
}
void GDALRegister_BLX()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "BLX" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "BLX" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"Magellan topo (.blx)" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_various.html#BLX" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "blx" );
poDriver->pfnOpen = BLXDataset::Open;
poDriver->pfnCreateCopy = BLXCreateCopy;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}

View file

@ -0,0 +1,48 @@
<html>
<head>
<title>BLX -- Magellan BLX Topo File Format (available from GDAL 1.6.0)</title>
</head>
<body bgcolor="#ffffff">
<h1>BLX -- Magellan BLX Topo File Format</h1>
<p>
BLX is the format for storing topographic data in Magellan GPS units. This driver
supports both reading and writing. In addition the 4 overview levels inherent in
the BLX format can be used with the driver.
</p>
<p>
The BLX format is tile based, for the moment the tile size is fixed to 128x128 size. Furthermore the dimensions must be a multiple of the tile size.
</p>
<p>
The data type is fixed to Int16 and the value for undefined values is fixed to -32768. In the BLX format undefined values are only really supported on tile level. For
undefined pixels in non-empty tiles see the FILLUNDEF/FILLUNDEFVAL options.
</p>
<h2>Georeferencing</h2>
<p>
The BLX projection is fixed to WGS84 and georeferencing from BLX is supported in the form of one tiepoint and
pixelsize.
</p>
<h2>Creation Issues</h2>
Creation Options:
<p>
<ul>
<li> <b>ZSCALE=1</b>: Set the desired quantization increment for write access. A higher value will result in better compression and lower vertical resolution.
<li> <b>BIGENDIAN=YES</b>: If BIGENDIAN is defined, the output file will be in XLB format (big endian blx).
<li> <b>FILLUNDEF=YES</b>: If FILLUNDEF is yes the value of FILLUNDEFVAL will be used instead of -32768 for non-empty tiles. This is needed since the BLX format only support undefined values for full tiles, not individual pixels.
<li> <b>FILLUNDEFVAL=0</b>: See FILLUNDEF
</ul>
</p>
</body>
</html>

View file

@ -0,0 +1,15 @@
OBJ = blxdataset.obj blx.obj
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
EXTRAFLAGS = -I. -DGDALDRIVER
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,13 @@
include ../../GDALmake.opt
OBJ = bmpdataset.o
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o $(O_OBJ)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,45 @@
<html>
<head>
<title>BMP --- Microsoft Windows Device Independent Bitmap</title>
</head>
<body bgcolor="#ffffff">
<h1>BMP --- Microsoft Windows Device Independent Bitmap</h1>
MS Windows Device Independent Bitmaps supported by the Windows kernel and
mostly used for storing system decoration images. Due to the nature of the
BMP format it has several restrictions and could not be used for general image
storing. In particular, you can create only 1-bit monochrome,
8-bit pseudocoloured and 24-bit RGB images only. Even grayscale images must
be saved in pseudocolour form.<p>
This driver supports reading almost any type of the BMP files and could write
ones which should be supported on any Windows system. Only single- or three-
band files could be saved in BMP file. Input values will be resampled to 8
bit.<p>
If an ESRI world file exists with the .bpw, .bmpw or .wld extension, it will be read and
used to establish the geotransform for the image.<p>
<h2>Creation Options</h2>
<ul>
<li> <b>WORLDFILE=YES</b>: Force the generation of an associated
ESRI world file (with the extension .wld).
<p>
</ul>
<h2>See Also:</h2>
<ul>
<li> Implemented as <tt>gdal/frmts/bmp/bmpdataset.cpp</tt>.<p>
<li> <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_9qg5.asp">
MSDN Bitmap Reference
</a><p>
</ul>
</body>
</html>

View file

@ -0,0 +1,13 @@
OBJ = bmpdataset.obj
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,361 @@
/******************************************************************************
* $Id$
*
* Project: GDAL BPG Driver
* Purpose: Implement GDAL BPG Support based on libbpg
* Author: Even Rouault, <even dot rouault at spatialys dot com>
*
******************************************************************************
* Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
*
* 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 <stdint.h>
#include "gdal_pam.h"
#include "cpl_string.h"
// NOTE: build instructions
// bpg Makefile needs to be modified to have -fPIC on CFLAGS:= at line 49 and LDFLAGS at line 54 before building bpg
// g++ -fPIC -g -Wall -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -I/home/even/libbpg-0.9.4 frmts/bpg/bpgdataset.cpp -shared -o gdal_BPG.so -L. -lgdal -L/home/even/libbpg-0.9.4/ -lbpg
CPL_C_START
#include "libbpg.h"
CPL_C_END
CPL_CVSID("$Id$");
CPL_C_START
void GDALRegister_BPG(void);
CPL_C_END
/************************************************************************/
/* ==================================================================== */
/* BPGDataset */
/* ==================================================================== */
/************************************************************************/
class BPGRasterBand;
class BPGDataset : public GDALPamDataset
{
friend class BPGRasterBand;
VSILFILE* fpImage;
GByte* pabyUncompressed;
int bHasBeenUncompressed;
CPLErr eUncompressErrRet;
CPLErr Uncompress();
public:
BPGDataset();
~BPGDataset();
static GDALDataset *Open( GDALOpenInfo * );
static int Identify( GDALOpenInfo * );
};
/************************************************************************/
/* ==================================================================== */
/* BPGRasterBand */
/* ==================================================================== */
/************************************************************************/
class BPGRasterBand : public GDALPamRasterBand
{
friend class BPGDataset;
public:
BPGRasterBand( BPGDataset *, int nbits );
virtual CPLErr IReadBlock( int, int, void * );
virtual GDALColorInterp GetColorInterpretation();
};
/************************************************************************/
/* BPGRasterBand() */
/************************************************************************/
BPGRasterBand::BPGRasterBand( BPGDataset *poDS, int nbits )
{
this->poDS = poDS;
eDataType = (nbits > 8) ? GDT_UInt16 : GDT_Byte;
nBlockXSize = poDS->nRasterXSize;
nBlockYSize = 1;
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr BPGRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
void * pImage )
{
BPGDataset* poGDS = (BPGDataset*) poDS;
if( poGDS->Uncompress() != CE_None )
return CE_Failure;
int i;
int iBand = nBand;
if( poGDS->nBands == 2 )
iBand = 4;
if( eDataType == GDT_Byte )
{
GByte* pabyUncompressed =
&poGDS->pabyUncompressed[nBlockYOff * nRasterXSize * poGDS->nBands + iBand - 1];
for(i=0;i<nRasterXSize;i++)
((GByte*)pImage)[i] = pabyUncompressed[poGDS->nBands * i];
}
else
{
GUInt16* pasUncompressed = (GUInt16*)
&poGDS->pabyUncompressed[(nBlockYOff * nRasterXSize * poGDS->nBands + iBand - 1) * 2];
for(i=0;i<nRasterXSize;i++)
((GUInt16*)pImage)[i] = pasUncompressed[poGDS->nBands * i];
}
return CE_None;
}
/************************************************************************/
/* GetColorInterpretation() */
/************************************************************************/
GDALColorInterp BPGRasterBand::GetColorInterpretation()
{
BPGDataset* poGDS = (BPGDataset*) poDS;
if( poGDS->nBands >= 3 )
return (GDALColorInterp) (GCI_RedBand + (nBand - 1));
else if( nBand == 1 )
return GCI_GrayIndex;
else
return GCI_AlphaBand;
}
/************************************************************************/
/* ==================================================================== */
/* BPGDataset */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* BPGDataset() */
/************************************************************************/
BPGDataset::BPGDataset()
{
fpImage = NULL;
pabyUncompressed = NULL;
bHasBeenUncompressed = FALSE;
eUncompressErrRet = CE_None;
}
/************************************************************************/
/* ~BPGDataset() */
/************************************************************************/
BPGDataset::~BPGDataset()
{
FlushCache();
if (fpImage)
VSIFCloseL(fpImage);
VSIFree(pabyUncompressed);
}
/************************************************************************/
/* Uncompress() */
/************************************************************************/
CPLErr BPGDataset::Uncompress()
{
if (bHasBeenUncompressed)
return eUncompressErrRet;
bHasBeenUncompressed = TRUE;
eUncompressErrRet = CE_Failure;
int nOutBands = (nBands < 3) ? nBands + 2 : nBands;
int nDTSize = ( GetRasterBand(1)->GetRasterDataType() == GDT_Byte ) ? 1 : 2;
pabyUncompressed = (GByte*)VSIMalloc3(nRasterXSize, nRasterYSize,
nOutBands * nDTSize);
if (pabyUncompressed == NULL)
return CE_Failure;
VSIFSeekL(fpImage, 0, SEEK_END);
vsi_l_offset nSize = VSIFTellL(fpImage);
if (nSize != (vsi_l_offset)(int)nSize)
return CE_Failure;
VSIFSeekL(fpImage, 0, SEEK_SET);
uint8_t* pabyCompressed = (uint8_t*)VSIMalloc(nSize);
if (pabyCompressed == NULL)
return CE_Failure;
VSIFReadL(pabyCompressed, 1, nSize, fpImage);
BPGDecoderContext* ctxt = bpg_decoder_open();
if( ctxt == NULL )
{
VSIFree(pabyCompressed);
return CE_Failure;
}
BPGDecoderOutputFormat eOutputFormat;
if( GetRasterBand(1)->GetRasterDataType() == GDT_Byte )
eOutputFormat = (nBands == 1 || nBands == 3) ? BPG_OUTPUT_FORMAT_RGB24 :
BPG_OUTPUT_FORMAT_RGBA32;
else
eOutputFormat = (nBands == 1 || nBands == 3) ? BPG_OUTPUT_FORMAT_RGB48 :
BPG_OUTPUT_FORMAT_RGBA64;
if( bpg_decoder_decode(ctxt, pabyCompressed, (int)nSize) < 0 ||
bpg_decoder_start(ctxt, eOutputFormat) < 0 )
{
bpg_decoder_close(ctxt);
VSIFree(pabyCompressed);
return CE_Failure;
}
for(int i=0;i<nRasterYSize;i++)
{
void* pRow = pabyUncompressed + i * nBands * nRasterXSize * nDTSize;
if( bpg_decoder_get_line(ctxt, pRow) < 0 )
{
bpg_decoder_close(ctxt);
VSIFree(pabyCompressed);
return CE_Failure;
}
}
bpg_decoder_close(ctxt);
VSIFree(pabyCompressed);
eUncompressErrRet = CE_None;
return CE_None;
}
/************************************************************************/
/* Identify() */
/************************************************************************/
int BPGDataset::Identify( GDALOpenInfo * poOpenInfo )
{
if( poOpenInfo->nHeaderBytes < BPG_DECODER_INFO_BUF_SIZE )
return FALSE;
return memcmp(poOpenInfo->pabyHeader, "BPG\xfb", 4) == 0;
}
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *BPGDataset::Open( GDALOpenInfo * poOpenInfo )
{
if( !Identify( poOpenInfo ) || poOpenInfo->fpL == NULL )
return NULL;
BPGImageInfo imageInfo;
if( bpg_decoder_get_info_from_buf(&imageInfo, NULL,
poOpenInfo->pabyHeader,
poOpenInfo->nHeaderBytes) < 0 )
return NULL;
if( poOpenInfo->eAccess == GA_Update )
{
CPLError( CE_Failure, CPLE_NotSupported,
"The BPG driver does not support update access to existing"
" datasets.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
BPGDataset *poDS;
poDS = new BPGDataset();
poDS->nRasterXSize = imageInfo.width;
poDS->nRasterYSize = imageInfo.height;
poDS->fpImage = poOpenInfo->fpL;
poOpenInfo->fpL = NULL;
/* -------------------------------------------------------------------- */
/* Create band information objects. */
/* -------------------------------------------------------------------- */
int nBands = ( imageInfo.format == BPG_FORMAT_GRAY ) ? 1 : 3;
if( imageInfo.has_alpha )
nBands ++;
for( int iBand = 0; iBand < nBands; iBand++ )
poDS->SetBand( iBand+1, new BPGRasterBand( poDS, imageInfo.bit_depth ) );
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
/* -------------------------------------------------------------------- */
/* Open overviews. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
poOpenInfo->GetSiblingFiles() );
return poDS;
}
/************************************************************************/
/* GDALRegister_BPG() */
/************************************************************************/
void GDALRegister_BPG()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "BPG" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "BPG" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"Better Portable Graphics" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_bpg.html" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "bpg" );
//poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/bpg" );
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->pfnIdentify = BPGDataset::Identify;
poDriver->pfnOpen = BPGDataset::Open;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}

View file

@ -0,0 +1,37 @@
VERSION = 1.3
include ../../GDALmake.opt
OBJ = bsb_read.o bsbdataset.o
DISTDIR = bsb-$(VERSION)
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o $(O_OBJ)
bsb2raw$(EXE): bsb2raw.$(OBJ_EXT)
$(LD) $(LDFLAGS) bsb2raw.$(OBJ_EXT) $(CONFIG_LIBS) -o bsb2raw$(EXE)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))
dist:
rm -rf $(DISTDIR)
mkdir $(DISTDIR)
cp *.cpp *.c *.h $(DISTDIR)
rm $(DISTDIR)/bsbdataset.cpp
cp Makefile.dist $(DISTDIR)/Makefile
cp README.dist $(DISTDIR)/README
cp ../../port/{cpl_error*,cpl_port*,cpl_string*} $(DISTDIR)
cp ../../port/{cpl_vsisimple.cpp,cpl_config.h.in} $(DISTDIR)
cp ../../port/{cpl_vsi.h,cpl_conv.*,cpl_path.cpp} $(DISTDIR)
cp ../../port/cpl_config.h.in $(DISTDIR)/cpl_config.h
rm $(DISTDIR)/*.o
tar czf $(DISTDIR).tar.gz $(DISTDIR)
zip -r $(DISTDIR).zip $(DISTDIR)

View file

@ -0,0 +1,2 @@
bsb2raw:
$(CXX) $(CFLAGS) *.c *.cpp -o bsb2raw

View file

@ -0,0 +1,48 @@
Sample BSB Reader
=================
Files
-----
bsb2raw.c: Sample mainline program for converting BSB files to "raw" format.
bsb_read.c: Core BSB reading code ... you may use this in your application.
bsb_read.h: Declarations for functions and structures in bsb_read.c. #include
this from your application.
cpl_*: Supporting low level code and include files.
Makefile: Simple Unix style makefile for building bsb2raw program.
NOTE: It may be necessary to fool with the cpl_config.h include file for
different platforms. In particular, change the #undef WORDS_BIGENDIAN to
a #define WORDS_BIGENDIAN for big endian systems (Sparc, SGI, etc). Some
changes may be needed in cpl_config.h for Windows.
License
-------
MIT/X license ... see header of bsb_read.c.
On the Web
----------
http://gdal.velocet.ca/projects/bsb/
GDAL
----
Note that this BSB code is normally incorporated into the larger GDAL
library. To convert BSB to other common formats like GeoTIFF, PNG, etc
consider using the GDAL utilities at:
http://www.remotesensing.org/gdal
July 19, 2002
Frank Warmerdam <warmerdam@pobox.com>

View file

@ -0,0 +1,109 @@
/******************************************************************************
* $Id: bsb2raw.c 10645 2007-01-18 02:22:39Z warmerdam $
*
* Project: BSB Reader
* Purpose: Test program for dumping BSB to PPM raster format.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2001, Frank Warmerdam
*
* 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 "cpl_error.h"
#include "cpl_vsi.h"
#include "cpl_conv.h"
#include "bsb_read.h"
CPL_CVSID("$Id: bsb2raw.c 10645 2007-01-18 02:22:39Z warmerdam $");
/************************************************************************/
/* main() */
/************************************************************************/
int main( int nArgc, char **papszArgv )
{
BSBInfo *psInfo;
int iLine, i;
GByte *pabyScanline;
FILE *fp;
int nError = 0;
if( nArgc < 3 )
{
fprintf( stderr, "Usage: bsb2raw src_file dst_file\n" );
exit( 1 );
}
psInfo = BSBOpen( papszArgv[1] );
if( psInfo == NULL )
exit( 1 );
fp = VSIFOpen( papszArgv[2], "wb" );
if( fp == NULL )
{
perror( "open" );
exit( 1 );
}
pabyScanline = (GByte *) CPLMalloc(psInfo->nXSize);
for( iLine = 0; iLine < psInfo->nYSize; iLine++ )
{
if( !BSBReadScanline( psInfo, iLine, pabyScanline ) )
nError++;
VSIFWrite( pabyScanline, 1, psInfo->nXSize, fp );
}
VSIFClose( fp );
if( nError > 0 )
fprintf( stderr, "Read failed for %d scanlines out of %d.\n",
nError, psInfo->nYSize );
/* -------------------------------------------------------------------- */
/* Write .aux file. */
/* -------------------------------------------------------------------- */
fp = VSIFOpen( CPLResetExtension( papszArgv[2], "aux" ), "wt" );
fprintf( fp, "AuxilaryTarget: %s\n",
CPLGetFilename(papszArgv[2]) );
fprintf( fp, "RawDefinition: %d %d 1\n",
psInfo->nXSize, psInfo->nYSize );
fprintf( fp, "ChanDefinition-1: 8U 0 1 %d Swapped\n",
psInfo->nXSize );
for( i = 0; i < psInfo->nPCTSize; i++ )
fprintf( fp, "METADATA_IMG_1_Class_%d_Color: (RGB:%d %d %d)\n",
i,
psInfo->pabyPCT[i*3 + 0],
psInfo->pabyPCT[i*3 + 1],
psInfo->pabyPCT[i*3 + 2] );
VSIFClose( fp );
exit( 0 );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
/******************************************************************************
* $Id: bsb_read.h 20996 2010-10-28 18:38:15Z rouault $
*
* Project: BSB Reader
* Purpose: non-GDAL BSB API Declarations
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2001, Frank Warmerdam
*
* 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.
****************************************************************************/
#ifndef _BSBREAD_H_INCLUDED
#define _BSBREAD_H_INCLUDED
#include "cpl_port.h"
#include "cpl_vsi.h"
CPL_C_START
typedef struct {
VSILFILE *fp;
GByte *pabyBuffer;
int nBufferOffset;
int nBufferSize;
int nBufferAllocation;
int nSavedCharacter;
int nXSize;
int nYSize;
int nPCTSize;
unsigned char *pabyPCT;
char **papszHeader;
int *panLineOffset;
int nColorSize;
int nVersion; /* times 100 */
int bNO1;
int bNewFile;
int nLastLineWritten;
} BSBInfo;
BSBInfo CPL_DLL *BSBOpen( const char *pszFilename );
int CPL_DLL BSBReadScanline( BSBInfo *psInfo, int nScanline,
unsigned char *pabyScanlineBuf );
void CPL_DLL BSBClose( BSBInfo *psInfo );
BSBInfo CPL_DLL *BSBCreate( const char *pszFilename, int nCreationFlags,
int nVersion, int nXSize, int nYSize );
int CPL_DLL BSBWritePCT( BSBInfo *psInfo,
int nPCTSize, unsigned char *pabyPCT );
int CPL_DLL BSBWriteScanline( BSBInfo *psInfo,
unsigned char *pabyScanlineBuf );
CPL_C_END
#endif /* ndef _BSBREAD_H_INCLUDED */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
OBJ = bsbdataset.obj bsb_read.obj
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,17 @@
include ../../GDALmake.opt
OBJ = ceosopen.o ceosdataset.o
default: $(OBJ:.o=.$(OBJ_EXT))
clean:
rm -f *.o $(O_OBJ)
ceostest$(EXE): ceostest.$(OBJ_EXT)
$(LD) $(LDFLAGS) ceostest.$(OBJ_EXT) $(CONFIG_LIBS) -o ceostest$(EXE)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

View file

@ -0,0 +1,257 @@
/******************************************************************************
* $Id: ceosdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: CEOS Translator
* Purpose: GDALDataset driver for CEOS translator.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
* Copyright (c) 2009-2010, 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 "ceosopen.h"
#include "gdal_pam.h"
CPL_CVSID("$Id: ceosdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
CPL_C_START
void GDALRegister_CEOS(void);
CPL_C_END
/************************************************************************/
/* ==================================================================== */
/* CEOSDataset */
/* ==================================================================== */
/************************************************************************/
class CEOSRasterBand;
class CEOSDataset : public GDALPamDataset
{
friend class CEOSRasterBand;
CEOSImage *psCEOS;
public:
CEOSDataset();
~CEOSDataset();
static GDALDataset *Open( GDALOpenInfo * );
};
/************************************************************************/
/* ==================================================================== */
/* CEOSRasterBand */
/* ==================================================================== */
/************************************************************************/
class CEOSRasterBand : public GDALPamRasterBand
{
friend class CEOSDataset;
public:
CEOSRasterBand( CEOSDataset *, int );
virtual CPLErr IReadBlock( int, int, void * );
};
/************************************************************************/
/* CEOSRasterBand() */
/************************************************************************/
CEOSRasterBand::CEOSRasterBand( CEOSDataset *poDS, int nBand )
{
this->poDS = poDS;
this->nBand = nBand;
eDataType = GDT_Byte;
nBlockXSize = poDS->GetRasterXSize();
nBlockYSize = 1;
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr CEOSRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
int nBlockYOff,
void * pImage )
{
CEOSDataset *poCEOS_DS = (CEOSDataset *) poDS;
CPLAssert( nBlockXOff == 0 );
return( CEOSReadScanline(poCEOS_DS->psCEOS, nBand, nBlockYOff+1, pImage) );
}
/************************************************************************/
/* ==================================================================== */
/* CEOSDataset */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* CEOSDataset() */
/************************************************************************/
CEOSDataset::CEOSDataset()
{
psCEOS = NULL;
}
/************************************************************************/
/* ~CEOSDataset() */
/************************************************************************/
CEOSDataset::~CEOSDataset()
{
FlushCache();
if( psCEOS )
CEOSClose( psCEOS );
}
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *CEOSDataset::Open( GDALOpenInfo * poOpenInfo )
{
CEOSImage *psCEOS;
int i;
/* -------------------------------------------------------------------- */
/* Before trying CEOSOpen() we first verify that the first */
/* record is in fact a CEOS file descriptor record. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->nHeaderBytes < 100 )
return NULL;
if( poOpenInfo->pabyHeader[4] != 0x3f
|| poOpenInfo->pabyHeader[5] != 0xc0
|| poOpenInfo->pabyHeader[6] != 0x12
|| poOpenInfo->pabyHeader[7] != 0x12 )
return NULL;
/* -------------------------------------------------------------------- */
/* Try opening the dataset. */
/* -------------------------------------------------------------------- */
psCEOS = CEOSOpen( poOpenInfo->pszFilename, "rb" );
if( psCEOS == NULL )
return( NULL );
if( psCEOS->nBitsPerPixel != 8 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"The CEOS driver cannot handle nBitsPerPixel = %d",
psCEOS->nBitsPerPixel );
CEOSClose(psCEOS);
return NULL;
}
if( !GDALCheckDatasetDimensions(psCEOS->nPixels, psCEOS->nBands) ||
!GDALCheckBandCount(psCEOS->nBands, FALSE) )
{
CEOSClose( psCEOS );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Confirm the requested access is supported. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->eAccess == GA_Update )
{
CEOSClose(psCEOS);
CPLError( CE_Failure, CPLE_NotSupported,
"The CEOS driver does not support update access to existing"
" datasets.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
CEOSDataset *poDS;
poDS = new CEOSDataset();
poDS->psCEOS = psCEOS;
/* -------------------------------------------------------------------- */
/* Capture some information from the file that is of interest. */
/* -------------------------------------------------------------------- */
poDS->nRasterXSize = psCEOS->nPixels;
poDS->nRasterYSize = psCEOS->nLines;
/* -------------------------------------------------------------------- */
/* Create band information objects. */
/* -------------------------------------------------------------------- */
poDS->nBands = psCEOS->nBands;;
for( i = 0; i < poDS->nBands; i++ )
poDS->SetBand( i+1, new CEOSRasterBand( poDS, i+1 ) );
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->TryLoadXML();
/* -------------------------------------------------------------------- */
/* Check for overviews. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
return( poDS );
}
/************************************************************************/
/* GDALRegister_GTiff() */
/************************************************************************/
void GDALRegister_CEOS()
{
GDALDriver *poDriver;
if( GDALGetDriverByName( "CEOS" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "CEOS" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"CEOS Image" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
"frmt_various.html#CEOS" );
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->pfnOpen = CEOSDataset::Open;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
}

View file

@ -0,0 +1,379 @@
/******************************************************************************
* $Id: ceosopen.c 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: CEOS Translator
* Purpose: Implementation of non-GDAL dependent CEOS support.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
* Copyright (c) 2007-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 "ceosopen.h"
CPL_CVSID("$Id: ceosopen.c 27745 2014-09-27 16:38:57Z goatbar $");
/************************************************************************/
/* CEOSScanInt() */
/* */
/* Read up to nMaxChars from the passed string, and interpret */
/* as an integer. */
/************************************************************************/
static long CEOSScanInt( const char * pszString, int nMaxChars )
{
char szWorking[33];
int i;
if( nMaxChars > 32 || nMaxChars == 0 )
nMaxChars = 32;
for( i = 0; i < nMaxChars && pszString[i] != '\0'; i++ )
szWorking[i] = pszString[i];
szWorking[i] = '\0';
return( atoi(szWorking) );
}
/************************************************************************/
/* CEOSReadRecord() */
/* */
/* Read a single CEOS record at the current point in the file. */
/* Return NULL after reporting an error if it fails, otherwise */
/* return the record. */
/************************************************************************/
CEOSRecord * CEOSReadRecord( CEOSImage *psImage )
{
GByte abyHeader[12];
CEOSRecord *psRecord;
/* -------------------------------------------------------------------- */
/* Read the standard CEOS header. */
/* -------------------------------------------------------------------- */
if( VSIFEofL( psImage->fpImage ) )
return NULL;
if( VSIFReadL( abyHeader, 1, 12, psImage->fpImage ) != 12 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Ran out of data reading CEOS record." );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Extract this information. */
/* -------------------------------------------------------------------- */
psRecord = (CEOSRecord *) CPLMalloc(sizeof(CEOSRecord));
if( psImage->bLittleEndian )
{
CPL_SWAP32PTR( abyHeader + 0 );
CPL_SWAP32PTR( abyHeader + 8 );
}
psRecord->nRecordNum = abyHeader[0] * 256 * 256 * 256
+ abyHeader[1] * 256 * 256
+ abyHeader[2] * 256
+ abyHeader[3];
psRecord->nRecordType = abyHeader[4] * 256 * 256 * 256
+ abyHeader[5] * 256 * 256
+ abyHeader[6] * 256
+ abyHeader[7];
psRecord->nLength = abyHeader[8] * 256 * 256 * 256
+ abyHeader[9] * 256 * 256
+ abyHeader[10] * 256
+ abyHeader[11];
/* -------------------------------------------------------------------- */
/* Does it look reasonable? We assume there can't be too many */
/* records and that the length must be between 12 and 200000. */
/* -------------------------------------------------------------------- */
if( psRecord->nRecordNum < 0 || psRecord->nRecordNum > 200000
|| psRecord->nLength < 12 || psRecord->nLength > 200000 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"CEOS record leader appears to be corrupt.\n"
"Record Number = %d, Record Length = %d\n",
psRecord->nRecordNum, psRecord->nLength );
CPLFree( psRecord );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Read the remainder of the record into a buffer. Ensure that */
/* the first 12 bytes gets moved into this buffer as well. */
/* -------------------------------------------------------------------- */
psRecord->pachData = (char *) VSIMalloc(psRecord->nLength );
if( psRecord->pachData == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Out of memory allocated %d bytes for CEOS record data.\n"
"Are you sure you aren't leaking CEOSRecords?\n",
psRecord->nLength );
CPLFree( psRecord );
return NULL;
}
memcpy( psRecord->pachData, abyHeader, 12 );
if( (int)VSIFReadL( psRecord->pachData + 12, 1, psRecord->nLength-12,
psImage->fpImage )
!= psRecord->nLength - 12 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Short read on CEOS record data.\n" );
CPLFree( psRecord );
return NULL;
}
return psRecord;
}
/************************************************************************/
/* CEOSDestroyRecord() */
/* */
/* Free a record. */
/************************************************************************/
void CEOSDestroyRecord( CEOSRecord * psRecord )
{
CPLFree( psRecord->pachData );
CPLFree( psRecord );
}
/************************************************************************/
/* CEOSOpen() */
/************************************************************************/
/**
* Open a CEOS transfer.
*
* @param pszFilename The name of the CEOS imagery file (ie. imag_01.dat).
* @param pszAccess An fopen() style access string. Should be either "rb" for
* read-only access, or "r+b" for read, and update access.
*
* @return A CEOSImage pointer as a handle to the image. The CEOSImage also
* has various information about the image available. A NULL is returned
* if an error occurs.
*/
CEOSImage * CEOSOpen( const char * pszFilename, const char * pszAccess )
{
VSILFILE *fp;
CEOSRecord *psRecord;
CEOSImage *psImage;
int nSeqNum, i;
GByte abyHeader[16];
/* -------------------------------------------------------------------- */
/* Try to open the imagery file. */
/* -------------------------------------------------------------------- */
fp = VSIFOpenL( pszFilename, pszAccess );
if( fp == NULL )
{
CPLError( CE_Failure, CPLE_OpenFailed,
"Failed to open CEOS file `%s' with access `%s'.\n",
pszFilename, pszAccess );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Create a CEOSImage structure, and initialize it. */
/* -------------------------------------------------------------------- */
psImage = (CEOSImage *) CPLCalloc(1,sizeof(CEOSImage));
psImage->fpImage = fp;
psImage->nPixels = psImage->nLines = psImage->nBands = 0;
/* -------------------------------------------------------------------- */
/* Preread info on the first record, to establish if it is */
/* little endian. */
/* -------------------------------------------------------------------- */
VSIFReadL( abyHeader, 16, 1, fp );
VSIFSeekL( fp, 0, SEEK_SET );
if( abyHeader[0] != 0 || abyHeader[1] != 0 )
psImage->bLittleEndian = TRUE;
/* -------------------------------------------------------------------- */
/* Try to read the header record. */
/* -------------------------------------------------------------------- */
psRecord = CEOSReadRecord( psImage );
if( psRecord == NULL )
{
CEOSClose( psImage );
return NULL;
}
if( psRecord->nRecordType != CRT_IMAGE_FDR )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Got a %X type record, instead of the expected\n"
"file descriptor record on file %s.\n",
psRecord->nRecordType, pszFilename );
CEOSDestroyRecord( psRecord );
CEOSClose( psImage );
return NULL;
}
/* -------------------------------------------------------------------- */
/* The sequence number should be 2 indicating this is the */
/* imagery file. */
/* -------------------------------------------------------------------- */
nSeqNum = CEOSScanInt( psRecord->pachData + 44, 4 );
if( nSeqNum != 2 )
{
CPLError( CE_Warning, CPLE_AppDefined,
"Got a %d file sequence number, instead of the expected\n"
"2 indicating imagery on file %s.\n"
"Continuing to access anyways.\n",
nSeqNum, pszFilename );
}
/* -------------------------------------------------------------------- */
/* Extract various information. */
/* -------------------------------------------------------------------- */
psImage->nImageRecCount = CEOSScanInt( psRecord->pachData+180, 6 );
psImage->nImageRecLength = CEOSScanInt( psRecord->pachData+186, 6 );
psImage->nBitsPerPixel = CEOSScanInt( psRecord->pachData+216, 4 );
psImage->nBands = CEOSScanInt( psRecord->pachData+232, 4 );
psImage->nLines = CEOSScanInt( psRecord->pachData+236, 8 );
psImage->nPixels = CEOSScanInt( psRecord->pachData+248, 8 );
psImage->nPrefixBytes = CEOSScanInt( psRecord->pachData+276, 4 );
psImage->nSuffixBytes = CEOSScanInt( psRecord->pachData+288, 4 );
if( psImage->nImageRecLength <= 0 ||
psImage->nPrefixBytes < 0 ||
psImage->nBands > INT_MAX / psImage->nImageRecLength ||
(size_t)psImage->nBands > INT_MAX / sizeof(int))
{
CEOSDestroyRecord( psRecord );
CEOSClose( psImage );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Try to establish the layout of the imagery data. */
/* -------------------------------------------------------------------- */
psImage->nLineOffset = psImage->nBands * psImage->nImageRecLength;
psImage->panDataStart = (int *) VSIMalloc(sizeof(int) * psImage->nBands);
if( psImage->panDataStart == NULL )
{
CEOSDestroyRecord( psRecord );
CEOSClose( psImage );
return NULL;
}
for( i = 0; i < psImage->nBands; i++ )
{
psImage->panDataStart[i] =
psRecord->nLength + i * psImage->nImageRecLength
+ 12 + psImage->nPrefixBytes;
}
CEOSDestroyRecord( psRecord );
return psImage;
}
/************************************************************************/
/* CEOSReadScanline() */
/************************************************************************/
/**
* Read a scanline of image.
*
* @param psCEOS The CEOS dataset handle returned by CEOSOpen().
* @param nBand The band number (ie. 1, 2, 3).
* @param nScanline The scanline requested, one based.
* @param pData The data buffer to read into. Must be at least nPixels *
* nBitesPerPixel bits long.
*
* @return CPLErr Returns error indicator or CE_None if the read succeeds.
*/
CPLErr CEOSReadScanline( CEOSImage * psCEOS, int nBand, int nScanline,
void * pData )
{
int nOffset, nBytes;
/*
* As a short cut, I currently just seek to the data, and read it
* raw, rather than trying to read ceos records properly.
*/
nOffset = psCEOS->panDataStart[nBand-1]
+ (nScanline-1) * psCEOS->nLineOffset;
if( VSIFSeekL( psCEOS->fpImage, nOffset, SEEK_SET ) != 0 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Seek to %d for scanline %d failed.\n",
nOffset, nScanline );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Read the data. */
/* -------------------------------------------------------------------- */
nBytes = psCEOS->nPixels * psCEOS->nBitsPerPixel / 8;
if( (int) VSIFReadL( pData, 1, nBytes, psCEOS->fpImage ) != nBytes )
{
CPLError( CE_Failure, CPLE_FileIO,
"Read of %d bytes for scanline %d failed.\n",
nBytes, nScanline );
return CE_Failure;
}
return CE_None;
}
/************************************************************************/
/* CEOSClose() */
/************************************************************************/
/**
* Close a CEOS transfer. Any open files are closed, and memory deallocated.
*
* @param psCEOS The CEOSImage handle from CEOSOpen to be closed.
*/
void CEOSClose( CEOSImage * psCEOS )
{
CPLFree( psCEOS->panDataStart );
VSIFCloseL( psCEOS->fpImage );
CPLFree( psCEOS );
}

View file

@ -0,0 +1,108 @@
/******************************************************************************
* $Id: ceosopen.h 20996 2010-10-28 18:38:15Z rouault $
*
* Project: CEOS Translator
* Purpose: Public (C callable) interface for CEOS and related formats such
* as Spot CAP. This stuff can be used independently of GDAL.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* 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.
****************************************************************************/
#ifndef _CEOSOPEN_H_INCLUDED
#define _CEOSOPEN_H_INCLUDED
/* -------------------------------------------------------------------- */
/* Include standard portability stuff. */
/* -------------------------------------------------------------------- */
#include "cpl_conv.h"
#include "cpl_string.h"
/* -------------------------------------------------------------------- */
/* Base ``class'' for ceos records. */
/* -------------------------------------------------------------------- */
CPL_C_START
typedef struct {
int nRecordNum;
GUInt32 nRecordType;
int nLength;
char *pachData;
}CEOSRecord;
/* well known record types */
#define CRT_IMAGE_FDR 0x3FC01212
#define CRT_IMAGE_DATA 0xEDED1212
/* -------------------------------------------------------------------- */
/* Main CEOS info structure. */
/* -------------------------------------------------------------------- */
typedef struct {
/* public information */
int nPixels;
int nLines;
int nBands;
int nBitsPerPixel;
/* private information */
VSILFILE *fpImage;
int bLittleEndian;
int nImageRecCount;
int nImageRecLength;
int nPrefixBytes;
int nSuffixBytes;
int *panDataStart;
int nLineOffset;
} CEOSImage;
/* -------------------------------------------------------------------- */
/* External Prototypes */
/* -------------------------------------------------------------------- */
CEOSImage CPL_ODLL *CEOSOpen( const char *, const char * );
void CPL_ODLL CEOSClose( CEOSImage * );
CPLErr CPL_ODLL CEOSReadScanline( CEOSImage *psImage, int nBand,
int nScanline, void * pData );
/* -------------------------------------------------------------------- */
/* Internal prototypes. */
/* -------------------------------------------------------------------- */
CEOSRecord CPL_ODLL *CEOSReadRecord( CEOSImage * );
void CPL_ODLL CEOSDestroyRecord( CEOSRecord * );
CPL_C_END
#endif /* ndef _CEOSOPEN_H_INCLUDED */

View file

@ -0,0 +1,69 @@
/******************************************************************************
* $Id: ceostest.c 20504 2010-09-02 02:40:49Z warmerdam $
*
* Project: CEOS Translator
* Purpose: Test mainline.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* 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 "ceosopen.h"
/************************************************************************/
/* main() */
/************************************************************************/
int main( int nArgc, char ** papszArgv )
{
const char *pszFilename;
FILE *fp;
CEOSRecord *psRecord;
int nPosition = 0;
if( nArgc > 1 )
pszFilename = papszArgv[1];
else
pszFilename = "imag_01.dat";
fp = VSIFOpenL( pszFilename, "rb" );
if( fp == NULL )
{
fprintf( stderr, "Can't open %s at all.\n", pszFilename );
exit( 1 );
}
while( !VSIFEofL(fp)
&& (psRecord = CEOSReadRecord( fp )) != NULL )
{
printf( "%9d:%4d:%8x:%d\n",
nPosition, psRecord->nRecordNum,
psRecord->nRecordType, psRecord->nLength );
CEOSDestroyRecord( psRecord );
nPosition = (int) VSIFTellL( fp );
}
VSIFCloseL( fp );
exit( 0 );
}

View file

@ -0,0 +1,13 @@
OBJ = ceosopen.obj ceosdataset.obj
GDAL_ROOT = ..\..
!INCLUDE $(GDAL_ROOT)\nmake.opt
default: $(OBJ)
xcopy /D /Y *.obj ..\o
clean:
-del *.obj

View file

@ -0,0 +1,18 @@
OBJ = sar_ceosdataset.o \
ceosrecipe.o ceossar.o ceos.o link.o
include ../../GDALmake.opt
CPPFLAGS := -I../raw $(CPPFLAGS)
default: $(OBJ:.o=.$(OBJ_EXT))
$(O_OBJ): ../raw/rawdataset.h
clean:
rm -f *.o $(O_OBJ)
install-obj: $(O_OBJ:.o=.$(OBJ_EXT))

View file

@ -0,0 +1,408 @@
/******************************************************************************
* $Id: ceos.c 20996 2010-10-28 18:38:15Z rouault $
*
* Project: ASI CEOS Translator
* Purpose: Core CEOS functions.
* Author: Paul Lahaie, pjlahaie@atlsci.com
*
******************************************************************************
* Copyright (c) 2000, Atlantis Scientific Inc
*
* 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 "ceos.h"
CPL_CVSID("$Id: ceos.c 20996 2010-10-28 18:38:15Z rouault $");
/* Function implementations of functions described in ceos.h */
void CeosUpdateHeaderFromBuffer(CeosRecord_t *record);
void InitEmptyCeosRecord(CeosRecord_t *record, int32 sequence, CeosTypeCode_t typecode, int32 length)
{
if(record)
{
if((record->Buffer = HMalloc(length)) == NULL)
{
return;
}
/* First we zero fill the buffer */
memset(record->Buffer,0,length);
/* Setup values inside the CeosRecord_t header */
record->Sequence = sequence;
record->Flavour = 0;
record->FileId = 0;
record->TypeCode = typecode;
record->Subsequence = 0;
record->Length = length;
/* Now we fill in the buffer portion as well */
NativeToCeos( record->Buffer+__SEQUENCE_OFF, &(record->Sequence), sizeof(record->Sequence), sizeof( record->Sequence ) );
memcpy(record->Buffer+__TYPE_OFF, &( record->TypeCode.Int32Code ), sizeof( record->TypeCode.Int32Code ) );
NativeToCeos( record->Buffer+__LENGTH_OFF, &length, sizeof( length ), sizeof( length ) );
}
}
void InitCeosRecord(CeosRecord_t *record, uchar *buffer)
{
if(record && buffer)
{
InitCeosRecordWithHeader(record, buffer, buffer+__CEOS_HEADER_LENGTH);
}
}
void InitCeosRecordWithHeader(CeosRecord_t *record, uchar *header, uchar *buffer)
{
if(record && buffer && header)
{
if( record->Length != 0 )
record->Length = DetermineCeosRecordBodyLength( header );
if((record->Buffer = HMalloc(record->Length)) == NULL)
{
record->Length = 0;
return;
}
/* First copy the header then the buffer */
memcpy(record->Buffer,header,__CEOS_HEADER_LENGTH);
/* Now we copy the rest */
memcpy(record->Buffer+__CEOS_HEADER_LENGTH,buffer,record->Length-__CEOS_HEADER_LENGTH);
/* Now we fill in the rest of the structure! */
memcpy(&(record->TypeCode.Int32Code),header+__TYPE_OFF,sizeof(record->TypeCode.Int32Code));
CeosToNative(&(record->Sequence),header+__SEQUENCE_OFF,sizeof(record->Sequence), sizeof( record->Sequence ) );
}
}
int DetermineCeosRecordBodyLength(const uchar *header)
{
int i;
if(header)
{
CeosToNative(&i,header+__LENGTH_OFF,sizeof( i ), sizeof( i ) );
return i;
}
return -1;
}
void DeleteCeosRecord(CeosRecord_t *record)
{
if(record)
{
if(record->Buffer)
{
HFree(record->Buffer);
record->Buffer = NULL;
}
HFree( record );
}
}
void GetCeosRecordStruct(const CeosRecord_t *record,void *struct_ptr)
{
if(record && struct_ptr && record->Buffer)
{
memcpy(record->Buffer,struct_ptr,record->Length);
}
}
void PutCeosRecordStruct(CeosRecord_t *record,const void *struct_ptr)
{
int Length;
if(record && struct_ptr)
{
CeosToNative( &Length, struct_ptr, sizeof( Length ), sizeof( Length ) );
memcpy(record->Buffer,struct_ptr,Length);
CeosUpdateHeaderFromBuffer(record);
}
}
void GetCeosField(CeosRecord_t *record, int32 start_byte,
const char *format, void *value)
{
int field_size;
char *d_ptr;
char *mod_buf = NULL;
field_size = atoi(format+1);
if(field_size < 1)
{
return;
}
/* Check for out of bounds */
if(start_byte + field_size - 1 > record->Length)
{
return;
}
if((mod_buf = (char *) HMalloc(field_size + 1)) == NULL)
{
return;
}
memcpy(mod_buf,record->Buffer+(start_byte-1), field_size);
mod_buf[field_size] = '\0';
/* Switch on format type */
switch(format[0])
{
case 'b':
case 'B':
/* Binary data type */
if(field_size > 1)
{
CeosToNative( value, mod_buf, field_size, field_size );
} else {
memcpy( value, mod_buf, field_size );
}
break;
case 'i':
case 'I':
/* Integer type */
*( (int *)value) = atoi(mod_buf);
break;
case 'f':
case 'F':
case 'e':
case 'E':
/* Double precision float data type */
/* Change the 'D' exponent separators to 'e' */
if( ( d_ptr = strchr(mod_buf, 'd') ) != NULL)
{
*d_ptr = 'e';
}
if( ( d_ptr = strchr(mod_buf, 'D') ) != NULL)
{
*d_ptr = 'e';
}
*( (double *)value) = strtod(mod_buf,NULL);
break;
case 'a':
case 'A':
/* ASCII.. We just easily extract it */
( (char *)value)[field_size] = '\0';
memcpy( value, mod_buf, field_size );
break;
default:
/* Unknown format */
return;
}
HFree(mod_buf);
}
void SetCeosField(CeosRecord_t *record, int32 start_byte, char *format, void *value)
{
int field_size;
char * temp_buf = NULL;
char printf_format[ 20 ];
field_size = 0;
sscanf(&format[1], "%d", &field_size);
if(field_size < 1)
{
return;
}
/* Check for bounds */
if(start_byte + field_size - 1 > record->Length)
{
return;
}
/* Make a local buffer to print into */
if((temp_buf = (char *) HMalloc(field_size+1)) == NULL)
{
return;
}
switch(format[0])
{
case 'b':
case 'B':
/* Binary data type */
if(field_size > 1)
{
NativeToCeos( value, temp_buf, field_size, field_size );
} else {
memcpy(value,temp_buf,field_size);
}
break;
case 'i':
case 'I':
/* Integer data type */
sprintf( printf_format,"%%%s%c",format+1, 'd');
sprintf( temp_buf, printf_format, *(int *) value);
break;
case 'f':
case 'F':
/* Double precision floating point data type */
sprintf(printf_format, "%%%s%c", format+1, 'g');
sprintf(temp_buf, printf_format, *(double *)value);
break;
case 'e':
case 'E':
/* Double precision floating point data type (forced exponent) */
sprintf(printf_format,"%%%s%c", format+1, 'e');
sprintf(temp_buf, printf_format, *(double *)value);
break;
case 'a':
case 'A':
strncpy(temp_buf,value,field_size+1);
temp_buf[field_size] = '0';
break;
default:
/* Unknown format */
return;
}
memcpy(record->Buffer + start_byte -1, temp_buf, field_size);
HFree(temp_buf);
}
void SetIntCeosField(CeosRecord_t *record, int32 start_byte, int32 length, int32 value)
{
int integer_value = value;
char total_len[12]; /* 12 because 2^32 -> 4294967296 + I + null */
sprintf(total_len,"I%d",length);
SetCeosField(record,start_byte,total_len,&integer_value);
}
CeosRecord_t *FindCeosRecord(Link_t *record_list, CeosTypeCode_t typecode, int32 fileid, int32 flavour, int32 subsequence)
{
Link_t *Link;
CeosRecord_t *record;
for( Link = record_list; Link != NULL; Link = Link->next )
{
record = (CeosRecord_t *)Link->object;
if( (record->TypeCode.Int32Code == typecode.Int32Code)
&& ( ( fileid == -1 ) || ( record->FileId == fileid ) )
&& ( ( flavour == -1 ) || ( record->Flavour == flavour ) )
&& ( ( subsequence == -1 ) || ( record->Subsequence == subsequence ) ) )
return record;
}
return NULL;
}
void SerializeCeosRecordsToFile(Link_t *record_list, VSILFILE *fp)
{
Link_t *list;
CeosRecord_t crec;
unsigned char *Buffer;
list = record_list;
while(list != NULL)
{
memcpy(&crec,list->object,sizeof(CeosRecord_t));
Buffer = crec.Buffer;
crec.Buffer = NULL;
VSIFWriteL(&crec,sizeof(CeosRecord_t),1,fp);
VSIFWriteL(Buffer,crec.Length,1,fp);
}
}
void SerializeCeosRecordsFromFile(Link_t *record_list, VSILFILE *fp)
{
CeosRecord_t *crec;
Link_t *Link;
while(!VSIFEofL(fp))
{
crec = HMalloc(sizeof(CeosRecord_t));
VSIFReadL(crec,sizeof(CeosRecord_t),1,fp);
crec->Buffer = HMalloc(crec->Length * sizeof(char) );
VSIFReadL(crec->Buffer,sizeof(char),crec->Length,fp);
Link = ceos2CreateLink(crec);
AddLink(record_list,Link);
}
}
void CeosUpdateHeaderFromBuffer(CeosRecord_t *record)
{
if(record && record->Buffer)
{
CeosToNative( &( record->Length ), record->Buffer+__LENGTH_OFF, sizeof(record->Length ), sizeof( record->Length ) );
memcpy(&(record->TypeCode.Int32Code),record->Buffer+__TYPE_OFF,sizeof(record->TypeCode.Int32Code));
CeosToNative(&(record->Sequence),record->Buffer+__SEQUENCE_OFF,sizeof(record->Sequence ), sizeof( record->Sequence ) );
}
record->Subsequence = 0;
}
#ifdef CPL_LSB
void swapbyte(void *dst,void *src,int toswap)
{
int i,e;
unsigned char *in = (unsigned char *) src;
unsigned char *out = (unsigned char *) dst;
for(i = 0,e=toswap;i < toswap;i++,e--)
{
out[i] = in[e-1];
}
}
void NativeToCeos( void *dst, const void *src, const size_t len, const size_t swapunit)
{
int i;
int remainder;
int units;
remainder = len % swapunit;
units = len - remainder;
for(i = 0;i < units; i += swapunit )
{
swapbyte( ( unsigned char *) dst + i, ( unsigned char * ) src + i, swapunit);
}
if(remainder)
{
memcpy( ( unsigned char * ) dst + i, ( unsigned char * ) src + i, remainder );
}
}
#endif

View file

@ -0,0 +1,332 @@
/******************************************************************************
* $Id: ceos.h 20996 2010-10-28 18:38:15Z rouault $
*
* Project: ASI CEOS Translator
* Purpose: CEOS library prototypes
* Author: Paul Lahaie, pjlahaie@atlsci.com
*
******************************************************************************
* Copyright (c) 2000, Atlantis Scientific Inc
*
* 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.
****************************************************************************/
#ifndef __CEOS_H
#define __CEOS_H
#include "cpl_conv.h"
CPL_C_START
#define int32 GInt32
#define TBool int
#define uchar unsigned char
typedef struct Link_t_struct
{
struct Link_t_struct *next;
void *object;
} Link_t;
#define HMalloc CPLMalloc
#define HFree CPLFree
#define HCalloc CPLCalloc
Link_t *ceos2CreateLink( void * pObject );
Link_t *InsertLink(Link_t *psList, Link_t *psLink);
void DestroyList( Link_t *psList );
Link_t *AddLink( Link_t *psList, Link_t *psLink );
/* Basic CEOS header defs */
#define __SEQUENCE_OFF 0
#define __TYPE_OFF 4
#define __LENGTH_OFF 8
#define __CEOS_HEADER_LENGTH 12
/* Defines for CEOS banding type */
#define __CEOS_IL_PIXEL 1
#define __CEOS_IL_LINE 2
#define __CEOS_IL_BAND 3
/* Defines for CEOS data types */
#define __CEOS_TYP_CHAR 1
#define __CEOS_TYP_UCHAR 2
#define __CEOS_TYP_SHORT 3
#define __CEOS_TYP_USHORT 4
#define __CEOS_TYP_LONG 5
#define __CEOS_TYP_ULONG 6
#define __CEOS_TYP_FLOAT 7
#define __CEOS_TYP_DOUBLE 8
#define __CEOS_TYP_COMPLEX_CHAR 9
#define __CEOS_TYP_COMPLEX_UCHAR 10
#define __CEOS_TYP_COMPLEX_SHORT 11
#define __CEOS_TYP_COMPLEX_USHORT 12
#define __CEOS_TYP_COMPLEX_LONG 13
#define __CEOS_TYP_COMPLEX_ULONG 14
#define __CEOS_TYP_COMPLEX_FLOAT 15
#define __CEOS_TYP_CCP_COMPLEX_FLOAT 16 /* COMPRESSED CROSS PRODUCT */
#define __CEOS_TYP_PALSAR_COMPLEX_SHORT 17 /* PALSAR - treat as COMPLEX SHORT*/
/* Defines for CEOS file names */
#define __CEOS_VOLUME_DIR_FILE 0
#define __CEOS_LEADER_FILE 1
#define __CEOS_IMAGRY_OPT_FILE 2
#define __CEOS_TRAILER_FILE 3
#define __CEOS_NULL_VOL_FILE 4
#define __CEOS_ANY_FILE -1
/* Defines for Recipe values */
#define __CEOS_REC_NUMCHANS 1
#define __CEOS_REC_INTERLEAVE 2
#define __CEOS_REC_DATATYPE 3
#define __CEOS_REC_BPR 4
#define __CEOS_REC_LINES 5
#define __CEOS_REC_TBP 6
#define __CEOS_REC_BBP 7
#define __CEOS_REC_PPL 8
#define __CEOS_REC_LBP 9
#define __CEOS_REC_RBP 10
#define __CEOS_REC_BPP 11
#define __CEOS_REC_RPL 12
#define __CEOS_REC_PPR 13
#define __CEOS_REC_IDS 14
#define __CEOS_REC_FDL 15
#define __CEOS_REC_PIXORD 16
#define __CEOS_REC_LINORD 17
#define __CEOS_REC_PRODTYPE 18
#define __CEOS_REC_RECORDSIZE 19
#define __CEOS_REC_SUFFIX_SIZE 20
#define __CEOS_REC_PDBPR 21
/* Defines for Recipe Types */
#define __CEOS_REC_TYP_A 1
#define __CEOS_REC_TYP_B 2
#define __CEOS_REC_TYP_I 3
/* Defines for SAR Embedded info */
#define __CEOS_SAR_ACQ_YEAR 1
#define __CEOS_SAR_ACQ_DAY 2
#define __CEOS_SAR_ACQ_MSEC 4
#define __CEOS_SAR_TRANS_POL 8
#define __CEOS_SAR_PULSE_REP 16
#define __CEOS_SAR_SLANT_FIRST 32
#define __CEOS_SAR_SLANT_MID 64
#define __CEOS_SAR_SLANT_LAST 128
/* Maximum size of LUT for Calibration records */
#define __CEOS_RADAR_MAX_LUT 512
#define __CEOS_RADAR_FLIP_DATE 19980101
#define __CEOS_RADAR_FACILITY "CDPF-RSAT"
typedef union
{
int32 Int32Code;
struct
{
uchar Subtype1;
uchar Type;
uchar Subtype2;
uchar Subtype3;
} UCharCode;
} CeosTypeCode_t;
typedef struct
{
int32 Sequence;
CeosTypeCode_t TypeCode;
int32 Length;
int32 Flavour;
int32 Subsequence;
int32 FileId;
uchar * Buffer;
} CeosRecord_t;
struct CeosSARImageDesc
{
TBool ImageDescValid;
int NumChannels;
int32 ChannelInterleaving;
int32 DataType;
int BytesPerRecord;
int Lines;
int TopBorderPixels;
int BottomBorderPixels;
int PixelsPerLine;
int LeftBorderPixels;
int RightBorderPixels;
int BytesPerPixel;
int RecordsPerLine;
int PixelsPerRecord;
int ImageDataStart;
int ImageSuffixData;
int FileDescriptorLength;
int32 PixelOrder;
int32 LineOrder;
int PixelDataBytesPerRecord;
};
typedef struct
{
int32 Flavour;
int32 Sensor;
int32 ProductType;
int32 FileNamingConvention;
TBool VolumeDirectoryFile;
TBool SARLeaderFile;
TBool ImagryOptionsFile;
TBool SARTrailerFile;
TBool NullVolumeDirectoryFile;
struct CeosSARImageDesc ImageDesc;
Link_t * RecordList;
} CeosSARVolume_t;
typedef struct
{
int ImageDescValue;
int Override;
int FileId;
struct { unsigned char Subtype1,
Type,
Subtype2,
Subtype3;
} TypeCode;
int Offset;
int Length;
int Type;
} CeosRecipeType_t;
typedef struct
{
CeosRecipeType_t *Recipe;
} CeosSARImageDescRecipe_t;
typedef struct
{
int32 ValidFields;
TBool SensorUpdate;
int32 AcquisitionYear;
int32 AcquisitionDay;
int32 AcquisitionMsec;
int32 TransmittedPolarization;
int32 ReceivedPolarization;
int32 PulsRepetitionFrequency;
int32 SlantRangeFirstPixel;
int32 SlantRangeMidPixel;
int32 SlantRangeLastPixel;
} CeosSAREmbeddedInfo_t;
typedef struct
{
double Slant[ 6 ];
double Lut[ 512 ];
double SemiMajorAxis;
double PlatformLatitude;
double CalibrationScale;
int NumberOfSamples;
int Increment;
TBool PossiblyFlipped;
} CeosRadarCalibration_t;
/* Function prototypes */
void InitEmptyCeosRecord(CeosRecord_t *record, int32 sequence, CeosTypeCode_t typecode, int32 length);
void InitCeosRecord(CeosRecord_t *record, uchar *buffer);
void InitCeosRecordWithHeader(CeosRecord_t *record, uchar *header, uchar *buffer);
int DetermineCeosRecordBodyLength(const uchar *header);
void DeleteCeosRecord(CeosRecord_t *record);
void GetCeosRecordStruct(const CeosRecord_t *record, void *struct_ptr);
void PutCeosRecordStruct(CeosRecord_t *record, const void *struct_ptr);
void GetCeosField(CeosRecord_t *, int32, const char *, void *);
void SetCeosField(CeosRecord_t *record, int32 start_byte, char *format, void *value);
void SetIntCeosField(CeosRecord_t *record, int32 start_byte, int32 length, int32 value);
CeosRecord_t *FindCeosRecord(Link_t *record_list, CeosTypeCode_t typecode, int32 fileid, int32 flavour, int32 subsequence);
void SerializeCeosRecordsToFile(Link_t *record_list, VSILFILE *fp);
void SerializeCeosRecordsFromFile( Link_t *record_list, VSILFILE *fp );
void InitCeosSARVolume( CeosSARVolume_t *volume, int32 file_name_convention );
void GetCeosSARImageDesc( CeosSARVolume_t *volume );
void GetCeosSARImageDescInfo(CeosSARVolume_t *volume, CeosSARImageDescRecipe_t *recipe);
void CalcCeosSARImageFilePosition(CeosSARVolume_t *volume, int channel, int line, int *record, int *file_offset);
int32 GetCeosSARImageData(CeosSARVolume_t *volume, CeosRecord_t *processed_data_record, int channel, int xoff, int xsize, int bufsize, uchar *buffer);
void DetermineCeosSARPixelOrder(CeosSARVolume_t *volume, CeosRecord_t *record );
void GetCeosSAREmbeddedInfo(CeosSARVolume_t *volume, CeosRecord_t *processed_data_record, CeosSAREmbeddedInfo_t *info);
void DeleteCeosSARVolume(CeosSARVolume_t *volume);
void RegisterRecipes(void);
void FreeRecipes();
void AddRecipe( int ( *function )( CeosSARVolume_t *volume, void *token ),
void *token, const char *name );
int CeosDefaultRecipe( CeosSARVolume_t *volume, void *token );
int ScanSARRecipeFCN( CeosSARVolume_t *volume, void *token );
/* ceoscalib.c function declarations */
CeosRadarCalibration_t *GetCeosRadarCalibration( CeosSARVolume_t *volume );
/* CEOS byte swapping stuff */
#if defined(CPL_MSB)
#define NativeToCeos(a,b,c,d) memcpy(a,b,c)
#define CeosToNative(a,b,c,d) memcpy(a,b,c)
#else
void NativeToCeos( void *dst, const void *src, const size_t len, const size_t swap_unit);
#define CeosToNative(a,b,c,d) NativeToCeos(a,b,c,d)
#endif
/* Recipe defines */
CPL_C_END
#endif

View file

@ -0,0 +1,758 @@
/******************************************************************************
* $Id: ceosrecipe.c 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: ASI CEOS Translator
* Purpose: CEOS field layout recipes.
* Author: Paul Lahaie, pjlahaie@atlsci.com
*
******************************************************************************
* Copyright (c) 2000, Atlantis Scientific Inc
*
* 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 "ceos.h"
CPL_CVSID("$Id: ceosrecipe.c 27745 2014-09-27 16:38:57Z goatbar $");
/* Array of Datatypes and their names/values */
typedef struct {
char *String;
int Type;
} CeosStringType_t;
typedef struct {
int (*function)(CeosSARVolume_t *volume, void *token);
void *token;
const char *name;
} RecipeFunctionData_t;
CeosStringType_t CeosDataType[] = { { "IU1", __CEOS_TYP_UCHAR },
{ "IU2", __CEOS_TYP_USHORT },
{ "UI1", __CEOS_TYP_UCHAR },
{ "UI2", __CEOS_TYP_USHORT },
{ "CI*2", __CEOS_TYP_COMPLEX_CHAR },
{ "CI*4", __CEOS_TYP_COMPLEX_SHORT },
{ "CIS4", __CEOS_TYP_COMPLEX_SHORT },
{ "CI*8", __CEOS_TYP_COMPLEX_LONG },
{ "C*8", __CEOS_TYP_COMPLEX_FLOAT },
{ "R*4", __CEOS_TYP_FLOAT },
{ NULL, 0 } };
CeosStringType_t CeosInterleaveType[] = { { "BSQ", __CEOS_IL_BAND },
{ " BSQ", __CEOS_IL_BAND },
{ "BIL", __CEOS_IL_LINE },
{ " BIL", __CEOS_IL_LINE },
{ NULL, 0 } };
#define IMAGE_OPT { 63, 192, 18, 18 }
#define IMAGE_JERS_OPT { 50, 192, 18, 18 } /* Some JERS data uses this instead of IMAGE_OPT */
#define PROC_DATA_REC { 50, 11, 18, 20 }
#define PROC_DATA_REC_ALT { 50, 11, 31, 20 }
#define PROC_DATA_REC_ALT2 { 50, 11, 31, 50 } /* Some cases of ERS 1, 2 */
#define DATA_SET_SUMMARY { 18, 10, 18, 20 }
/* NOTE: This seems to be the generic recipe used for most things */
CeosRecipeType_t RadarSatRecipe[] =
{
{ __CEOS_REC_NUMCHANS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
233, 4, __CEOS_REC_TYP_I }, /* Number of channels */
{ __CEOS_REC_INTERLEAVE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
269, 4, __CEOS_REC_TYP_A }, /* Interleaving type */
{ __CEOS_REC_DATATYPE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
429, 4, __CEOS_REC_TYP_A }, /* Data type */
{ __CEOS_REC_BPR, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
0, 0, __CEOS_REC_TYP_A }, /* For Defeault CEOS, this is done using other vals */
{ __CEOS_REC_LINES, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
237, 8, __CEOS_REC_TYP_I }, /* How many lines */
{ __CEOS_REC_TBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
261, 4, __CEOS_REC_TYP_I },
{ __CEOS_REC_BBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
265, 4, __CEOS_REC_TYP_I }, /* Bottom border pixels */
{ __CEOS_REC_PPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
249, 8, __CEOS_REC_TYP_I }, /* Pixels per line */
{ __CEOS_REC_LBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
245, 4, __CEOS_REC_TYP_I }, /* Left Border Pixels */
{ __CEOS_REC_RBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
257, 4, __CEOS_REC_TYP_I }, /* Isn't available for RadarSAT */
{ __CEOS_REC_BPP, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
225, 4, __CEOS_REC_TYP_I }, /* Bytes Per Pixel */
{ __CEOS_REC_RPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
273, 2, __CEOS_REC_TYP_I }, /* Records per line */
{ __CEOS_REC_PPR, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
0, 0, __CEOS_REC_TYP_I }, /* Pixels Per Record -- need to fill record type */
{ __CEOS_REC_PDBPR, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
281, 8, __CEOS_REC_TYP_I }, /* pixel data bytes per record */
{ __CEOS_REC_IDS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
277, 4, __CEOS_REC_TYP_I }, /* Prefix data per record */
{ __CEOS_REC_FDL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
9, 4, __CEOS_REC_TYP_B }, /* Length of Imagry Options Header */
{ __CEOS_REC_PIXORD, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
0, 0, __CEOS_REC_TYP_I }, /* Must be calculated */
{ __CEOS_REC_LINORD, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
0, 0, __CEOS_REC_TYP_I }, /* Must be calculated */
{ __CEOS_REC_PRODTYPE, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
0, 0, __CEOS_REC_TYP_I },
{ __CEOS_REC_RECORDSIZE, 1, __CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC,
9, 4, __CEOS_REC_TYP_B }, /* The processed image record size */
/* Some ERS-1 products use an alternate data record subtype2. */
{ __CEOS_REC_RECORDSIZE, 1, __CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC_ALT,
9, 4, __CEOS_REC_TYP_B }, /* The processed image record size */
/* Yet another ERS-1 and ERS-2 alternate data record subtype2. */
{ __CEOS_REC_RECORDSIZE, 1, __CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC_ALT2,
9, 4, __CEOS_REC_TYP_B }, /* The processed image record size */
{ __CEOS_REC_SUFFIX_SIZE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
289, 4, __CEOS_REC_TYP_I }, /* Suffix data per record */
{ 0, 0, 0, { 0, 0, 0, 0 }, 0, 0, 0 } /* Last record is Zero */
} ;
CeosRecipeType_t JersRecipe[] =
{
{ __CEOS_REC_NUMCHANS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
233, 4, __CEOS_REC_TYP_I }, /* Number of channels */
{ __CEOS_REC_INTERLEAVE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
269, 4, __CEOS_REC_TYP_A }, /* Interleaving type */
{ __CEOS_REC_DATATYPE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
429, 4, __CEOS_REC_TYP_A }, /* Data type */
{ __CEOS_REC_BPR, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
0, 0, __CEOS_REC_TYP_A }, /* For Defeault CEOS, this is done using other vals */
{ __CEOS_REC_LINES, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
237, 8, __CEOS_REC_TYP_I }, /* How many lines */
{ __CEOS_REC_TBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
261, 4, __CEOS_REC_TYP_I },
{ __CEOS_REC_BBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
265, 4, __CEOS_REC_TYP_I }, /* Bottom border pixels */
{ __CEOS_REC_PPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
249, 8, __CEOS_REC_TYP_I }, /* Pixels per line */
{ __CEOS_REC_LBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
245, 4, __CEOS_REC_TYP_I }, /* Left Border Pixels */
{ __CEOS_REC_RBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
257, 4, __CEOS_REC_TYP_I }, /* Isn't available for RadarSAT */
{ __CEOS_REC_BPP, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
225, 4, __CEOS_REC_TYP_I }, /* Bytes Per Pixel */
{ __CEOS_REC_RPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
273, 2, __CEOS_REC_TYP_I }, /* Records per line */
{ __CEOS_REC_PPR, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
0, 0, __CEOS_REC_TYP_I }, /* Pixels Per Record -- need to fill record type */
{ __CEOS_REC_PDBPR, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
281, 8, __CEOS_REC_TYP_I }, /* pixel data bytes per record */
{ __CEOS_REC_IDS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
277, 4, __CEOS_REC_TYP_I }, /* Prefix data per record */
{ __CEOS_REC_FDL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
9, 4, __CEOS_REC_TYP_B }, /* Length of Imagry Options Header */
{ __CEOS_REC_PIXORD, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
0, 0, __CEOS_REC_TYP_I }, /* Must be calculated */
{ __CEOS_REC_LINORD, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
0, 0, __CEOS_REC_TYP_I }, /* Must be calculated */
{ __CEOS_REC_PRODTYPE, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
0, 0, __CEOS_REC_TYP_I },
{ __CEOS_REC_RECORDSIZE, 1, __CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC,
9, 4, __CEOS_REC_TYP_B }, /* The processed image record size */
{ __CEOS_REC_SUFFIX_SIZE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT,
289, 4, __CEOS_REC_TYP_I }, /* Suffix data per record */
{ 0, 0, 0, { 0, 0, 0, 0 }, 0, 0, 0 } /* Last record is Zero */
} ;
CeosRecipeType_t ScanSARRecipe[] =
{
{ __CEOS_REC_NUMCHANS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
233, 4, __CEOS_REC_TYP_I }, /* Number of channels */
{ __CEOS_REC_INTERLEAVE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
269, 4, __CEOS_REC_TYP_A }, /* Interleaving type */
{ __CEOS_REC_DATATYPE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
429, 4, __CEOS_REC_TYP_A }, /* Data type */
{ __CEOS_REC_LINES, 1, __CEOS_ANY_FILE, DATA_SET_SUMMARY,
325, 8, __CEOS_REC_TYP_I }, /* How many lines */
{ __CEOS_REC_PPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
249, 8, __CEOS_REC_TYP_I }, /* Pixels per line */
{ __CEOS_REC_BPP, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
225, 4, __CEOS_REC_TYP_I }, /* Bytes Per Pixel */
{ __CEOS_REC_RPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
273, 2, __CEOS_REC_TYP_I }, /* Records per line */
{ __CEOS_REC_IDS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
277, 4, __CEOS_REC_TYP_I }, /* Prefix data per record */
{ __CEOS_REC_FDL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
9, 4, __CEOS_REC_TYP_B }, /* Length of Imagry Options Header */
{ __CEOS_REC_RECORDSIZE, 1, __CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC,
9, 4, __CEOS_REC_TYP_B }, /* The processed image record size */
{ __CEOS_REC_SUFFIX_SIZE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
289, 4, __CEOS_REC_TYP_I }, /* Suffix data per record */
{ 0, 0, 0, { 0, 0, 0, 0 }, 0, 0, 0 } /* Last record is Zero */
} ;
CeosRecipeType_t SIRCRecipe[] =
{
{ __CEOS_REC_NUMCHANS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
233, 4, __CEOS_REC_TYP_I }, /* Number of channels */
{ __CEOS_REC_INTERLEAVE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
269, 4, __CEOS_REC_TYP_A }, /* Interleaving type */
{ __CEOS_REC_DATATYPE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
429, 4, __CEOS_REC_TYP_A }, /* Data type */
{ __CEOS_REC_LINES, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
237, 8, __CEOS_REC_TYP_I }, /* How many lines */
{ __CEOS_REC_TBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
261, 4, __CEOS_REC_TYP_I },
{ __CEOS_REC_BBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
265, 4, __CEOS_REC_TYP_I }, /* Bottom border pixels */
{ __CEOS_REC_PPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
249, 8, __CEOS_REC_TYP_I }, /* Pixels per line */
{ __CEOS_REC_LBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
245, 4, __CEOS_REC_TYP_I }, /* Left Border Pixels */
{ __CEOS_REC_RBP, 0, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
257, 4, __CEOS_REC_TYP_I }, /* Right Border Pixels */
{ __CEOS_REC_BPP, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
225, 4, __CEOS_REC_TYP_I }, /* Bytes Per Pixel */
{ __CEOS_REC_RPL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
273, 2, __CEOS_REC_TYP_I }, /* Records per line */
{ __CEOS_REC_IDS, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
277, 4, __CEOS_REC_TYP_I }, /* Prefix data per record */
{ __CEOS_REC_FDL, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
9, 4, __CEOS_REC_TYP_B }, /* Length of Imagry Options Header */
{ __CEOS_REC_RECORDSIZE, 1, __CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC,
9, 4, __CEOS_REC_TYP_B }, /* The processed image record size */
{ __CEOS_REC_SUFFIX_SIZE, 1, __CEOS_IMAGRY_OPT_FILE, IMAGE_OPT,
289, 4, __CEOS_REC_TYP_I }, /* Suffix data per record */
{ 0, 0, 0, { 0, 0, 0, 0 }, 0, 0, 0 } /* Last record is Zero */
} ;
#undef PROC_DATA_REC
static void ExtractInt( CeosRecord_t *record, int type, unsigned int offset, unsigned int length, int *value );
static char *ExtractString( CeosRecord_t *record, unsigned int offset, unsigned int length, char *string );
static int GetCeosStringType(const CeosStringType_t *CeosType, const char *string);
static int SIRCRecipeFCN( CeosSARVolume_t *volume, void *token );
static int PALSARRecipeFCN( CeosSARVolume_t *volume, void *token );
Link_t *RecipeFunctions = NULL;
void RegisterRecipes( void )
{
AddRecipe( SIRCRecipeFCN, SIRCRecipe, "SIR-C" );
AddRecipe( ScanSARRecipeFCN, ScanSARRecipe, "ScanSAR" );
AddRecipe( CeosDefaultRecipe, RadarSatRecipe, "RadarSat" );
AddRecipe( CeosDefaultRecipe, JersRecipe, "Jers" );
AddRecipe( PALSARRecipeFCN, RadarSatRecipe, "PALSAR-ALOS" );
/* AddRecipe( CeosDefaultRecipe, AtlantisRecipe ); */
}
void FreeRecipes( void )
{
Link_t *link;
for( link = RecipeFunctions; link != NULL; link = link->next )
HFree( link->object );
DestroyList( RecipeFunctions );
RecipeFunctions = NULL;
}
void AddRecipe( int (*function)(CeosSARVolume_t *volume,
void *token),
void *token,
const char *name )
{
RecipeFunctionData_t *TempData;
Link_t *Link;
TempData = HMalloc( sizeof( RecipeFunctionData_t ) );
TempData->function = function;
TempData->token = token;
TempData->name = name;
Link = ceos2CreateLink( TempData );
if( RecipeFunctions == NULL)
{
RecipeFunctions = Link;
} else {
RecipeFunctions = InsertLink( RecipeFunctions, Link );
}
}
int CeosDefaultRecipe( CeosSARVolume_t *volume, void *token )
{
CeosRecipeType_t *recipe;
CeosRecord_t *record;
CeosTypeCode_t TypeCode;
struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
char temp_str[1024];
int i /*, temp_int */;
#define DoExtractInt(a) ExtractInt( record, recipe[i].Type, recipe[i].Offset, recipe[i].Length, &a)
if(token == NULL)
{
return 0;
}
memset(ImageDesc, 0, sizeof( struct CeosSARImageDesc ) );
/* temp_imagerecipe = (CeosSARImageDescRecipe_t *) token;
recipe = temp_imagerecipe->Recipe; */
recipe = token;
for(i = 0; recipe[i].ImageDescValue != 0; i++ )
{
if(recipe[i].Override)
{
TypeCode.UCharCode.Subtype1 = recipe[i].TypeCode.Subtype1;
TypeCode.UCharCode.Type = recipe[i].TypeCode.Type;
TypeCode.UCharCode.Subtype2 = recipe[i].TypeCode.Subtype2;
TypeCode.UCharCode.Subtype3 = recipe[i].TypeCode.Subtype3;
record = FindCeosRecord( volume->RecordList, TypeCode, recipe[i].FileId, -1, -1 );
if(record == NULL)
{
/* temp_int = 0; */
} else {
switch( recipe[i].ImageDescValue )
{
case __CEOS_REC_NUMCHANS:
DoExtractInt( ImageDesc->NumChannels );
break;
case __CEOS_REC_LINES:
DoExtractInt( ImageDesc->Lines );
break;
case __CEOS_REC_BPP:
DoExtractInt( ImageDesc->BytesPerPixel );
break;
case __CEOS_REC_RPL:
DoExtractInt( ImageDesc->RecordsPerLine );
break;
case __CEOS_REC_PDBPR:
DoExtractInt( ImageDesc->PixelDataBytesPerRecord );
break;
case __CEOS_REC_FDL:
DoExtractInt( ImageDesc->FileDescriptorLength );
break;
case __CEOS_REC_IDS:
DoExtractInt( ImageDesc->ImageDataStart );
/*
** This is really reading the quantity of prefix data
** per data record. We want the offset from the very
** beginning of the record to the data, so we add another
** 12 to that. I think some products incorrectly indicate
** 192 (prefix+12) instead of 180 so if we see 192 assume
** the 12 bytes of record start data has already been
** added. Frank Warmerdam.
*/
if( ImageDesc->ImageDataStart != 192 )
ImageDesc->ImageDataStart += 12;
break;
case __CEOS_REC_SUFFIX_SIZE:
DoExtractInt( ImageDesc->ImageSuffixData );
break;
case __CEOS_REC_RECORDSIZE:
DoExtractInt( ImageDesc->BytesPerRecord );
break;
case __CEOS_REC_PPL:
DoExtractInt( ImageDesc->PixelsPerLine );
break;
case __CEOS_REC_TBP:
DoExtractInt( ImageDesc->TopBorderPixels );
break;
case __CEOS_REC_BBP:
DoExtractInt( ImageDesc->BottomBorderPixels );
break;
case __CEOS_REC_LBP:
DoExtractInt( ImageDesc->LeftBorderPixels );
break;
case __CEOS_REC_RBP:
DoExtractInt( ImageDesc->RightBorderPixels );
break;
case __CEOS_REC_INTERLEAVE:
ExtractString( record, recipe[i].Offset, recipe[i].Length, temp_str );
ImageDesc->ChannelInterleaving = GetCeosStringType( CeosInterleaveType, temp_str );
break;
case __CEOS_REC_DATATYPE:
ExtractString( record, recipe[i].Offset, recipe[i].Length, temp_str );
ImageDesc->DataType = GetCeosStringType( CeosDataType, temp_str );
break;
}
}
}
}
/* Some files (Telaviv) don't record the number of pixel groups per line.
* Try to derive it from the size of a data group, and the number of
* bytes of pixel data if necessary.
*/
if( ImageDesc->PixelsPerLine == 0
&& ImageDesc->PixelDataBytesPerRecord != 0
&& ImageDesc->BytesPerPixel != 0 )
{
ImageDesc->PixelsPerLine =
ImageDesc->PixelDataBytesPerRecord / ImageDesc->BytesPerPixel;
CPLDebug( "SAR_CEOS", "Guessing PixelPerLine to be %d\n",
ImageDesc->PixelsPerLine );
}
/* Some files don't have the BytesPerRecord stuff, so we calculate it if possible */
if( ImageDesc->BytesPerRecord == 0 && ImageDesc->RecordsPerLine == 1 &&
ImageDesc->PixelsPerLine > 0 && ImageDesc->BytesPerPixel > 0 )
{
CeosRecord_t *img_rec;
ImageDesc->BytesPerRecord = ImageDesc->PixelsPerLine *
ImageDesc->BytesPerPixel + ImageDesc->ImageDataStart +
ImageDesc->ImageSuffixData ;
TypeCode.UCharCode.Subtype1 = 0xed;
TypeCode.UCharCode.Type = 0xed;
TypeCode.UCharCode.Subtype2 = 0x12;
TypeCode.UCharCode.Subtype3 = 0x12;
img_rec = FindCeosRecord( volume->RecordList, TypeCode,
__CEOS_IMAGRY_OPT_FILE, -1, -1 );
if( img_rec == NULL )
{
CPLDebug( "SAR_CEOS",
"Unable to find imagery rec to check record length." );
return 0;
}
if( img_rec->Length != ImageDesc->BytesPerRecord )
{
CPLDebug( "SAR_CEOS",
"Guessed record length (%d) did not match\n"
"actual imagery record length (%d), recipe fails.",
ImageDesc->BytesPerRecord, img_rec->Length );
return 0;
}
}
if( ImageDesc->PixelsPerRecord == 0 &&
ImageDesc->BytesPerRecord != 0 && ImageDesc->BytesPerPixel != 0 )
{
ImageDesc->PixelsPerRecord = ( ( ImageDesc->BytesPerRecord -
(ImageDesc->ImageSuffixData +
ImageDesc->ImageDataStart )) /
ImageDesc->BytesPerPixel );
if(ImageDesc->PixelsPerRecord > ImageDesc->PixelsPerLine)
ImageDesc->PixelsPerRecord = ImageDesc->PixelsPerLine;
}
/* If we didn't get a data type, try guessing. */
if( ImageDesc->DataType == 0
&& ImageDesc->BytesPerPixel != 0
&& ImageDesc->NumChannels != 0 )
{
int nDataTypeSize = ImageDesc->BytesPerPixel / ImageDesc->NumChannels;
if( nDataTypeSize == 1 )
ImageDesc->DataType = __CEOS_TYP_UCHAR;
else if( nDataTypeSize == 2 )
ImageDesc->DataType = __CEOS_TYP_USHORT;
}
/* Sanity checking */
if( ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
ImageDesc->FileDescriptorLength == 0 || ImageDesc->DataType == 0 ||
ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
{
return 0;
} else {
ImageDesc->ImageDescValid = TRUE;
return 1;
}
}
int ScanSARRecipeFCN( CeosSARVolume_t *volume, void *token )
{
struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
memset( ImageDesc, 0, sizeof( struct CeosSARImageDesc ) );
if( CeosDefaultRecipe( volume, token ) )
{
ImageDesc->Lines *= 2;
return 1;
}
return 0;
}
static int SIRCRecipeFCN( CeosSARVolume_t *volume, void *token )
{
struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
CeosTypeCode_t TypeCode;
CeosRecord_t *record;
char szSARDataFormat[29];
memset( ImageDesc, 0, sizeof( struct CeosSARImageDesc ) );
/* -------------------------------------------------------------------- */
/* First, we need to check if the "SAR Data Format Type */
/* identifier" is set to "COMPRESSED CROSS-PRODUCTS" which is */
/* pretty idiosyncratic to SIRC products. It might also appear */
/* for some other similarly encoded Polarimetric data I suppose. */
/* -------------------------------------------------------------------- */
/* IMAGE_OPT */
TypeCode.UCharCode.Subtype1 = 63;
TypeCode.UCharCode.Type = 192;
TypeCode.UCharCode.Subtype2 = 18;
TypeCode.UCharCode.Subtype3 = 18;
record = FindCeosRecord( volume->RecordList, TypeCode,
__CEOS_IMAGRY_OPT_FILE, -1, -1 );
if( record == NULL )
return 0;
ExtractString( record, 401, 28, szSARDataFormat );
if( !EQUALN( szSARDataFormat, "COMPRESSED CROSS-PRODUCTS", 25) )
return 0;
/* -------------------------------------------------------------------- */
/* Apply normal handling... */
/* -------------------------------------------------------------------- */
CeosDefaultRecipe( volume, token );
/* -------------------------------------------------------------------- */
/* Make sure this looks like the SIRC product we are expecting. */
/* -------------------------------------------------------------------- */
if( ImageDesc->BytesPerPixel != 10 )
return 0;
/* -------------------------------------------------------------------- */
/* Then fix up a few values. */
/* -------------------------------------------------------------------- */
/* It seems the bytes of pixel data per record is just wrong. Fix. */
ImageDesc->PixelDataBytesPerRecord =
ImageDesc->BytesPerPixel * ImageDesc->PixelsPerLine;
ImageDesc->DataType = __CEOS_TYP_CCP_COMPLEX_FLOAT;
/* -------------------------------------------------------------------- */
/* Sanity checking */
/* -------------------------------------------------------------------- */
if( ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
ImageDesc->FileDescriptorLength == 0 || ImageDesc->DataType == 0 ||
ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
{
return 0;
} else {
ImageDesc->ImageDescValid = TRUE;
return 1;
}
}
static int PALSARRecipeFCN( CeosSARVolume_t *volume, void *token )
{
struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
CeosTypeCode_t TypeCode;
CeosRecord_t *record;
char szSARDataFormat[29], szProduct[32];
memset( ImageDesc, 0, sizeof( struct CeosSARImageDesc ) );
/* -------------------------------------------------------------------- */
/* First, we need to check if the "SAR Data Format Type */
/* identifier" is set to "COMPRESSED CROSS-PRODUCTS" which is */
/* pretty idiosyncratic to SIRC products. It might also appear */
/* for some other similarly encoded Polarimetric data I suppose. */
/* -------------------------------------------------------------------- */
/* IMAGE_OPT */
TypeCode.UCharCode.Subtype1 = 63;
TypeCode.UCharCode.Type = 192;
TypeCode.UCharCode.Subtype2 = 18;
TypeCode.UCharCode.Subtype3 = 18;
record = FindCeosRecord( volume->RecordList, TypeCode,
__CEOS_IMAGRY_OPT_FILE, -1, -1 );
if( record == NULL )
return 0;
ExtractString( record, 401, 28, szSARDataFormat );
if( !EQUALN( szSARDataFormat, "INTEGER*18 ", 25) )
return 0;
ExtractString( record, 49, 16, szProduct );
if( !EQUALN( szProduct, "ALOS-", 5 ) )
return 0;
/* -------------------------------------------------------------------- */
/* Apply normal handling... */
/* -------------------------------------------------------------------- */
CeosDefaultRecipe( volume, token );
/* -------------------------------------------------------------------- */
/* Make sure this looks like the SIRC product we are expecting. */
/* -------------------------------------------------------------------- */
if( ImageDesc->BytesPerPixel != 18 )
return 0;
/* -------------------------------------------------------------------- */
/* Then fix up a few values. */
/* -------------------------------------------------------------------- */
ImageDesc->DataType = __CEOS_TYP_PALSAR_COMPLEX_SHORT;
ImageDesc->NumChannels = 6;
/* -------------------------------------------------------------------- */
/* Sanity checking */
/* -------------------------------------------------------------------- */
if( ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
ImageDesc->FileDescriptorLength == 0 || ImageDesc->DataType == 0 ||
ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
{
return 0;
} else {
ImageDesc->ImageDescValid = TRUE;
return 1;
}
}
void GetCeosSARImageDesc( CeosSARVolume_t *volume )
{
Link_t *link;
RecipeFunctionData_t *rec_data;
int (*function)(CeosSARVolume_t *volume, void *token);
if( RecipeFunctions == NULL )
{
RegisterRecipes();
}
if(RecipeFunctions == NULL )
{
return ;
}
for(link = RecipeFunctions; link != NULL; link = link->next)
{
if(link->object)
{
rec_data = link->object;
function = rec_data->function;
if(( *function )( volume, rec_data->token ) )
{
CPLDebug( "CEOS", "Using recipe '%s'.",
rec_data->name );
return;
}
}
}
return ;
}
static void ExtractInt(CeosRecord_t *record, int type, unsigned int offset, unsigned int length, int *value)
{
void *buffer;
char format[32];
buffer = HMalloc( length + 1 );
switch(type)
{
case __CEOS_REC_TYP_A:
sprintf( format, "A%u", length );
GetCeosField( record, offset, format, buffer );
*value = atoi( buffer );
break;
case __CEOS_REC_TYP_B:
sprintf( format, "B%u", length );
#ifdef notdef
GetCeosField( record, offset, format, buffer );
if( length <= 4 )
CeosToNative( value, buffer, length, length );
else
*value = 0;
#else
GetCeosField( record, offset, format, value );
#endif
break;
case __CEOS_REC_TYP_I:
sprintf( format, "I%u", length );
GetCeosField( record, offset, format, value );
break;
}
HFree( buffer );
}
static char *ExtractString( CeosRecord_t *record, unsigned int offset, unsigned int length, char *string )
{
char format[12];
if(string == NULL)
{
string = HMalloc( length + 1 );
}
sprintf( format, "A%u", length );
GetCeosField( record, offset, format, string );
return string;
}
static int GetCeosStringType(const CeosStringType_t *CeosStringType, const char *string)
{
int i;
for(i = 0;CeosStringType[i].String != NULL;i++)
{
if(strncmp(CeosStringType[i].String ,string, strlen( CeosStringType[i].String ) ) == 0 )
{
return CeosStringType[i].Type;
}
}
return 0;
}

View file

@ -0,0 +1,139 @@
/******************************************************************************
* $Id: ceossar.c 27745 2014-09-27 16:38:57Z goatbar $
*
* Project: ASI CEOS Translator
* Purpose: Functions related to CeosSARVolume_t.
* Author: Paul Lahaie, pjlahaie@atlsci.com
*
******************************************************************************
* Copyright (c) 2000, Atlantis Scientific Inc
*
* 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 "ceos.h"
CPL_CVSID("$Id: ceossar.c 27745 2014-09-27 16:38:57Z goatbar $");
extern Link_t *RecipeFunctions;
void InitCeosSARVolume(CeosSARVolume_t *volume, int32 file_name_convention)
{
volume->Flavour = \
volume->Sensor = \
volume->ProductType = 0;
volume->FileNamingConvention = file_name_convention ;
volume->VolumeDirectoryFile =
volume->SARLeaderFile =
volume->SARTrailerFile =
volume->NullVolumeDirectoryFile =
volume->ImageDesc.ImageDescValid = FALSE;
volume->RecordList = NULL;
}
void CalcCeosSARImageFilePosition(CeosSARVolume_t *volume, int channel, int line, int *record, int *file_offset)
{
struct CeosSARImageDesc *ImageDesc;
int TotalRecords=0, TotalBytes=0;
if(record)
*record = 0;
if(file_offset)
*file_offset = 0;
if( volume )
{
if( volume->ImageDesc.ImageDescValid )
{
ImageDesc = &( volume->ImageDesc );
switch( ImageDesc->ChannelInterleaving )
{
case __CEOS_IL_PIXEL:
TotalRecords = (line - 1) * ImageDesc->RecordsPerLine;
TotalBytes = (TotalRecords) * ( ImageDesc->BytesPerRecord );
break;
case __CEOS_IL_LINE:
TotalRecords = (ImageDesc->NumChannels * (line - 1) +
(channel - 1)) * ImageDesc->RecordsPerLine;
TotalBytes = (TotalRecords) * ( ImageDesc->BytesPerRecord ) ;
break;
case __CEOS_IL_BAND:
TotalRecords = (((channel - 1) * ImageDesc->Lines) *
ImageDesc->RecordsPerLine) +
(line - 1) * ImageDesc->RecordsPerLine;
TotalBytes = (TotalRecords) * ( ImageDesc->BytesPerRecord );
break;
}
if(file_offset)
*file_offset = ImageDesc->FileDescriptorLength + TotalBytes;
if(record)
*record = TotalRecords + 1;
}
}
}
int32 GetCeosSARImageData(CPL_UNUSED CeosSARVolume_t *volume,
CPL_UNUSED CeosRecord_t *processed_data_record,
CPL_UNUSED int channel,
CPL_UNUSED int xoff,
CPL_UNUSED int xsize,
CPL_UNUSED int bufsize,
CPL_UNUSED uchar *buffer)
{
return 0;
}
void DetermineCeosSARPixelOrder( CPL_UNUSED CeosSARVolume_t *volume,
CPL_UNUSED CeosRecord_t *record )
{
}
void GetCeosSAREmbeddedInfo(CPL_UNUSED CeosSARVolume_t *volume,
CPL_UNUSED CeosRecord_t *processed_data_record,
CPL_UNUSED CeosSAREmbeddedInfo_t *info)
{
}
void DeleteCeosSARVolume(CeosSARVolume_t *volume)
{
Link_t *Links;
if( volume )
{
if( volume->RecordList )
{
for(Links = volume->RecordList; Links != NULL; Links = Links->next)
{
if(Links->object)
{
DeleteCeosRecord( Links->object );
Links->object = NULL;
}
}
DestroyList( volume->RecordList );
}
HFree( volume );
}
}

Some files were not shown because too many files have changed in this diff Show more