Beispiel #1
0
CPLXMLNode *GDALPamDataset::SerializeToXML( const char *pszVRTPath )

{
    CPLString oFmt;

    if( psPam == NULL )
        return NULL;

/* -------------------------------------------------------------------- */
/*      Setup root node and attributes.                                 */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psDSTree;

    psDSTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMDataset" );

/* -------------------------------------------------------------------- */
/*      SRS                                                             */
/* -------------------------------------------------------------------- */
    if( psPam->pszProjection != NULL && strlen(psPam->pszProjection) > 0 )
        CPLSetXMLValue( psDSTree, "SRS", psPam->pszProjection );

/* -------------------------------------------------------------------- */
/*      GeoTransform.                                                   */
/* -------------------------------------------------------------------- */
    if( psPam->bHaveGeoTransform )
    {
        CPLSetXMLValue( psDSTree, "GeoTransform", 
                        oFmt.Printf( "%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
                                     psPam->adfGeoTransform[0],
                                     psPam->adfGeoTransform[1],
                                     psPam->adfGeoTransform[2],
                                     psPam->adfGeoTransform[3],
                                     psPam->adfGeoTransform[4],
                                     psPam->adfGeoTransform[5] ) );
    }

/* -------------------------------------------------------------------- */
/*      Metadata.                                                       */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psMD;

    psMD = oMDMD.Serialize();
    if( psMD != NULL )
    {
        if( psMD->psChild == NULL )
            CPLDestroyXMLNode( psMD );
        else
            CPLAddXMLChild( psDSTree, psMD );
    }

/* -------------------------------------------------------------------- */
/*      GCPs                                                            */
/* -------------------------------------------------------------------- */
    if( psPam->nGCPCount > 0 )
    {
        CPLXMLNode *psPamGCPList = CPLCreateXMLNode( psDSTree, CXT_Element, 
                                                     "GCPList" );

        if( psPam->pszGCPProjection != NULL 
            && strlen(psPam->pszGCPProjection) > 0 )
            CPLSetXMLValue( psPamGCPList, "#Projection", 
                            psPam->pszGCPProjection );

        for( int iGCP = 0; iGCP < psPam->nGCPCount; iGCP++ )
        {
            CPLXMLNode *psXMLGCP;
            GDAL_GCP *psGCP = psPam->pasGCPList + iGCP;

            psXMLGCP = CPLCreateXMLNode( psPamGCPList, CXT_Element, "GCP" );

            CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );

            if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
                CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );

            CPLSetXMLValue( psXMLGCP, "#Pixel", 
                            oFmt.Printf( "%.4f", psGCP->dfGCPPixel ) );

            CPLSetXMLValue( psXMLGCP, "#Line", 
                            oFmt.Printf( "%.4f", psGCP->dfGCPLine ) );

            CPLSetXMLValue( psXMLGCP, "#X", 
                            oFmt.Printf( "%.12E", psGCP->dfGCPX ) );

            CPLSetXMLValue( psXMLGCP, "#Y", 
                            oFmt.Printf( "%.12E", psGCP->dfGCPY ) );

            if( psGCP->dfGCPZ != 0.0 )
                CPLSetXMLValue( psXMLGCP, "#GCPZ", 
                                oFmt.Printf( "%.12E", psGCP->dfGCPZ ) );
        }
    }

/* -------------------------------------------------------------------- */
/*      Process bands.                                                  */
/* -------------------------------------------------------------------- */
    int iBand;

    for( iBand = 0; iBand < GetRasterCount(); iBand++ )
    {
        CPLXMLNode *psBandTree;

        GDALPamRasterBand *poBand = (GDALPamRasterBand *)
            GetRasterBand(iBand+1);

        if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
            continue;

        psBandTree = poBand->SerializeToXML( pszVRTPath );

        if( psBandTree != NULL )
            CPLAddXMLChild( psDSTree, psBandTree );
    }

/* -------------------------------------------------------------------- */
/*      We don't want to return anything if we had no metadata to       */
/*      attach.                                                         */
/* -------------------------------------------------------------------- */
    if( psDSTree->psChild == NULL )
    {
        CPLDestroyXMLNode( psDSTree );
        psDSTree = NULL;
    }

    return psDSTree;
}
static CPLXMLNode* exportProjCSToXML(const OGRSpatialReference *poSRS)

{
    const OGR_SRSNode *poProjCS = poSRS->GetAttrNode("PROJCS");

    if (poProjCS == NULL)
        return NULL;

/* -------------------------------------------------------------------- */
/*      Establish initial infrastructure.                               */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psCRS_XML;

    psCRS_XML = CPLCreateXMLNode(NULL, CXT_Element, "gml:ProjectedCRS");
    addGMLId(psCRS_XML);

/* -------------------------------------------------------------------- */
/*      Attach symbolic name (a name in a nameset).                     */
/* -------------------------------------------------------------------- */
    CPLCreateXMLElementAndValue(psCRS_XML, "gml:srsName",
                                poProjCS->GetChild(0)->GetValue());

/* -------------------------------------------------------------------- */
/*      Add authority info if we have it.                               */
/* -------------------------------------------------------------------- */
    exportAuthorityToXML(poProjCS, "gml:srsID", psCRS_XML, "crs");

/* -------------------------------------------------------------------- */
/*      Use the GEOGCS as a <baseCRS>                                   */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psBaseCRSXML =
        CPLCreateXMLNode(psCRS_XML, CXT_Element, "gml:baseCRS");

    CPLAddXMLChild(psBaseCRSXML, exportGeogCSToXML(poSRS));

/* -------------------------------------------------------------------- */
/*      Our projected coordinate system is "defined by Conversion".     */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psDefinedBy;

    psDefinedBy = CPLCreateXMLNode(psCRS_XML, CXT_Element,
                                   "gml:definedByConversion");

/* -------------------------------------------------------------------- */
/*      Projections are handled as ParameterizedTransformations.        */
/* -------------------------------------------------------------------- */
    const char *pszProjection = poSRS->GetAttrValue("PROJECTION");
    CPLXMLNode *psConv;

    psConv = CPLCreateXMLNode(psDefinedBy, CXT_Element, "gml:Conversion");
    addGMLId(psConv);

/* -------------------------------------------------------------------- */
/*      Transverse Mercator                                             */
/* -------------------------------------------------------------------- */
    if (EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR))
    {
        AddValueIDWithURN(psConv, "gml:usesMethod", "EPSG", "method",
                          9807);

        addProjArg(poSRS, psConv, "Angular", 0.0,
                   8801, SRS_PP_LATITUDE_OF_ORIGIN);
        addProjArg(poSRS, psConv, "Angular", 0.0,
                   8802, SRS_PP_CENTRAL_MERIDIAN);
        addProjArg(poSRS, psConv, "Unitless", 1.0,
                   8805, SRS_PP_SCALE_FACTOR);
        addProjArg(poSRS, psConv, "Linear", 0.0,
                   8806, SRS_PP_FALSE_EASTING);
        addProjArg(poSRS, psConv, "Linear", 0.0,
                   8807, SRS_PP_FALSE_NORTHING);
    }

/* -------------------------------------------------------------------- */
/*      Lambert Conformal Conic                                         */
/* -------------------------------------------------------------------- */
    else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP))
    {
        AddValueIDWithURN(psConv, "gml:usesMethod", "EPSG", "method",
                          9801);

        addProjArg(poSRS, psConv, "Angular", 0.0,
                   8801, SRS_PP_LATITUDE_OF_ORIGIN);
        addProjArg(poSRS, psConv, "Angular", 0.0,
                   8802, SRS_PP_CENTRAL_MERIDIAN);
        addProjArg(poSRS, psConv, "Unitless", 1.0,
                   8805, SRS_PP_SCALE_FACTOR);
        addProjArg(poSRS, psConv, "Linear", 0.0,
                   8806, SRS_PP_FALSE_EASTING);
        addProjArg(poSRS, psConv, "Linear", 0.0,
                   8807, SRS_PP_FALSE_NORTHING);
    }

/* -------------------------------------------------------------------- */
/*      Define the cartesian coordinate system.                         */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psCCS;

    psCCS =
        CPLCreateXMLNode(
            CPLCreateXMLNode(psCRS_XML, CXT_Element, "gml:usesCartesianCS"),
            CXT_Element, "gml:CartesianCS");

    addGMLId(psCCS);

    CPLCreateXMLElementAndValue(psCCS, "gml:csName", "Cartesian");
    addAuthorityIDBlock(psCCS, "gml:csID", "EPSG", "cs", 4400);
    addAxis(psCCS, "E", NULL);
    addAxis(psCCS, "N", NULL);

    return psCRS_XML;
}
Beispiel #3
0
CPLXMLNode *WCTSCollectKVPRequest()

{
    char **papszParmList;

/* -------------------------------------------------------------------- */
/*      Parse the query string.                                         */
/* -------------------------------------------------------------------- */
    if( getenv("QUERY_STRING") == NULL )
        WCTSEmitServiceException( "QUERY_STRING not set." );

    papszParmList = CSLTokenizeString2( getenv("QUERY_STRING"), "&",
                                        CSLT_PRESERVEESCAPES );
    
/* -------------------------------------------------------------------- */
/*      Un-url-encode the items.                                        */
/* -------------------------------------------------------------------- */
    int i;

    for( i = 0; papszParmList != NULL && papszParmList[i] != NULL; i++ )
    {
        char *pszNewValue = CPLUnescapeString( papszParmList[i], 
                                               NULL, CPLES_URL );
        
        CPLFree( papszParmList[i] );
        papszParmList[i] = pszNewValue;
    }

/* -------------------------------------------------------------------- */
/*      Check for REQUEST                                               */
/* -------------------------------------------------------------------- */
    const char *pszVersion = CSLFetchNameValue(papszParmList,"VERSION");
    const char *pszRequest = CSLFetchNameValue(papszParmList,"REQUEST");

    if( pszRequest == NULL )
        WCTSEmitServiceException( "REQUEST not provided in KVP URL." );

/* -------------------------------------------------------------------- */
/*      Handle GetCapabilities                                          */
/* -------------------------------------------------------------------- */
    else if( EQUAL(pszRequest,"GetCapabilities") )
    {
        CPLXMLNode *psRequest = CPLCreateXMLNode( NULL, CXT_Element, 
                                                  "GetCapabilities" );

        if( pszVersion != NULL )
        {
            CPLCreateXMLNode( 
                CPLCreateXMLNode( psRequest, CXT_Attribute, "version" ),
                CXT_Text, pszVersion );
        }

        if( CSLFetchNameValue(papszParmList,"SERVICE") != NULL )
        {
            CPLCreateXMLNode( 
                CPLCreateXMLNode( psRequest, CXT_Attribute, "service" ),
                CXT_Text, CSLFetchNameValue(papszParmList,"SERVICE") );
        }

        return psRequest;
    }

/* ==================================================================== */
/*      Handle IsTransformable                                          */
/* ==================================================================== */
    else if( EQUAL(pszRequest,"IsTransformable") )
    {
        CPLXMLNode *psRequest = CPLCreateXMLNode( NULL, CXT_Element, 
                                                  "IsTransformable" );

/* -------------------------------------------------------------------- */
/*      Translate the source crs.                                       */
/* -------------------------------------------------------------------- */
        CPLAddXMLChild( 
            CPLCreateXMLNode( psRequest, CXT_Element, "SourceCRS" ),
            WCTSAuthId2crsId( papszParmList, "SOURCECRS" ) );

/* -------------------------------------------------------------------- */
/*      Translate the destination crs.                                  */
/* -------------------------------------------------------------------- */
        CPLAddXMLChild( 
            CPLCreateXMLNode( psRequest, CXT_Element, "TargetCRS" ),
            WCTSAuthId2crsId( papszParmList, "TARGETCRS" ) );

/* -------------------------------------------------------------------- */
/*      Handle version.                                                 */
/* -------------------------------------------------------------------- */
        if( pszVersion != NULL )
        {
            CPLCreateXMLNode( 
                CPLCreateXMLNode( psRequest, CXT_Attribute, "version" ),
                CXT_Text, pszVersion );
        }

/* -------------------------------------------------------------------- */
/*      geometric primitive.                                            */
/* -------------------------------------------------------------------- */
        if( CSLFetchNameValue(papszParmList,"GEOMETRICPRIMITIVE") != NULL )
        {
            CPLCreateXMLElementAndValue( 
                psRequest, "GeometricPrimitive", 
                CSLFetchNameValue(papszParmList,"GEOMETRICPRIMITIVE") );
        }

        /* Add COVERAGETYPE and COVERAGEINTERPOLATIONMETHOD layer? */

        return psRequest;
    }

/* -------------------------------------------------------------------- */
/*      Unrecognised.                                                   */
/* -------------------------------------------------------------------- */
    else
        WCTSEmitServiceException( 
            CPLSPrintf( "Unrecognised REQUEST value (%.500s).", pszRequest) );

    return NULL;
}
Beispiel #4
0
CPLXMLNode *VRTRasterBand::SerializeToXML( const char *pszVRTPath )

{
    CPLXMLNode *psTree = CPLCreateXMLNode( NULL, CXT_Element, "VRTRasterBand" );

/* -------------------------------------------------------------------- */
/*      Various kinds of metadata.                                      */
/* -------------------------------------------------------------------- */
    CPLSetXMLValue( psTree, "#dataType",
                    GDALGetDataTypeName( GetRasterDataType() ) );

    if( nBand > 0 )
        CPLSetXMLValue( psTree, "#band", CPLSPrintf( "%d", GetBand() ) );

    CPLXMLNode *psMD = oMDMD.Serialize();
    if( psMD != NULL )
    {
        CPLAddXMLChild( psTree, psMD );
    }

    if( strlen(GetDescription()) > 0 )
        CPLSetXMLValue( psTree, "Description", GetDescription() );

    if( m_bNoDataValueSet )
    {
        if (CPLIsNan(m_dfNoDataValue))
            CPLSetXMLValue( psTree, "NoDataValue", "nan");
        else
            CPLSetXMLValue( psTree, "NoDataValue",
                            CPLSPrintf( "%.16g", m_dfNoDataValue ) );
    }

    if( m_bHideNoDataValue )
        CPLSetXMLValue( psTree, "HideNoDataValue",
                        CPLSPrintf( "%d", m_bHideNoDataValue ) );

    if( m_pszUnitType != NULL )
        CPLSetXMLValue( psTree, "UnitType", m_pszUnitType );

    if( m_dfOffset != 0.0 )
        CPLSetXMLValue( psTree, "Offset",
                        CPLSPrintf( "%.16g", m_dfOffset ) );

    if( m_dfScale != 1.0 )
        CPLSetXMLValue( psTree, "Scale",
                        CPLSPrintf( "%.16g", m_dfScale ) );

    if( m_eColorInterp != GCI_Undefined )
        CPLSetXMLValue( psTree, "ColorInterp",
                        GDALGetColorInterpretationName( m_eColorInterp ) );

/* -------------------------------------------------------------------- */
/*      Category names.                                                 */
/* -------------------------------------------------------------------- */
    if( m_papszCategoryNames != NULL )
    {
        CPLXMLNode *psCT_XML = CPLCreateXMLNode( psTree, CXT_Element,
                                                 "CategoryNames" );
        CPLXMLNode* psLastChild = NULL;

        for( int iEntry=0; m_papszCategoryNames[iEntry] != NULL; iEntry++ )
        {
            CPLXMLNode *psNode = CPLCreateXMLElementAndValue( NULL, "Category",
                                         m_papszCategoryNames[iEntry] );
            if( psLastChild == NULL )
                psCT_XML->psChild = psNode;
            else
                psLastChild->psNext = psNode;
            psLastChild = psNode;
        }
    }

/* -------------------------------------------------------------------- */
/*      Histograms.                                                     */
/* -------------------------------------------------------------------- */
    if( m_psSavedHistograms != NULL )
        CPLAddXMLChild( psTree, CPLCloneXMLTree( m_psSavedHistograms ) );

/* -------------------------------------------------------------------- */
/*      Color Table.                                                    */
/* -------------------------------------------------------------------- */
    if( m_poColorTable != NULL )
    {
        CPLXMLNode *psCT_XML = CPLCreateXMLNode( psTree, CXT_Element,
                                                 "ColorTable" );
        CPLXMLNode* psLastChild = NULL;

        for( int iEntry=0; iEntry < m_poColorTable->GetColorEntryCount();
             iEntry++ )
        {
            CPLXMLNode *psEntry_XML = CPLCreateXMLNode( NULL, CXT_Element,
                                                        "Entry" );
            if( psLastChild == NULL )
                psCT_XML->psChild = psEntry_XML;
            else
                psLastChild->psNext = psEntry_XML;
            psLastChild = psEntry_XML;

            GDALColorEntry sEntry;
            m_poColorTable->GetColorEntryAsRGB( iEntry, &sEntry );

            CPLSetXMLValue( psEntry_XML, "#c1", CPLSPrintf("%d",sEntry.c1) );
            CPLSetXMLValue( psEntry_XML, "#c2", CPLSPrintf("%d",sEntry.c2) );
            CPLSetXMLValue( psEntry_XML, "#c3", CPLSPrintf("%d",sEntry.c3) );
            CPLSetXMLValue( psEntry_XML, "#c4", CPLSPrintf("%d",sEntry.c4) );
        }
    }

/* ==================================================================== */
/*      Overviews                                                       */
/* ==================================================================== */

    for( int iOvr = 0; iOvr < static_cast<int>( m_apoOverviews.size() ); iOvr ++ )
    {
        CPLXMLNode *psOVR_XML = CPLCreateXMLNode( psTree, CXT_Element,
                                                 "Overview" );

        int bRelativeToVRT = FALSE;
        const char *pszRelativePath = NULL;
        VSIStatBufL sStat;

        if( VSIStatExL( m_apoOverviews[iOvr].osFilename, &sStat, VSI_STAT_EXISTS_FLAG ) != 0 )
        {
            pszRelativePath = m_apoOverviews[iOvr].osFilename;
            bRelativeToVRT = FALSE;
        }
        else
        {
            pszRelativePath =
                CPLExtractRelativePath( pszVRTPath, m_apoOverviews[iOvr].osFilename,
                                        &bRelativeToVRT );
        }

        CPLSetXMLValue( psOVR_XML, "SourceFilename", pszRelativePath );

        CPLCreateXMLNode(
            CPLCreateXMLNode( CPLGetXMLNode( psOVR_XML, "SourceFilename" ),
                            CXT_Attribute, "relativeToVRT" ),
            CXT_Text, bRelativeToVRT ? "1" : "0" );

        CPLSetXMLValue( psOVR_XML, "SourceBand",
                        CPLSPrintf("%d",m_apoOverviews[iOvr].nBand) );
    }

/* ==================================================================== */
/*      Mask band (specific to that raster band)                        */
/* ==================================================================== */

    if( m_poMaskBand != NULL )
    {
        CPLXMLNode *psBandTree =
            m_poMaskBand->SerializeToXML(pszVRTPath);

        if( psBandTree != NULL )
        {
            CPLXMLNode *psMaskBandElement = CPLCreateXMLNode( psTree, CXT_Element,
                                                              "MaskBand" );
            CPLAddXMLChild( psMaskBandElement, psBandTree );
        }
    }

    return psTree;
}
CPLXMLNode *VRTDataset::SerializeToXML( const char *pszVRTPath )

{
    /* -------------------------------------------------------------------- */
    /*      Setup root node and attributes.                                 */
    /* -------------------------------------------------------------------- */
    CPLXMLNode *psDSTree = NULL;
    CPLXMLNode *psMD = NULL;
    char       szNumber[128];

    psDSTree = CPLCreateXMLNode( NULL, CXT_Element, "VRTDataset" );

    sprintf( szNumber, "%d", GetRasterXSize() );
    CPLSetXMLValue( psDSTree, "#rasterXSize", szNumber );

    sprintf( szNumber, "%d", GetRasterYSize() );
    CPLSetXMLValue( psDSTree, "#rasterYSize", szNumber );

 /* -------------------------------------------------------------------- */
 /*      SRS                                                             */
 /* -------------------------------------------------------------------- */
    if( pszProjection != NULL && strlen(pszProjection) > 0 )
        CPLSetXMLValue( psDSTree, "SRS", pszProjection );

 /* -------------------------------------------------------------------- */
 /*      Geotransform.                                                   */
 /* -------------------------------------------------------------------- */
    if( bGeoTransformSet )
    {
        CPLSetXMLValue( psDSTree, "GeoTransform", 
                        CPLSPrintf( "%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
                                    adfGeoTransform[0],
                                    adfGeoTransform[1],
                                    adfGeoTransform[2],
                                    adfGeoTransform[3],
                                    adfGeoTransform[4],
                                    adfGeoTransform[5] ) );
    }

/* -------------------------------------------------------------------- */
/*      Metadata                                                        */
/* -------------------------------------------------------------------- */
    psMD = oMDMD.Serialize();
    if( psMD != NULL )
        CPLAddXMLChild( psDSTree, psMD );

 /* -------------------------------------------------------------------- */
 /*      GCPs                                                            */
 /* -------------------------------------------------------------------- */
    if( nGCPCount > 0 )
    {
        CPLXMLNode *psGCPList = CPLCreateXMLNode( psDSTree, CXT_Element, 
                                                  "GCPList" );

        if( pszGCPProjection != NULL && strlen(pszGCPProjection) > 0 )
            CPLSetXMLValue( psGCPList, "#Projection", pszGCPProjection );

        for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
        {
            CPLXMLNode *psXMLGCP;
            GDAL_GCP *psGCP = pasGCPList + iGCP;

            psXMLGCP = CPLCreateXMLNode( psGCPList, CXT_Element, "GCP" );

            CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );

            if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
                CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );

            CPLSetXMLValue( psXMLGCP, "#Pixel", 
                            CPLSPrintf( "%.4f", psGCP->dfGCPPixel ) );

            CPLSetXMLValue( psXMLGCP, "#Line", 
                            CPLSPrintf( "%.4f", psGCP->dfGCPLine ) );

            CPLSetXMLValue( psXMLGCP, "#X", 
                            CPLSPrintf( "%.12E", psGCP->dfGCPX ) );

            CPLSetXMLValue( psXMLGCP, "#Y", 
                            CPLSPrintf( "%.12E", psGCP->dfGCPY ) );

            if( psGCP->dfGCPZ != 0.0 )
                CPLSetXMLValue( psXMLGCP, "#GCPZ", 
                                CPLSPrintf( "%.12E", psGCP->dfGCPZ ) );
        }
    }

    /* -------------------------------------------------------------------- */
    /*      Serialize bands.                                                */
    /* -------------------------------------------------------------------- */
    for( int iBand = 0; iBand < nBands; iBand++ )
    {
        CPLXMLNode *psBandTree = 
            ((VRTRasterBand *) papoBands[iBand])->SerializeToXML(pszVRTPath);

        if( psBandTree != NULL )
            CPLAddXMLChild( psDSTree, psBandTree );
    }

    /* -------------------------------------------------------------------- */
    /*      Serialize dataset mask band.                                    */
    /* -------------------------------------------------------------------- */
    if (poMaskBand)
    {
        CPLXMLNode *psBandTree =
            poMaskBand->SerializeToXML(pszVRTPath);

        if( psBandTree != NULL )
        {
            CPLXMLNode *psMaskBandElement = CPLCreateXMLNode( psDSTree, CXT_Element, 
                                                              "MaskBand" );
            CPLAddXMLChild( psMaskBandElement, psBandTree );
        }
    }

    return psDSTree;
}
Beispiel #6
0
CPLErr VRTRasterBand::GetHistogram( double dfMin, double dfMax,
                                    int nBuckets, GUIntBig * panHistogram,
                                    int bIncludeOutOfRange, int bApproxOK,
                                    GDALProgressFunc pfnProgress, 
                                    void *pProgressData )

{
/* -------------------------------------------------------------------- */
/*      Check if we have a matching histogram.                          */
/* -------------------------------------------------------------------- */
    CPLXMLNode *psHistItem;

    psHistItem = PamFindMatchingHistogram( psSavedHistograms, 
                                           dfMin, dfMax, nBuckets, 
                                           bIncludeOutOfRange, bApproxOK );
    if( psHistItem != NULL )
    {
        GUIntBig *panTempHist = NULL;

        if( PamParseHistogram( psHistItem, &dfMin, &dfMax, &nBuckets, 
                               &panTempHist,
                               &bIncludeOutOfRange, &bApproxOK ) )
        {
            memcpy( panHistogram, panTempHist, sizeof(GUIntBig) * nBuckets );
            CPLFree( panTempHist );
            return CE_None;
        }
    }

/* -------------------------------------------------------------------- */
/*      We don't have an existing histogram matching the request, so    */
/*      generate one manually.                                          */
/* -------------------------------------------------------------------- */
    CPLErr eErr;

    eErr = GDALRasterBand::GetHistogram( dfMin, dfMax, 
                                         nBuckets, panHistogram, 
                                         bIncludeOutOfRange, bApproxOK,
                                         pfnProgress, pProgressData );

/* -------------------------------------------------------------------- */
/*      Save an XML description of this histogram.                      */
/* -------------------------------------------------------------------- */
    if( eErr == CE_None )
    {
        CPLXMLNode *psXMLHist;

        psXMLHist = PamHistogramToXMLTree( dfMin, dfMax, nBuckets, 
                                           panHistogram, 
                                           bIncludeOutOfRange, bApproxOK );
        if( psXMLHist != NULL )
        {
            ((VRTDataset *) poDS)->SetNeedsFlush();

            if( psSavedHistograms == NULL )
                psSavedHistograms = CPLCreateXMLNode( NULL, CXT_Element,
                                                      "Histograms" );
            
            CPLAddXMLChild( psSavedHistograms, psXMLHist );
        }
    }

    return eErr;
}